为什么在评估 ZoneInfo 部分时 GregorianCalendar 和 OffsetDateTime 之间的转换失败?

Why does conversion between GregorianCalendar and OffsetDateTime fail when evaluating the ZoneInfo part?

我正在将 OffsetDateTime 转换为 GregorianCalendar 作为出站 Web 服务填充值的一部分。我只是想测试实际的转换。

它失败了,我不明白为什么 - 这是测试方法:

@Test
public void testOffsetDateTimeToGregorianCalendar() {
    // given the current gregorian utc time
    GregorianCalendar expectedGregorianUtcNow = new GregorianCalendar(TimeZone.getTimeZone("UTC"));
    OffsetDateTime expectedUtcOffsetDateTime = OffsetDateTime.from(expectedGregorianUtcNow.toZonedDateTime());

    // when converting to a GregorianCalendar
    GregorianCalendar actualGregorianUtcNow = GregorianCalendar.from(expectedUtcOffsetDateTime.toZonedDateTime());

    // then make sure we got the correct value
    assertThat(actualGregorianUtcNow, equalTo(expectedGregorianUtcNow));
}

在 equalto 中,比较在 gregorianCutover 的评估中失败。为什么?这是一个错误吗?

看起来实际有: 公历转换 = -9223372036854775808 并且预期有: gregorianCutover = -12219292800000

从单元测试输出中可以看出其他一切都是正确的(gregorianCutover 没有出现在那里):

    java.lang.AssertionError: 
    Expected:<java.util.GregorianCalendar[time=1458667828375,areFieldsSet=true,areAllFieldsSet=true,lenient=true,zone=sun.util.calendar.ZoneInfo[id="UTC",offset=0,dstSavings=0,useDaylight=false,transitions=0,lastRule=null],firstDayOfWeek=2,minimalDaysInFirstWeek=4,ERA=1,YEAR=2016,MONTH=2,WEEK_OF_YEAR=12,WEEK_OF_MONTH=4,DAY_OF_MONTH=22,DAY_OF_YEAR=82,DAY_OF_WEEK=3,DAY_OF_WEEK_IN_MONTH=4,AM_PM=1,HOUR=5,HOUR_OF_DAY=17,MINUTE=30,SECOND=28,MILLISECOND=375,ZONE_OFFSET=0,DST_OFFSET=0]>
    but: was <java.util.GregorianCalendar[time=1458667828375,areFieldsSet=true,areAllFieldsSet=true,lenient=true,zone=sun.util.calendar.ZoneInfo[id="UTC",offset=0,dstSavings=0,useDaylight=false,transitions=0,lastRule=null],firstDayOfWeek=2,minimalDaysInFirstWeek=4,ERA=1,YEAR=2016,MONTH=2,WEEK_OF_YEAR=12,WEEK_OF_MONTH=4,DAY_OF_MONTH=22,DAY_OF_YEAR=82,DAY_OF_WEEK=3,DAY_OF_WEEK_IN_MONTH=4,AM_PM=1,HOUR=5,HOUR_OF_DAY=17,MINUTE=30,SECOND=28,MILLISECOND=375,ZONE_OFFSET=0,DST_OFFSET=0]>

我是不是做错了什么?

基本上,据我所知,java.time 不会尝试模拟公历转换 - 所以当 OffsetDateTime 转换回 GregorianCalendar 时,那是通过将其建模为具有在时间开始时切换回来的公历来完成。因此 GregorianCalendar.from(ZoneDateTime):

的文档

Since ZonedDateTime does not support a Julian-Gregorian cutover date and uses ISO calendar system, the return GregorianCalendar is a pure Gregorian calendar and uses ISO 8601 standard for week definitions, which has MONDAY as the FirstDayOfWeek and 4 as the value of the MinimalDaysInFirstWeek.

理想情况下,我建议您避免在 date/time API 方面使用 java.util.*...坚持使用 java.time。但是,如果您确实需要,我可能建议您不要使用 GregorianCalendar.equals 来测试相等性 - 如果您对这些感兴趣,请分别检查时间和时区。