Java ZonedDateTime 和英国夏令时
Java ZonedDateTime and British Summer Time
我目前正在查看日期在英国夏令时内外时的 ZonedDateTime 行为。
英国夏令时从 3 月 25 日开始,增加一小时 (+1)。
我创建了几个 ZonedDateTime 实例(UTC 和 Europe/London),接下来我给它们添加了 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 是不可变的。这意味着当我添加一个月时,我实际上创建了一个更改月份的新实例。你能告诉我我对给定观察的假设是否正确吗:
添加一个月将创建一个新的 ZonedDateTime 实例。 ZonedDateTime 上的小时将始终相同。新日期是否在 BST 中并不重要。 (查看 LondonFirstMarch 和 LondonFirstMarchPlusMonth)
因为添加 1 个月后 londonFirstMarchPlusMonth 落入 BST 以使其仍然是 12:00 它实际上提取了一个小时。这意味着基础纪元秒将不同于 utcFirstMarchPlusMonth。
最后,当我们将时区转换为 UTC 时,londonFirstMarchPlusMonthToUtc 显示实际时间是 11:00。
- 如果我想要恰好 1 个月后的约会。我应该只使用 UTC 并在最后选择将其转换为 London/Europe 吗?
编辑:
也许我不够清楚 - 抱歉。一个月是任意值,因此当添加到第一个日期时会产生属于 BST 的第二个日期。
如前所述,也许一个月不是一个很好的例子,因为它根据我们所处的月份而有不同的含义。对我来说,重点是 "month" 将由 24 小时单位组成。 (正如 Ole.v.v. 所说)
我认为在 UTC 时间上运行并可选择将其转换为 Europe/London 是 "my questions"
的解决方案
我建议您使用 Period
实例来实现 DateFormat
:
的正确行为
ZonedDateTime nZoneDateTime = utcFirstMarch.plus(Period.ofDays(30));
您的假设大体上是正确的。一些评论。
对于 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 即可。
我目前正在查看日期在英国夏令时内外时的 ZonedDateTime 行为。
英国夏令时从 3 月 25 日开始,增加一小时 (+1)。
我创建了几个 ZonedDateTime 实例(UTC 和 Europe/London),接下来我给它们添加了 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 是不可变的。这意味着当我添加一个月时,我实际上创建了一个更改月份的新实例。你能告诉我我对给定观察的假设是否正确吗:
添加一个月将创建一个新的 ZonedDateTime 实例。 ZonedDateTime 上的小时将始终相同。新日期是否在 BST 中并不重要。 (查看 LondonFirstMarch 和 LondonFirstMarchPlusMonth)
因为添加 1 个月后 londonFirstMarchPlusMonth 落入 BST 以使其仍然是 12:00 它实际上提取了一个小时。这意味着基础纪元秒将不同于 utcFirstMarchPlusMonth。
最后,当我们将时区转换为 UTC 时,londonFirstMarchPlusMonthToUtc 显示实际时间是 11:00。
- 如果我想要恰好 1 个月后的约会。我应该只使用 UTC 并在最后选择将其转换为 London/Europe 吗?
编辑:
也许我不够清楚 - 抱歉。一个月是任意值,因此当添加到第一个日期时会产生属于 BST 的第二个日期。
如前所述,也许一个月不是一个很好的例子,因为它根据我们所处的月份而有不同的含义。对我来说,重点是 "month" 将由 24 小时单位组成。 (正如 Ole.v.v. 所说)
我认为在 UTC 时间上运行并可选择将其转换为 Europe/London 是 "my questions"
的解决方案我建议您使用 Period
实例来实现 DateFormat
:
ZonedDateTime nZoneDateTime = utcFirstMarch.plus(Period.ofDays(30));
您的假设大体上是正确的。一些评论。
对于 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 即可。