javadatetime-formatjava-11java-17datetimeformatter

java.time.format.DateTimeParseException in java 17 but not in java 11


I am migrating a service from jdk 11 to jdk 17. But I kept getting errors in java 17:

Exception in thread "main" java.time.format.DateTimeParseException: Text '09/18/2018 10:31:40 PM' could not be parsed at index 0
at java.base/java.time.format.DateTimeFormatter.parseResolved0(DateTimeFormatter.java:2052)
at java.base/java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1954)
at java.base/java.time.ZonedDateTime.parse(ZonedDateTime.java:600)
at Main.convertToEpoch(Main.java:15)
at Main.getOrderTime(Main.java:54)
at Main.lambda$dateTest$0(Main.java:60)
at java.base/java.util.Arrays$ArrayList.forEach(Arrays.java:4204)
at Main.dateTest(Main.java:60)
at Main.main(Main.java:71)

However I don't get this error in java 11. Following is the sample code:

public class Main {
public static Long convertToEpoch(String dateTime, String pattern) {
    System.out.println(ZoneId.systemDefault());
    DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(pattern).withZone(ZoneId.systemDefault());
    return ZonedDateTime.parse(dateTime, dateTimeFormatter).toInstant().toEpochMilli();
}

private static Long getOrderTime(String orderSavedTime) {
    try {
        return convertToEpoch(orderSavedTime, "yyyy-M-d'T'H:m:sXXX");
    } catch (DateTimeParseException e) {
        System.out.println("unable to parse date in yyyy-M-d'T'H:m:sXXX  trying next format ");
    }
    try {
        //one space less
        return convertToEpoch(orderSavedTime, "MMM d yyyy h:m:s a");
    } catch (DateTimeParseException e) {
        System.out.println("unable to parse date in MMM d yyyy h:m:s a trying next format ");
    }

    try {
        return convertToEpoch(orderSavedTime, "M/d/yy h:m:s a");
    } catch (DateTimeParseException e) {
        System.out.println("unable to parse date in M/d/yy h:m:s a trying next format ");
    }
    try {
        return convertToEpoch(orderSavedTime, "M/d/yyyy h:m:s a");
    } catch (DateTimeParseException e) {
        System.out.println("unable to parse date in M/d/yyyy h:m:s a trying next format ");
    }

    try {
        return convertToEpoch(orderSavedTime, "yyyy-M-d H:m:s");
    } catch (DateTimeParseException e) {
        System.out.println("unable to parse date in yyyy-M-d H:m:s trying next format ");
    }

    try {
        return convertToEpoch(orderSavedTime, "MMM  d yyyy h:m:s:SSSa");
    } catch (DateTimeParseException e) {
        System.out.println("unable to parse date in yyyy-M-d H:m:s trying next format ");
    }

    return convertToEpoch(orderSavedTime, "MMM d yyyy h:m:s:SSSa");
}

public static void dateTest() {
    List<String> formats = Arrays.asList("09/18/2018 10:31:40 PM", "10/18/2018 3:39:24 AM", "9/18/2018 10:31:40 PM", "9/18/2018 3:39:24 PM", "9/18/2018 2:43:08 PM",
            "9/18/2018 5:09:05 PM", "09/09/2018 06:32:29 PM", "09/09/18 06:32:29 PM", "08/09/18 06:02:20 PM", "8/9/18 6:2:2 PM", "Nov  1 2018 12:00:00:000AM");
    formats.forEach(v -> System.out.println(v + " -> " + new Date(getOrderTime(v))));
    System.out.println("new form");
    formats = Arrays.asList("Sep 22 2014 10:33:55:555AM", "Sep 02 2014 2:3:5:555AM", "Sep 2 2014 2:3:05 AM", "Oct 12 2004 02:3:50 PM", "2018-09-08T00:00:00+05:30",
            "Nov  1 2018 12:00:00:000AM");
    formats.forEach(v -> System.out.println(
            v + " -> " + ZonedDateTime.ofInstant(Instant.ofEpochMilli(getOrderTime(v)), ZoneId.systemDefault()).format(DateTimeFormatter.ofPattern("MMM d yyyy h:m:s:SSSa"))));
    formats.forEach(v -> System.out.println(v + " -> " + ZonedDateTime.ofInstant(Instant.ofEpochMilli(getOrderTime(v)), ZoneId.systemDefault())));

}

public static void main(String[] args) {
    dateTest();
    }
}

Same sample code in java11 runs properly: Partial output (for first element)

Asia/Kolkata
unable to parse date in yyyy-M-d'T'H:m:sXXX  trying next format 
Asia/Kolkata
unable to parse date in MMM d yyyy h:m:s a trying next format 
Asia/Kolkata
unable to parse date in M/d/yy h:m:s a trying next format 
Asia/Kolkata
09/18/2018 10:31:40 PM -> Tue Sep 18 22:31:40 IST 2018

It might be related to AM/PM markers and case sensitivity, but the original code is legacy and I don't want to make a lot of changes.


Solution

  • ...could it be possible that this issue persists as my system default is ASIA/Kolkata (en_IN) as locale. If yes then without switching my locale to US or English, How do I fix it?

    I highly recommend that you always specify a Locale with a DateTimeFormatter object which is always Locale-sensitive. However, if you do not want to use it in this case, you can use create a case-insensitive DateTimeFormatter.

    Demo

    public class Main {
        public static void main(String[] args) {
            DateTimeFormatter dtf = new DateTimeFormatterBuilder()
                    .parseCaseInsensitive() // For case-insensitive (e.g. am, Am, AM) parsing
                    .appendPattern("d MMM uuuu h:m a")
                    .toFormatter();
    
            // Test
            Stream.of(
                    "24 Oct 2016 7:31 pm",
                    "24 Oct 2016 7:31 PM"
            ).forEach(s -> System.out.println(LocalDateTime.parse(s, dtf)));
        }
    }
    

    Output:

    2016-10-24T19:31
    2016-10-24T19:31
    

    ONLINE DEMO

    Learn more about the modern Date-Time API from Trail: Date Time.