java.time.format.DateTimeParseException не может быть проанализирован при переходе с Java 8 на Java 11

Sep 02 2020

Это работает в Java 8

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

Но в Java 11 я получаю

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)

Может ли кто-нибудь помочь мне понять, почему это так? Я проверил документацию и не увидел никаких очевидных изменений в классе DateTimeFormatter.

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

Ответы

9 rzwitserloot Sep 02 2020 at 18:40

Ничего не изменилось. Вы совершаете ошибку стиля кода "платформа по умолчанию". Это анти-шаблон, когда вы используете неработающий метод и нарушаете свой код, но ошибку практически невозможно найти с помощью модульных тестов; ваш код в конечном итоге взорвется во время производства, когда на кону будет много денег и репутации. «К счастью», сегодня вы обнаружили эту ошибку, переключив JDK и получив удачу, что конфигурации локали в ваших установках JDK как-то различаются.

Я предлагаю вам вырасти столько же неприязни к этим плохим методам, сколько и у меня :) Эти методы предполагают, что какой-то параметр будет `` независимо от того, что ваша платформа имеет по умолчанию для этого значения '', и 3 распространенных виновника: заказ:

  • Кодировка кодировки
  • Locale
  • Часовой пояс

ofPattern(String)один из таких методов; он предполагает «языковой стандарт платформы по умолчанию», и, очевидно, при установке JDK8 он английский или что-то подобное, а при установке JDK11 - нет. Анализ AMкак значения для aполя зависит от языкового стандарта; очевидно, AM - это англичанин, это не имеет никакого смысла на голландском или французском языках!

Чтобы решить эту проблему, нужно сделать 2 действия:

  1. Если в вашей среде IDE есть функции, позволяющие пометить метод как «вы действительно никогда не должны это вызывать», вам следует серьезно подумать о добавлении всех этих методов в список, и если вы затем хотите, чтобы платформа использовалась по умолчанию, вы явно используете такие вещи, как Charset.defaultCharset(), например , чтобы сделать ясно, что вы действительно этого хотите.

  2. Исправьте свой код, вставив значок , Locale.ENGLISHпосле шаблона, и все снова будет хорошо, как дождь.

Пример:

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

будет терпеть неудачу на JDK8 так же, как и на JDK11.

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

работает и с JDK8, и с JDK11.

NB: Куча неанглийских языков, таких как .GERMANYand .ITALYи, .FRANCEдействительно каким-то образом правильно анализируют AM, но, как показано выше, голландский (Нидерланды) является примером, когда это не сработает.