Получение java.time.DateTimeException при форматировании экземпляра LocalDateTime с Locale - PullRequest
0 голосов
/ 04 марта 2019

Это мне не понятно.По какой-то причине, когда я пытаюсь отформатировать LocalDateTime экземпляр, используя DateTimeFormatter.ofLocalizedDateTime(FormatStyle.LONG).withLocale(...), я получаю исключение:

java.time.DateTimeException: Невозможно извлечь значение: класс java.time.LocalDateTime

Это происходит, только если я использую FormatStyle.LONG, отлично работает, например, для FormatStyle.MEDIUM.

Вот мой тест:

@Test
public void dateTest() {
    LocalDateTime now = LocalDateTime.now();

    // this is ok. prints a value
    System.out.println("LocalDateTime now (formatted with locale): "
            + now.format(DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM)
                                                       .withLocale(new Locale("it"))));

    // this fails with java.time.DateTimeException: Unable to extract value: class java.time.LocalDateTime
    // only if FormatStyle.LONG (as it is now)
    System.out.println("LocalDateTime now (formatted with locale): "
            + now.format(DateTimeFormatter.ofLocalizedDateTime(FormatStyle.LONG)
                                                       .withLocale(new Locale("it"))));
}

Есть ли хорошее объяснение этому?

Ответы [ 3 ]

0 голосов
/ 05 марта 2019

В настоящее время (Java "1.8.0_162") FormatStyle.FULL и .LONG применяются ТОЛЬКО для .format (date) LocalDateTime не хранит много деталей, в которых проблема.

Подробности: https://coderanch.com/t/690125/java/java-time-DateTimeException-FormatStyle-LONG

0 голосов
/ 06 марта 2019

tl; dr

Есть ли хорошее объяснение этому?

Да.

Форматы LONG и FULL *Для 1011 * требуется часовой пояс или смещение от UTC.В вашем LocalDateTime отсутствует какая-либо зона или смещение.

Использование LocalDateTime.now неверно .Вы должны фиксировать текущий момент только с помощью Instant (или OffsetDateTime / ZonedDateTime).

Instant.now()  // Capture the current moment as seen in UTC.

Для большей гибкости при генерации строк используйте OffsetDateTime или ZonedDateTime.

ZonedDateTime.now( 
    ZoneId.of( "Pacific/Auckland" )
)
.format(
    DateTimeFormatter.ofLocalizedDateTime(
        FormatStyle.LONG   // Or `FULL`.
    )
    .withLocale( Locale.ITALY ) 
)

6 марта 2019 10:22:23 NZDT

И с FormatStyle.FULL:

mercoledì 6 марта 2019 10:23: 25 Ora legale della Nuova Zelanda

LocalDateTime - это , а не мгновение

Класс LocalDateTime - это просто дата и времядень.Намеренно отсутствует какая-либо концепция часового пояса или смещения от UTC.Таким образом, по определению, он не может представлять момент.

Никогда не звоните LocalDateTime.now()

LocalDateTime.now();

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

Никогда не используйте LocalDateTime при отслеживании моментов.LocalDateTime - это просто дата и время суток, и ничего более.Без контекста часового пояса или смещения от UTC , LocalDateTime не может представлять момент.Он представляет потенциальных моментов в диапазоне около 26-27 часов, текущем диапазоне часовых поясов по всему земному шару.

A LocalDateTime - все равно что сказать «полдень 23 января этого года».Вы имеете в виду полдень в Токио, Япония или Калькутта, Индия?Или, может быть, Париж, Франция?Монреаль, Квебек?Полдень в этих разных местах случается в разные моменты, и между ними проходит время.

«Локальный» в LocalDateTime означает любой населенный пункт или каждый населенный пункт, но не означает любой конкретный locality.

Запись текущего момента

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

  • InstantМомент в UTC, всегда в UTC
  • OffsetDateTimeМомент со смещением от UTC, то есть на несколько часов-минут-секунд перед или за базовой линией UTC (меридиан в Королевская обсерватория в Гринвиче).
  • ZonedDateTimeМомент, который видят часы настенного времени, используемые людьми определенного региона (часового пояса).

Как правило, лучшая практика - это работать в UTC и забыть о своем собственном приходском часовом поясе..

Instant instant = Instant.now() ;

Если вы хотите использовать настенное время какого-либо региона:

ZoneId z = ZoneId.of( "Africa/Tunis" ) ;
ZonedDateTime zdt = instant.atZone( instant ) ;

И instant, и zdt представляют один и тот же момент одновременно,та же единственная точка на временной шкале.Только время настенных часов отличается.

Или вы можете пропустить Instant.

ZonedDateTime zdt = ZonedDateTime.now( z ) ;

Форматы LONG & FULL требуют часовой пояс

Эти два стиля формата:

… оба требуют часовой пояс как часть их отображения.

Как обсуждалось выше, объект LocalDateTime не имеет зоны или смещения.Поэтому нет смысла использовать форматы LONG или FUL с таким объектом.

Совет: LocalDateTime - это не тот класс, который вам нужен в большинстве распространенных бизнес-приложений.Используйте этот класс только в том случае, если у вас есть конкретная проблема, например, когда вы назначаете встречи в будущем достаточно далеко, и вы рискуете, что политики переопределят смещение вашего часового пояса (что они часто делают в большинстве стран).При отслеживании определенного момента сначала подумайте об использовании Instant.

0 голосов
/ 04 марта 2019

С FormatStyle.LONG Вы должны использовать:

ZonedDateTime.now()

Вместо:

LocalDateTime.now()

Поскольку ZonedDateTime дает вам много деталей, а не LocalDateTime.

Когда вы используете FormatStyle.LONG, форматер ищет другую информацию, такую ​​как ZoneId, которая не найдена в LocalDateTime, поэтому вы получаете исключения

...