Формат LocalDateTime с часовым поясом в Java8

У меня есть этот простой код:

DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyyMMdd HH:mm:ss.SSSSSS Z");
LocalDateTime.now().format(FORMATTER)

Тогда я получу следующее исключение:

java.time.temporal.UnsupportedTemporalTypeException: Unsupported field: OffsetSeconds
at java.time.LocalDate.get0(LocalDate.java:680)
at java.time.LocalDate.getLong(LocalDate.java:659)
at java.time.LocalDateTime.getLong(LocalDateTime.java:720)
at java.time.format.DateTimePrintContext.getValue(DateTimePrintContext.java:298)
at java.time.format.DateTimeFormatterBuilder$OffsetIdPrinterParser.format(DateTimeFormatterBuilder.java:3315)
at java.time.format.DateTimeFormatterBuilder$CompositePrinterParser.format(DateTimeFormatterBuilder.java:2182)
at java.time.format.DateTimeFormatter.formatTo(DateTimeFormatter.java:1745)
at java.time.format.DateTimeFormatter.format(DateTimeFormatter.java:1719)
at java.time.LocalDateTime.format(LocalDateTime.java:1746)

Как решить эту проблему?

Ответ 1

LocalDateTime - это дата-время без временной зоны. Вы указали символ формата смещения часового пояса в формате, однако LocalDateTime не имеет такой информации. Вот почему произошла ошибка.

Если вам нужна информация о часовом поясе, вы должны использовать ZonedDateTime.

DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyyMMdd HH:mm:ss.SSSSSS Z");
ZonedDateTime.now().format(FORMATTER)
=> "20140829 14:12:22.122000 +09"

Ответ 2

Префикс "Локальный" в JSR-310 (aka java.time-package в Java-8) не указывает, что во внутреннем состоянии этого класса есть информация о часовом поясе (здесь: LocalDateTime). Несмотря на часто вводимое в заблуждение имя, такие классы, как LocalDateTime или LocalTime, не имеют информации о часовом поясе или смещения.

Вы пытались отформатировать такой временный тип (который не содержит никакого смещения) со смещенной информацией (обозначенной символом шаблона Z). Поэтому форматер пытается получить доступ к недоступной информации и должен отбросить исключение, которое вы наблюдали.

Решение:

Используйте тип, который имеет такую ​​информацию о смещении или часовом поясе. В JSR-310 это либо OffsetDateTime (который содержит смещение, но не часовой пояс, включая правила DST) или ZonedDateTime. Вы можете просмотреть все поддерживаемые поля такого типа, посмотрев на метод isSupported (TemporalField).. Поле OffsetSeconds поддерживается в OffsetDateTime и ZonedDateTime, но не в LocalDateTime.

DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd HH:mm:ss.SSSSSS Z");
String s = ZonedDateTime.now().format(formatter);