Узнайте, как обойти ошибку Java.time с написанием названия месяца

Недавно я обнаружил ошибку java.time. его очень легко воспроизвести;

Я тестировал его на JDK 17.0.10 и JDK 21.0.4 на MacOS X и Centos Stream 9.

Кодируйте как:

public class JakartaDateTime {

public static void main(String[] args) {
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss yyyy");
    LocalDateTime now = LocalDateTime.now();
    System.out.println(formatter.format(now));
}

Этот код напечатает строку

Fri Sept 06 23:10:23 2024

Конечно, я этого не ожидал, ожидаемый результат должен быть:

Fri Sep 06 23:10:23 2024

Я сообщил об этом как об ошибке в отчете об ошибках Java и в базе данных ошибок Oracle с идентификатором: 9077542. Я уверен, что это не будет исправлено в ближайшее время. Поэтому мне нужно найти обходной путь, чтобы избежать этого.

Я пытаюсь использовать gson для сопоставления json дохода с нашим классом Java, парой ключ/значение объекта json как:

{"date":"Fri Sep 06 23:10:23 2024"}

Итак, мне нужно написать десериализатор для анализа этой строки в java.time.LocalDateTime. Я сделал что-то вроде этого:

public class EuDateTimeDeserializer implements JsonDeserializer<LocalDateTime> {
@Override
public LocalDateTime deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext jsonDeserializationContext) throws JsonParseException {
    String dateTimeStr =jsonElement.getAsString();
    if (!ThssUtils.isValidString(dateTimeStr)){
        return null;
    }else {
        return LocalDateTime.parse(dateTimeStr, DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss yyyy"));
    }
  }
}

Но этот десериализатор работает только в другие месяцы, кроме сентября.

выдает ошибку как:

java.time.format.DateTimeParseException: Text 'Fri Sep  6 15:42:12 2024' could not be parsed at index 4

Это означает, что десериализатор не распознает указанную выше строку.

Есть ли у кого-нибудь такой опыт, чтобы найти способ избежать предыдущей ошибки java.time?

Пожалуйста, порекомендуйте!

Какую версию JDK вы используете?

aled 07.09.2024 01:25

Я тестировал его на JDK 17.0.10 и JDK 21.0.4 на MacOS X и Centos Stream 9.

cidy.long 07.09.2024 01:27

В чем конкретно у вас "ошибка"? Вы имеете в виду отсутствующий t в Sept и Sep?

Basil Bourque 07.09.2024 01:31
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
0
3
50
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

вр; доктор

Это не ошибка. Укажите Locale.

DateTimeFormatter.ofPattern( … ).withLocale( locale )

Функция, а не ошибка

Хотя вы забыли упомянуть, что именно вы считаете «ошибкой», я предполагаю, что вы имеете в виду отсутствующий t в Sept и Sep.

Локализация

Орфография, сокращения и пунктуация в формате даты и времени зависят от Locale. Человеческий язык и культурные нормы, содержащиеся в Locale объекте, управляют процессом локализации.

Укажите Locale

Здесь мы указываем английский в США 🇺🇸. Мы получаем Sep без t.

LocalDateTime ldt = LocalDateTime.of( 2024 , Month.SEPTEMBER , 6 , 23 , 10 , 23 , 0 );
System.out.println( "ldt = " + ldt );

Locale locale = Locale.of( "en" , "US" );
DateTimeFormatter formatter = DateTimeFormatter.ofPattern( "EEE MMM dd HH:mm:ss yyyy" ).withLocale( locale );
String output = formatter.format( ldt );

System.out.println( "output = " + output );

лдт = 2024-09-06T23:10:23

выход = пт, 6 сентября, 23:10:23 2024 г.

Измените этот язык на английский в Австралии 🇦🇺. Мы получаем Sept с помощью t.

Locale locale = Locale.of( "en" , "AU" );

лдт = 2024-09-06T23:10:23

выход = пятница, 6 сентября, 23:10:23 2024 г.

Измените этот язык на французский в Канаде 🇨🇦. Получаем sept. строчными буквами со знаками препинания.

Locale locale = Locale.of( "fr" , "CA" );

выход = вен. сентябрь 06 23:10:23 2024

Пожалуйста, отзовите свой ошибочный отчет об ошибке.

Совет: Всегда подозревайте свой собственный код или собственное непонимание, прежде чем сомневаться в библиотеке, поставляемой в комплекте с Java. Да, ошибка может проникнуть в кодовую базу реализации Java. Но такие ошибки, как ваше утверждение, встречаются редко. Кодовая база OpenJDK, используемая в большинстве реализаций Java, является одним из наиболее тщательно изученных и протестированных кодов, когда-либо созданных (за исключением таких специальностей, как военная и аэрокосмическая промышленность).

Избегайте LocalDateTime.now

Кстати, ваш код вызывает LocalDateTime.now. Я не могу представить сценарий, в котором это было бы разумно. Этот класс не может представлять момент.

Объект LocalDateTime представляет дату с указанием времени суток, но не имеет контекста смещения от UTC или часового пояса. Без этого контекста у нас нет возможности узнать, имели ли вы в виду 23:00 в Тувумбе, Австралия, 23:00 в Тулузе, Франция, или 23:00 в Толедо, штат Огайо, США — три совершенно разных момента, разделенных несколькими часами.

Чтобы запечатлеть текущий момент, используйте один из трех классов, отслеживающих определенную точку на временной шкале:

  • Instant
  • OffsetDateTime
  • ZonedDateTime

Первый и третий наиболее распространены для бизнес-целей, а второй используется в основном для обмена с базой данных SQL.

Instant now = Instant.now() ;  // Capture current moment as seen "in UTC", meaning an offset from UTC of zero hours-minutes-seconds. 

Увидьте тот же момент через настенные часы/календарь определенного часового пояса.

ZoneId z = ZoneId.of( "Australia/Brisbane" ) ;
ZonedDateTime zdt = instant.atZone( z ) ;

Вероятно, поэтому я живу в Австралии и использую AU в качестве локали по умолчанию. Спасибо Василий!

cidy.long 07.09.2024 01:49

@cidy.long Извлеченный урок: явно укажите желаемую/ожидаемую локаль, а не неявно полагайтесь на значение по умолчанию. То же самое и с часовым поясом: всегда указывайте желаемый/ожидаемый ZoneId.

Basil Bourque 07.09.2024 01:51

Другие вопросы по теме