kip2
kip2

Reputation: 6883

How to parse time (hour, minute) from a string?

Anybody know how to parse time (hour, minute and AM/PM) from a string that looks like "01:20" -> 1:20AM and "21:20" -> 9:20PM? Most solutions out there seem to assume or require a Date or Calendar object.

My input time is actually coming from a TimePickerDialog (specifically, this MaterialDateTimePicker implementation, so I receive only the hourOfDay, minute and seconds (integers).

I want to be able to format the time that the user picked in a friendly way, i.e 12:30PM, 02:15AM, etc.

I am trying to use Joda Time:

fun formattedTime(timeStr: String): String {
    // Get time from date
    val timeFormatter = DateTimeFormat.forPattern("h:mm a")
    val displayTime = timeFormatter.parseLocalTime(timeStr)
    return displayTime.toString()
}

but I get this error with an input string such as "1:20": java.lang.IllegalArgumentException: Invalid format: "1:20" is too short

I have also looked into SimpleDateFormat but it seems to require a full date-time string such as in this related question

Upvotes: 4

Views: 10597

Answers (3)

Anonymous
Anonymous

Reputation: 86306

Your two good options are Joda-Time and java.time.

Since you receive hourOfDay, minute and seconds as integers from the time picker, you don’t need to do any parsing.

java.time

    DateTimeFormatter timeFormatter = DateTimeFormatter.ofLocalizedTime(FormatStyle.SHORT)
            .withLocale(Locale.US);
    LocalTime time = LocalTime.of(hourOfDay, minute, second);
    String displayTime = time.format(timeFormatter);
    System.out.println(displayTime);

This prints the time like this:

11:45 PM

Rather than an explicit format pattern string I am relying on the built-in localized format for the US locale. It has put a space between the minutes and PM (or AM). I believe your users will be happy about that. If not, you will need to use DateTimeFormatter.ofPattern("h:mma", Locale.US) instead.

Joda-Time

If you are already using Joda-Time and don’t have a reason for changing at this point, sticking to it is reasonable. You may use the LocalTime(int hourOfDay, int minuteOfHour, int secondOfMinute) constructor. Then proceed as in Meno Hochschild’s answer. It’s a good and knowledgeable answer.

Note that Joda-Time is considered to be a largely “finished” project. No major enhancements are planned. If using Java SE 8, please migrate to java.time (JSR-310).

(Quoted from the Joda-Time homepage)

Stay away from SimpleDateFormat

Stay far away from the SimpleDateFormat class. It can be made to work for the job, but it is not only long outdated, it is also notoriously troublesome.

Question: Can I use java.time on Android?

Yes, java.time works nicely on older and newer Android devices. It just requires at least Java 6.

  • In Java 8 and later and on newer Android devices (from API level 26, I’m told) the modern API comes built-in.
  • In Java 6 and 7 get the ThreeTen Backport, the backport of the new classes (ThreeTen for JSR 310; see the links at the bottom).
  • On (older) Android use the Android edition of ThreeTen Backport. It’s called ThreeTenABP. And make sure you import the date and time classes from org.threeten.bp with subpackages.

Links

Upvotes: 1

Jan
Jan

Reputation: 13858

As @ole-v-v pointed out, SimpleDateFormat has seen better days - so today you can make use of the java.time package to do the job:

java.time.format.DateTimeFormatter target2 = 
     java.time.format.DateTimeFormatter.ofPattern("h:mm a");
java.time.format.DateTimeFormatter source2 = 
     java.time.format.DateTimeFormatter.ofPattern("HH:mm");

System.out.println("01:30 -> " + target2.format(source2.parse("01:30")));
System.out.println("21:20 -> " + target2.format(source2.parse("21:20")));

Yields the result of

01:30 -> 1:30 AM
21:20 -> 9:20 PM

as expected.

In Joda-Time you would code it as @meno-hochschild pointed out in his answer below.

Using SimpleDateFormat it will look like this:

    SimpleDateFormat target = new SimpleDateFormat("h:mm a");
    SimpleDateFormat source = new SimpleDateFormat("HH:mm");
    System.out.println("01:30 -> " + target.format(source.parse("01:30")));
    System.out.println("21:20 -> " + target.format(source.parse("21:20")));

This will parse from 24h times to 12 hours display

    01:30 -> 1:30 AM
    21:20 -> 9:20 PM      

It all depends on the format for the hours - for parsing you'll want 24h hours (format HH), for output you want 12 hours plus am / pm - format is h.

If you want 01:30 to be PM you'll have to add that to the string to be parsed somehow:

   System.out.println("01:30 pm-> " + target.format(target.parse("01:30 pm")));

resulting in

   01:30 pm-> 1:30 PM

Upvotes: 7

Meno Hochschild
Meno Hochschild

Reputation: 44061

The accepted answer is correct. However, I am astonished to see the old classes like SimpleDateFormat although the OP has explicitly first desired a Joda answer (see the tags of the question). So I post here the Joda answer as supplement:

DateTimeFormatter target = DateTimeFormat.forPattern("h:mm a").withLocale(Locale.ENGLISH);
DateTimeFormatter source = DateTimeFormat.forPattern("HH:mm");
System.out.println("01:30 -> " + target.print(source.parseLocalTime("01:30")));
System.out.println("21:20 -> " + target.print(source.parseLocalTime("21:20")));

01:30 -> 1:30 AM
21:20 -> 9:20 PM

I advise not to mix two different time libraries (the OP obviously uses Joda-Time-Android).

Upvotes: 2

Related Questions