Java ZonedDateTime和英国夏令时

时间:2018-01-27 13:20:51

标签: java utc dst zoneddatetime jsr310

我目前正在查看日期在英国夏令时内外的ZonedDateTime行为。

英国夏令时从3月25日开始,增加一小时(+1)。

我创建了ZonedDateTime(UTC和欧洲/伦敦)的几个实例,然后我在1个月内添加了它们,以便它们落入ZonedDateTime。

// These dates will be outside British Summer Time
ZonedDateTime utcFirstMarch = ZonedDateTime.of(2018, 3, 1, 12, 0, 0, 0, ZoneId.of("UTC"));
ZonedDateTime londonFirstMarch = ZonedDateTime.of(2018, 3, 1, 12, 0, 0, 0, ZoneId.systemDefault());

// These dates will be inside British Summer Time
ZonedDateTime utcFirstMarchPlusMonth = ZonedDateTime.of(2018, 3, 1, 12, 0, 0, 0, ZoneId.of("UTC")).plusMonths(1);
ZonedDateTime londonFirstMarchPlusMonth = ZonedDateTime.of(2018, 3, 1, 12, 0, 0, 0, ZoneId.systemDefault()).plusMonths(1);

ZonedDateTime londonFirstMarchPlusMonthToUtc = ZonedDateTime.of(2018, 3, 1, 12, 0, 0, 0, ZoneId.systemDefault()).plusMonths(1).withZoneSameInstant(ZoneId.of("UTC"));

这是打印这些日期时的结果:

utcFirstMarch:                  2018-03-01T12:00Z[UTC]
londonFirstMarch:               2018-03-01T12:00Z[Europe/London]
utcFirstMarchPlusMonth:         2018-04-01T12:00Z[UTC]
londonFirstMarchPlusMonth:      2018-04-01T12:00+01:00[Europe/London]
londonFirstMarchPlusMonthToUtc: 2018-04-01T11:00Z[UTC]

最后,我打印了每个日期的纪元秒:

utcFirstMarch:                  1519905600
londonFirstMarch:               1519905600
utcFirstMarchPlusMonth:         1522584000
londonFirstMarchPlusMonth:      1522580400
londonFirstMarchPlusMonthToUtc: 1522580400

我知道ZonedDateTime是不可变的。这意味着当我添加一个月时,我实际上创建了一个月更改的新实例。能否请您告诉我对给定观察结果的假设是否正确:

  1. 添加一个月将创建ZonedDateTime的新实例。 ZonedDateTime上的小时将始终相同。新日期是否在BST中无关紧要。 (看看LondonFirstMarch和LondonFirstMarchPlusMonth)

  2. 因为在加入1个月后,londonFirstMarchPlusMonth落入BST以使其仍然是12:00,它实际上提取了一个小时。这意味着底层纪元秒将与utcFirstMarchPlusMonth不同。

  3. 最后,当我们将区域转换为UTC时,londonFirstMarchPlusMonthToUtc显示实际小时为11:00。

  4. 如果我想要一个月后的日期。我应该只使用UTC,并可选择将其转换为伦敦/欧洲?
  5. 修改

    也许我不够清楚 - 道歉。一个月是任意值,因此当添加到第一个日期时,产生第二个日期属于BST。

    如上所述,也许一个月不是一个很好的例子,因为它取决于我们所处的月份,这意味着不同的事情。对我来说,“月份”将由24小时单位组成。 (正如Ole.v.v.所说)

    我认为按UTC时间运行并可选择将其转换为欧洲/伦敦是“我的问题”的解决方案

2 个答案:

答案 0 :(得分:2)

您的假设通常是正确的。一些评论。

对于1.,ZonedDateTime将尝试保持小时相同。只有在不可能的情况下,它才会做其他事情。例如,可能希望以下内容打印时间01:30:

    System.out.println(ZonedDateTime
            .of(2018, 2, 25, 1, 30, 0, 0, ZoneId.of("Europe/London"))
            .plusMonths(1));

打印

2018-03-25T02:30+01:00[Europe/London]

在过渡到夏令时时间从1点到凌晨2点向前移动,因此那天 没有时间是1:30。 ZonedDateTime不会产生不存在的时间,因此在这种情况下它会选择02:30。

对于4,“恰好一个月”有点难以严格定义,因为一个月可能是28天,29天,30天或31天。但是如果你想要24小时的倍数,那么使用UTC会给你这个。

答案 1 :(得分:-3)

我建议您使用Period个实例来表达DateFormat的正确行为:

ZonedDateTime nZoneDateTime = utcFirstMarch.plus(Period.ofDays(30));