Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

java.time.format.DateTimeParseException could not be parsed migrating from Java 8 to Java 11

Tags:

java

This works in Java 8

LocalDateTime ldt = LocalDateTime.parse("4/11/17 00:00 AM", DateTimeFormatter.ofPattern("d/M/yy hh:mm[ ][a]"));

But in Java 11 I get

java.time.format.DateTimeParseException: Text '4/11/17 00:00 AM' could not be parsed, unparsed text found at index 14
at java.base/java.time.format.DateTimeFormatter.parseResolved0(DateTimeFormatter.java:2049)
at java.base/java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1948)

Can anyone help me understand why this is? I've checked the docs and don't see any obvious change to the DateTimeFormatter class.

https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html

https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/time/format/DateTimeFormatter.html

like image 956
F_SO_K Avatar asked Dec 23 '22 16:12

F_SO_K


1 Answers

Nothing changed. You're committing a 'default platform' code style error. This is an anti-pattern where you use a broken method and break your code, but the bug is almost impossible to find with unit tests; your code will end up blowing up at production time when lots of cash and reputation is on the line. "Fortunately", you found this bug today by switching JDKs and getting lucky that the locale configurations are somehow different between your JDK installations.

I suggest you grow just as much of a dislike to these bad methods as I do :) These methods are ones that presume some parameter to be 'whatever your platform has as a default for this value', and the 3 common culprits are, in order:

  • Charset encoding
  • Locale
  • Timezone

ofPattern(String) is one such method; it presumes 'the platform default locale', and evidently, on your JDK8 install, it's english or something similar and on your JDK11 install it is not. Parsing AM as value for an a field is locale dependent; obviously, AM is an englishism, it wouldn't make any sense in dutch or french!

There are 2 things to do to fix this problem:

  1. If your IDE has features to mark a method as 'you really should never call this', you should strongly consider adding all of these methods to the list, and if you then want platform default, that you explicitly use things like Charset.defaultCharset() instead, to make clear you really want that.

  2. Fix your code by shoving a , Locale.ENGLISH after your pattern and all will be right as rain again.

An example:

LocalDateTime ldt = LocalDateTime.parse("4/11/17 00:00 AM",
  DateTimeFormatter.ofPattern("d/M/yy hh:mm[ ][a]",
  Locale.forLanguageTag("NL")));

will fail on JDK8 just as much as it does on JDK11.

LocalDateTime ldt = LocalDateTime.parse("4/11/17 00:00 AM",
  DateTimeFormatter.ofPattern("d/M/yy hh:mm[ ][a]",
  Locale.ENGLISH));

works on JDK8 and JDK11 too.

NB: A bunch of non-english locales such as .GERMANY and .ITALY and .FRANCE actually do somehow parse AM correctly, but as shown above, dutch (The Netherlands) is an example where that won't work.

like image 150
rzwitserloot Avatar answered Mar 15 '23 23:03

rzwitserloot