2

I am using Java DateTimeFormatter for formatting given time and get difference between given start and end time. But I am getting below exception:

Exception in thread "main" java.time.format.DateTimeParseException: Text '1:23am' could not be parsed at index 0

Below is my code:

String dtStr = "1:23am-1:08am";
String t1 = dtStr.split("-")[0];
String t2 = dtStr.split("-")[1];
DateTimeFormatter format = DateTimeFormatter.ofPattern("hh:mma");
LocalTime time1 = LocalTime.parse(t1, format);
LocalTime time2 = LocalTime.parse(t2, format);
Duration dur = Duration.between(time1, time2);
System.out.println(dur.toMinutes() + " minutes " + dur.toSecondsPart() + " seconds");

I am not sure if I am doing anything wrong. Any help would be appreciated.

Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
DpkTheJavaCoder
  • 117
  • 1
  • 10

3 Answers3

4

You cannot parse the Strings due to two h in your format pattern instead of just one, and due to am-pm of day being in lower case letters. The a in the pattern String expects (standard/default) upper case, like AM.

You can either manipulate the Strings as shown in the other answer(s), but you can also use a DateTimeFormatter that can handle lower-case things. All you need is to build one with a DateTimeFormatterBuilder and make it parseCaseInsensitive() and apply a Locale:

public static void main(String[] args) {
    String dtStr = "1:23am-1:08am";
    String t1 = dtStr.split("-")[0];
    String t2 = dtStr.split("-")[1];
    // build a formatter that parses lower case am-pm of day
    DateTimeFormatter format = new DateTimeFormatterBuilder()
                                    .parseCaseInsensitive() // handles lower- and upper-case 
                                    .appendPattern("h:mma")
                                    .toFormatter(Locale.ENGLISH); // doesn't reliably work without a Locale
    LocalTime time1 = LocalTime.parse(t1, format);
    LocalTime time2 = LocalTime.parse(t2, format);
    Duration dur = Duration.between(time1, time2);
    System.out.println(dur.toMinutes() + " minutes " + dur.toSecondsPart() + " seconds");
}

Output:

-15 minutes 0 seconds

This is a little more flexible than manipulating the input before parsing, because this one can also parse upper-case am-pm of day.

deHaar
  • 17,687
  • 10
  • 38
  • 51
  • 2
    Definitely better than converting the source strings. You can even get rid of the `split` operation, using something like `ParsePosition p = new ParsePosition(0); LocalTime time1 = LocalTime.from(format.parse(dtStr, p)); assert dtStr.charAt(p.getIndex()) == '-'; p.setIndex(p.getIndex() + 1); LocalTime time2 = LocalTime.from(format.parse(dtStr, p));` – Holger Sep 19 '22 at 07:40
3

You need to use the following pattern h:mma because of one-digit hour, also a parses AM/PM in uppercase

String dtStr = "1:23am-1:08am";
String t1 = dtStr.split("-")[0].toUpperCase();
String t2 = dtStr.split("-")[1].toUpperCase();
DateTimeFormatter format = DateTimeFormatter.ofPattern("h:mma");

LocalTime time1 = LocalTime.parse(t1, format);
LocalTime time2 = LocalTime.parse(t2, format);
Duration dur = Duration.between(time1, time2);
System.out.println(dur.toMinutes() + " minutes " + dur.toSecondsPart() + " seconds");
-15 minutes 0 seconds

java.time format specifications

azro
  • 53,056
  • 7
  • 34
  • 70
  • I'm gonna add the [link](https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html) for the reference here – Aleson Sep 19 '22 at 06:23
2

When you put hh you are saying that hours have to be 2 digits you need just 1 and same should apply for the minutes h:ma

DateTimeFormatter docs

If the count of letters is one, then the value is output using the minimum number of digits and without padding. Otherwise, the count of digits is used as the width of the output field, with the value zero-padded as necessary

Next the "am" "pm" needs to be upper case to be parsed without an error.

String t1 = dtStr.split("-")[0].toUpperCase();;
String t2 = dtStr.split("-")[1].toUpperCase();;
DateTimeFormatter format = DateTimeFormatter.ofPattern("h:ma");

Note that if you don't have fixed length for minutes as 2 and pass for example 1:5am instead of 1:05am parsing would fail if you put h:mma as pattern

Vojin Purić
  • 2,140
  • 7
  • 9
  • 22