Разница между часовым поясом и смещением
У вас уже есть два хороших ответа. Вы затрагиваете интересную и немного хитрую часть java.time, поэтому я хотел бы также внести свой вклад. Мой ключевой момент заключается в том, что часовой пояс и смещение UTC не совпадают . Чтобы получить OffsetDateTime
вам нужно смещение. Вы предоставляете часовой пояс посредством звонка .withZone(ZoneId.of("UTC"))
на устройстве форматирования, но это вам не поможет. Да, мы с вами знаем, что UTC является базой всех смещений и поэтому само определяет смещение 0. Но Java не обнаружила этого в вашем коде.
Признаюсь, я с удивлением обнаружил, что следующего простого изменения было достаточно, чтобы ваш код работал на Java 9:
final DateTimeFormatter formatter1
= DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS 'UTC'")
.withZone(ZoneOffset.UTC);
Однако на Java 8 я получаю то же исключение, что и раньше. Вывод, который я получил на Java 9.0.4, был:
======================:2019-06-18T16:23:41.575 UTC
Until (with crono): 0
Единственное изменение заключается в том, что теперь я передаю ZoneOffset
, а не ZoneId
объект withZone
(это возможно, поскольку ZoneOffset
является подклассом ZoneId
).
Форматер, который работает и в Java 8, - это тот, в котором мы предоставляем смещение по умолчанию. Для этого нам нужно DateTimeFormatterBuilder
:
final DateTimeFormatter formatter1 = new DateTimeFormatterBuilder()
.append(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
.appendLiteral(" UTC")
.parseDefaulting(ChronoField.OFFSET_SECONDS, 0)
.toFormatter();
Еще одним и, возможно, более простым вариантом будет сначала выполнить синтаксический анализ LocalDateTime
(который не требует ни смещения, ни часового пояса), а затем преобразовать в OffsetDateTime
, вызвав .atOffset(ZoneOffset.UTC)
.