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.
...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
Learn more about the modern Date-Time API from Trail: Date Time.