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

I am converting an OffsetDateTime to a GregorianCalendar as part of populating values for an outbound web service. I just thought I'd test the actual conversion.

It is failing and i don't understand why - here is the test method:

@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));
}

within the equalto, the comparison fails in the evaluation of the gregorianCutover. Why? Is this a bug?

it looks like actual has: gregorianCutover = -9223372036854775808 and expected has: gregorianCutover = -12219292800000

Everything else is correct as can be seen in the unit test output (gregorianCutover does not appear there):

    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]>

Did i do something wrong?

Jon Skeet
people
quotationmark

Basically, as far as I'm aware, java.time doesn't try to model a Gregorian cutover - so when an OffsetDateTime is converted back to a GregorianCalendar, that's done by modeling it as having a Gregorian calendar with a cutover back at the start of time. Hence the documentation for 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.

Ideally, I'd suggest that you avoid using java.util.* in terms of date/time API... stick with java.time everywhere. But if you really need to, I'd probably suggest just not using GregorianCalendar.equals for testing equality - check the instant in time and the time zone separately, if those are the things you're interested in.

people

See more on this question at Stackoverflow