ZonedDateTime изменить поведение JDK 8/11
Я перемещаю приложение с jdk 8 на 11 и вижу, что ZonedDateTime меняет поведение в отношении перехода на летнее время. JDK8
ZonedDateTime parse = ZonedDateTime.parse("2037-05-10T19:15:00.000+01:00[Europe/Paris]");
System.out.println(parse);
выходной: 2037-05-10T19:15+02:00[Европа / Париж]
JDK11 / 12
ZonedDateTime parse = ZonedDateTime.parse("2037-05-10T19:15:00.000+01:00[Europe/Paris]");
System.out.println(parse);
2037-05-10T20: 15 + 02: 00 [Европа / Париж]
Может кто-нибудь объяснить мне, почему они изменили это поведение?
С наилучшими пожеланиями,
1 ответ
Это известная ошибка в Java 8: JDK-8066982
Я считаю, что то, что вы испытываете в Java 8, на самом деле является этой ошибкой: ZonedDateTime.parse () возвращает неправильный ZoneOffset при падении перехода DST. Название ошибки не рассказывает всей истории. Настоящая проблема в том, что в Java 8 DateTimeFormatter.ISO_ZONED_DATE_TIME
(который неявно используется одно аргументом ZonedDateTime.parse
который вы используете) игнорирует смещение, если в проанализированную строку включен идентификатор часового пояса. Это в сочетании с базой данных часовых поясов, которая не согласуется с вашей строкой о смещении, используемом в Париже в октябре 2037 года, приводит к анализу момента времени, который конфликтует со смещением в строке.
Ошибка исправлена в Java 9. Таким образом, в Java 9, 10 и 11, поскольку то же самое разногласие в отношении смещения все еще существует, анализируемый момент основан на смещении строки. Затем он преобразуется в часовой пояс из строки с использованием правил из базы данных часовых поясов. Это приводит к изменению смещения с +01:00 на +02:00 и часового дня соответственно с 19:15 до 20:15. Я согласен с Java 9+, что это правильное поведение.
Не используйте ZonedDateTime для дальнейших дат
Ваша проблема также частично вызвана использованием ZonedDateTime
на будущее Это рекомендуется только в самом ближайшем будущем, где мы предполагаем, что правила зоны не изменяются. Для даты и времени в 2037 году вы должны использовать Instant
если вы знаете момент времени или LocalDateTime
если вы знаете только дату и время суток. Только когда время приближается, и вы уверены, что ваша установка Java получила последние обновления часового пояса, преобразуйте в ZonedDateTime
,
Как уже говорилось в комментариях, мы, вероятно, еще не знаем правильное смещение UTC для Парижа в октябре 2037 года. Похоже, что ЕС, скорее всего, откажется от летнего времени (DST) с 2021 года, и, насколько я знаю, французские политики еще не решили, сколько времени будет во Франции после этого.
Что если бы мы хотели время суток из строки?
Чтобы получить время из строки (19:15), разберите в LocalDateTime
:
String zdtString = "2037-05-10T19:15:00.000+01:00[Europe/Paris]";
LocalDateTime dateTime
= LocalDateTime.parse(zdtString, DateTimeFormatter.ISO_ZONED_DATE_TIME);
System.out.println("Date and time from string: " + dateTime);
Выход (запустить на Java 11):
Дата и время из строки: 2037-05-10T19:15
Если вам нужно полное поведение Java 8 в более поздней версии Java - как я уже говорил, это не рекомендуется, вы не должны использовать ZonedDateTime
Вот:
TemporalAccessor parsed = DateTimeFormatter.ISO_ZONED_DATE_TIME.parse(zdtString);
LocalDateTime dateTime = LocalDateTime.from(parsed);
ZoneId zone = ZoneId.from(parsed);
ZonedDateTime java8Zdt = dateTime.atZone(zone);
System.out.println("Time from string in zone from string: " + java8Zdt);
Время от строки в зоне от строки: 2037-05-10T19:15+02:00[Европа / Париж]