Проблема создания экземпляра ZonedDateTime на основе LocalDateTime - PullRequest
0 голосов
/ 29 июня 2018

Я вижу какое-то поведение, которое не могу объяснить, надеясь, что кто-то может указать мне правильное направление.

Сначала я создаю экземпляр LocalDateTime, затем перехожу к ZonedDateTime, применяя часовой пояс «Европа / Лондон» к LocalDateTime, а затем использую DateTimeFormatter для печати для вывода. Я ожидаю увидеть точно такое же время, как указано в экземпляре LocalDateTime, но в приведенном ниже примере вывод для zonedDateTimeBeforeDST_Original показывает на час позже, чем я ожидал.

Итак, вкратце: почему 01:55 в моем LocalDateTime становится 02:55 для ZonedDateTime?

К вашему сведению, такого поведения не наблюдалось для других часовых поясов. Лондонский кажется особенным случаем.

    //init date pattern
    final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
    final DateTimeFormatter formatterOut = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss XXX");

    LocalDateTime localDateTimeBeforeDST = LocalDateTime.parse("2018-03-25 01:55:00", formatter); //testing with time 5 minutes before DST switch or after
    System.out.println("LocalDateTime: " + localDateTimeBeforeDST.format(formatter));
    System.out.println();

    String originalZone = "Europe/London";

    ZoneId originalZoneId = ZoneId.of(originalZone);
    ZoneId utcZoneId = ZoneId.of("Etc/UTC");
    ZoneId localZoneId = ZoneId.of("Europe/London");
    ZoneId localZoneId_2 = ZoneId.of("Europe/Brussels");

    ZonedDateTime zonedDateTimeBeforeDST_Original = localDateTimeBeforeDST.atZone(originalZoneId);
    ZonedDateTime zonedDateTimeBeforeDST_UTC = zonedDateTimeBeforeDST_Original.withZoneSameInstant(utcZoneId);
    ZonedDateTime zonedDateTimeBeforeDST_1 = zonedDateTimeBeforeDST_UTC.withZoneSameInstant(localZoneId);
    ZonedDateTime zonedDateTimeBeforeDST_2 = zonedDateTimeBeforeDST_UTC.withZoneSameInstant(localZoneId_2);

    System.out.println("Instant:                         " + zonedDateTimeBeforeDST_Original.toEpochSecond());
    System.out.println();
    System.out.println("ZonedDateTime (" + originalZone + "):   " + zonedDateTimeBeforeDST_Original.format(formatterOut));
    System.out.println("ZonedDateTime (Etc/UTC):         " + zonedDateTimeBeforeDST_UTC.format(formatterOut));
    System.out.println("ZonedDateTime (Europe/London):   " + zonedDateTimeBeforeDST_1.format(formatterOut));
    System.out.println("ZonedDateTime (Europe/Brussels): " + zonedDateTimeBeforeDST_2.format(formatterOut));
    System.out.println();

    zonedDateTimeBeforeDST_Original = zonedDateTimeBeforeDST_Original.plus(10, ChronoUnit.MINUTES);
    zonedDateTimeBeforeDST_UTC = zonedDateTimeBeforeDST_Original.withZoneSameInstant(utcZoneId);
    zonedDateTimeBeforeDST_1 = zonedDateTimeBeforeDST_UTC.withZoneSameInstant(localZoneId);
    zonedDateTimeBeforeDST_2 = zonedDateTimeBeforeDST_UTC.withZoneSameInstant(localZoneId_2);

    System.out.println("ZonedDateTime (DST) (" + originalZone + "):   " + zonedDateTimeBeforeDST_Original.format(formatterOut));
    System.out.println("ZonedDateTime (DST) (Etc/UTC):         " + zonedDateTimeBeforeDST_UTC.format(formatterOut));
    System.out.println("ZonedDateTime (DST) (Europe/London):   " + zonedDateTimeBeforeDST_1.format(formatterOut));
    System.out.println("ZonedDateTime (DST) (Europe/Brussels): " + zonedDateTimeBeforeDST_2.format(formatterOut));

Выход:

LocalDateTime: 2018-03-25 01:55:00

Instant:                         1521942900

ZonedDateTime (Europe/London):   2018-03-25 02:55:00 +01:00
ZonedDateTime (Etc/UTC):         2018-03-25 01:55:00 Z
ZonedDateTime (Europe/London):   2018-03-25 02:55:00 +01:00
ZonedDateTime (Europe/Brussels): 2018-03-25 03:55:00 +02:00

ZonedDateTime (DST) (Europe/London):   2018-03-25 03:05:00 +01:00
ZonedDateTime (DST) (Etc/UTC):         2018-03-25 02:05:00 Z
ZonedDateTime (DST) (Europe/London):   2018-03-25 03:05:00 +01:00
ZonedDateTime (DST) (Europe/Brussels): 2018-03-25 04:05:00 +02:00

1 Ответ

0 голосов
/ 29 июня 2018

Это проблема летнего времени (DST). Когда в Великобритании началось летнее время и часы были переведены с 1 на 2, 2018-03-25 01:55:00 не было. ZonedDateTime не дает вам несуществующего времени, поэтому он выбрал вместо него существующее.

Точное время, которое он выбирает, указано в документации LocalDateTime.atZone:

В случае разрыва, когда часы прыгают вперед, нет действительного смещение. Вместо этого местное время и дата корректируются, чтобы быть позже длина зазора. Для типичной смены летнего времени на один час местное время и дата будут перемещены на час позже в смещение, как правило, соответствует "лето".

То же самое происходит в других часовых поясах, которые используют летнее время, конечно. Только каждый часовой пояс имеет свое собственное время перехода, которое обычно не совпадает с воскресеньем, 25 марта 2018 года в 01:00.

...