3

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

Jan
  • 13,738
  • 3
  • 30
  • 55
kip2
  • 6,473
  • 4
  • 55
  • 72
  • 1
    If "01:20" should be interpreted as "01:20PM", then what should you enter if you want to get "01:20AM" ? – Erwin Bolwidt Apr 18 '18 at 09:26
  • Do you want to parse a time string or format teh time as a string? I'm not sure when you're using the `MaterialDateTimePicker` you get the hours and minutes as integers why do you need to parse it? – xander Apr 18 '18 at 09:26
  • @ErwinBolwidt actually, "1:20" -> 01:20 AM and "13:20" -> 01:20 PM. i.e., TimePickerDialog returns hourOfDay values in the 0 -> 24 range – kip2 Apr 18 '18 at 09:28
  • @kip2 Then why does your question read 'like "01:20" -> 1:20**PM** ' ? – Erwin Bolwidt Apr 18 '18 at 09:40
  • @ErwinBolwidt my fault, I've edited the question. – kip2 Apr 18 '18 at 09:42
  • @xander I could have done the formatting myself since I have the ints handy, but thought that using the standard/official libs would be a better approach since they're already built & tested :) – kip2 Apr 18 '18 at 09:43

3 Answers3

7

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
Jan
  • 13,738
  • 3
  • 30
  • 55
  • works beautifully! I didn't need to add in the am/pm string to the input as the hourOfDay is in the range (0, 23) – kip2 Apr 18 '18 at 09:38
  • 2
    Please don’t teach the young ones to use the long outdated and notoriously troublesome `SimpleDateFormat` class. Joda-Time (used in the question) is better. And today we have still better in [`java.time`, the modern Java date and time API](https://docs.oracle.com/javase/tutorial/datetime/) and its `DateTimeFormatter`. Yes, you can use it on Android. For older Android see [How to use ThreeTenABP in Android Project](https://stackoverflow.com/questions/38922754/how-to-use-threetenabp-in-android-project). – Ole V.V. Apr 19 '18 at 08:31
2

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).

Meno Hochschild
  • 42,708
  • 7
  • 104
  • 126
1

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

Ole V.V.
  • 81,772
  • 15
  • 137
  • 161