我看到的行为非常奇怪 - 有时候LocalDateTime
会等于ZonedDateTime
,有时会相差1小时或2,有时则是30分钟。所有这些奇怪的差异取决于我减去的年份。有人能解释一下发生了什么吗?已尝试jdk1.8.0_65
和jdk1.8.0_91
,MacOS 10.11.5
。我使用UTC:
ZoneOffset offset = ZoneOffset.UTC;
以下是一些实验。对于1919年,值可能相差纳米或毫秒,这是预期的:
assertEquals(
LocalDateTime.now(offset).minusYears(85).toInstant(offset),
ZonedDateTime.now().minusYears(85).withZoneSameInstant(offset).toInstant());
对于1919年它的1小时差异:
assertEquals(
LocalDateTime.now(offset).minusYears(86).toInstant(offset),
ZonedDateTime.now().minusYears(86).withZoneSameInstant(offset).toInstant());
Expected :<1930-05-28T20:19:10.383Z>
Actual :<1930-05-28T21:19:10.383Z>
对于1920年它的2小时差异:
assertEquals(
LocalDateTime.now(offset).minusYears(95).toInstant(offset),
ZonedDateTime.now().minusYears(95).withZoneSameInstant(offset).toInstant());
Expected :<1921-05-28T20:21:45.094Z>
Actual :<1921-05-28T18:21:45.094Z>
对于1921年再次毫秒或纳秒的差异:
assertEquals(
LocalDateTime.now(offset).minusYears(96).toInstant(offset),
ZonedDateTime.now().minusYears(96).withZoneSameInstant(offset).toInstant());
最奇怪的是 - 1930年<差> 30分钟差异:
assertEquals(
LocalDateTime.now(offset).minusYears(97).toInstant(offset),
ZonedDateTime.now().minusYears(97).withZoneSameInstant(offset).toInstant());
Expected :<1919-05-28T20:24:27.345Z>
Actual :<1919-05-28T19:53:08.346Z>
正如@Tunaki指出的那样,我必须指定ZonedDateTime
的偏移量:
assertEquals(
LocalDateTime.now(offset).minusYears(95).toInstant(offset),
ZonedDateTime.now(offset).minusYears(95).withZoneSameInstant(offset).toInstant());
答案 0 :(得分:1)
问题是这不知道时区:LocalDateTime.now(offset).minusYears(97).toInstant(offset)
。只有偏移存在。但是这知道时区:ZonedDateTime.now().minusYears(97).toInstant()
ZoneId
包含有关该地点的地点和时差的信息。它知道N年前在那个特定时区的偏移是2小时,而不是现在的3小时。 ZoneOffset
仅跟踪小时/分钟班次。它不知道特定国家的时间变化历史。它只是“增加了几个小时”。建议(并且有点不正确)解决方案是让ZonedDateTime
忘记区域并改为使用偏移:ZonedDateTime.now(offset).minusYears(97)
。现在这同意LocalDateTime
具有相同的偏移量 - 两者都会显示相同的不正确的信息。但是他们会同意,因为两者都“加上时间”,而不是理解那个地方的历史时间差:
ZoneOffset offset = ZoneId.of("Europe/Moscow").getRules().getOffset(Instant.now());
assertEquals(
LocalDateTime.now(offset).minusYears(97).toInstant(offset),
ZonedDateTime.now(offset).minusYears(97).toInstant());
或者,我们可以设置LocalDateTime
以显示该地点当时的正确值:
ZonedDateTime zoned = ZonedDateTime.now(ZoneId.of("Europe/Moscow")).minusYears(97);
ZoneOffset offset = zoned.getOffset();//agrees with history
assertEquals(
LocalDateTime.now().minusYears(97).toInstant(offset),
zoned.toInstant());
PS:这一切都表明ZonedDateTime
在不同的情况下可以有不同的工作方式 - 有时候它会知道时区,有时它只是“加上小时”,就像使用LocalDateTime手动设置偏移一样。对我来说,这是一个奇怪的实现。 JodaTime可能仍然是最好的Java实现。至少你几天不需要学习它来理解它。
答案 1 :(得分:0)
因为没有人回答这个问题......
在创建ZonedDateTime时也必须发送偏移量。否则它将使用Clock.systemDefaultZone()
,你会在时区上有所不同。
ZonedDateTime.now(offset).minusYears(95).withZoneSameInstant(offset).toInstant()