创建基于LocalDateTime的ZonedDateTime实例时出现问题

时间:2018-06-29 11:15:11

标签: java time timezone dst zoneddatetime

我看到一些我无法解释的行为,希望有人可以将我指向正确的方向。

我首先创建一个LocalDateTime实例,然后通过将“ Europe / London”时区应用于LocalDateTime来进入ZonedDateTime,然后使用DateTimeFormatter打印输出。我希望可以看到与LocalDateTime实例中指定的时间完全相同的时间,但是在下面的示例中,zonedDateTimeBeforeDST_Original的输出比我期望的时间晚了一个小时。

所以,简而言之:为什么我的LocalDateTime中的01:55变为ZonedDateTime的02:55?

仅供参考,其他时区没有这种行为。伦敦的情况似乎很特殊。

    //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 :(得分:1)

这是夏令时(DST)问题。当英国的夏令时开始并且时钟从1转到2时,没有2018-03-25 01:55:00。 ZonedDateTime不会给您不存在的时间,因此它选择了一个存在的时间。

确切选择的时间在the documentation of LocalDateTime.atZone中指定:

  

如果出现间隙,时钟向前跳,则没有有效的   偏移量。而是将本地日期时间调整为稍后   间隙的长度。对于典型的一小时夏令时更改,   当地日期时间通常会在一小时后移入偏移量   对应于“夏天”。

当然,在使用夏令时的其他时区也会发生同样的事情。只有每个时区都有自己的过渡时间,通常与2018年3月25日(星期日)的01:00不一致。