I'm writing some integration of legacy code that expects date/time as a GregorianCalendar.
So, I'm creating the GregorianCalendar using from(ZonedDateTime)
method.
However, the result is showing some inconsistent behaviour when the GregorianCalendar is created from the ZonedDateTime versus when the GregorianCalendar is created, let's say, from a string parsing or even from epoch millis. For example, when setting the Calendar day_of_week. To demonstrate this (https://onecompiler.com/java/3yssz4q86):
import java.util.*;
import java.time.*;
public class Main {
public static void main(String[] args) {
final GregorianCalendar calendarPure = new GregorianCalendar(TimeZone.getTimeZone("America/Los_Angeles"));
printInfo(calendarPure);
ZoneId zone = ZoneId.of("America/Los_Angeles");
final ZonedDateTime zdtNow = ZonedDateTime.now(zone);
final GregorianCalendar calendarFromZdt = GregorianCalendar.from(zdtNow);
printInfo(calendarFromZdt);
final GregorianCalendar calendarFromZdtEpoch = new GregorianCalendar();
calendarFromZdtEpoch.setTimeInMillis(zdtNow.toInstant().toEpochMilli());
printInfo(calendarFromZdtEpoch);
}
private static void printInfo(GregorianCalendar cal) {
System.out.printf("Now: %tc%n", cal);
System.out.printf("Last Sunday: %tc%n", getLastSunday(cal));
System.out.printf("Week of Year: %d%n", cal.get(Calendar.WEEK_OF_YEAR));
System.out.printf("Time in Millis: %d%n", cal.getTimeInMillis());
System.out.printf("toString(): %s%n", cal);
System.out.println();
}
public static GregorianCalendar getLastSunday(GregorianCalendar referenceDate) {
final GregorianCalendar lastSundayMidNight = (GregorianCalendar)referenceDate.clone();
lastSundayMidNight.set(Calendar.DAY_OF_WEEK, Calendar.SUNDAY);
return lastSundayMidNight;
}
}
The output is:
Now: Wed Dec 28 16:45:36 PST 2022
Last Sunday: Sun Dec 25 16:45:36 PST 2022
Week of Year: 53
Time in Millis: 1672274736631
toString(): java.util.GregorianCalendar[time=1672274736631,areFieldsSet=true,areAllFieldsSet=true,lenient=true,zone=sun.util.calendar.ZoneInfo[id="America/Los_Angeles",offset=-28800000,dstSavings=3600000,useDaylight=true,transitions=185,lastRule=java.util.SimpleTimeZone[id=America/Los_Angeles,offset=-28800000,dstSavings=3600000,useDaylight=true,startYear=0,startMode=3,startMonth=2,startDay=8,startDayOfWeek=1,startTime=7200000,startTimeMode=0,endMode=3,endMonth=10,endDay=1,endDayOfWeek=1,endTime=7200000,endTimeMode=0]],firstDayOfWeek=1,minimalDaysInFirstWeek=1,ERA=1,YEAR=2022,MONTH=11,WEEK_OF_YEAR=53,WEEK_OF_MONTH=5,DAY_OF_MONTH=28,DAY_OF_YEAR=362,DAY_OF_WEEK=4,DAY_OF_WEEK_IN_MONTH=4,AM_PM=1,HOUR=4,HOUR_OF_DAY=16,MINUTE=45,SECOND=36,MILLISECOND=631,ZONE_OFFSET=-28800000,DST_OFFSET=0]
Now: Wed Dec 28 16:45:36 PST 2022
Last Sunday: Sun Jan 01 16:45:36 PST 2023
Week of Year: 52
Time in Millis: 1672274736668
toString(): java.util.GregorianCalendar[time=1672274736668,areFieldsSet=true,areAllFieldsSet=true,lenient=true,zone=sun.util.calendar.ZoneInfo[id="America/Los_Angeles",offset=-28800000,dstSavings=3600000,useDaylight=true,transitions=185,lastRule=java.util.SimpleTimeZone[id=America/Los_Angeles,offset=-28800000,dstSavings=3600000,useDaylight=true,startYear=0,startMode=3,startMonth=2,startDay=8,startDayOfWeek=1,startTime=7200000,startTimeMode=0,endMode=3,endMonth=10,endDay=1,endDayOfWeek=1,endTime=7200000,endTimeMode=0]],firstDayOfWeek=2,minimalDaysInFirstWeek=4,ERA=1,YEAR=2022,MONTH=11,WEEK_OF_YEAR=52,WEEK_OF_MONTH=5,DAY_OF_MONTH=28,DAY_OF_YEAR=362,DAY_OF_WEEK=4,DAY_OF_WEEK_IN_MONTH=4,AM_PM=1,HOUR=4,HOUR_OF_DAY=16,MINUTE=45,SECOND=36,MILLISECOND=668,ZONE_OFFSET=-28800000,DST_OFFSET=0]
Now: Thu Dec 29 00:45:36 UTC 2022
Last Sunday: Sun Dec 25 00:45:36 UTC 2022
Week of Year: 53
Time in Millis: 1672274736668
toString(): java.util.GregorianCalendar[time=1672274736668,areFieldsSet=true,areAllFieldsSet=true,lenient=true,zone=sun.util.calendar.ZoneInfo[id="Etc/UTC",offset=0,dstSavings=0,useDaylight=false,transitions=0,lastRule=null],firstDayOfWeek=1,minimalDaysInFirstWeek=1,ERA=1,YEAR=2022,MONTH=11,WEEK_OF_YEAR=53,WEEK_OF_MONTH=5,DAY_OF_MONTH=29,DAY_OF_YEAR=363,DAY_OF_WEEK=5,DAY_OF_WEEK_IN_MONTH=5,AM_PM=0,HOUR=0,HOUR_OF_DAY=0,MINUTE=45,SECOND=36,MILLISECOND=668,ZONE_OFFSET=0,DST_OFFSET=0]
I noticed that, from GregorianCalendar.toString()
that prints the internal fields a different in firstDayOfWeek
and minimalDaysInFirstWeek
. That could be the cause for the divergence in the after results. I wonder where the GregorianCalendar is getting these values from. Maybe there is a way to set something on ZonedDateTime object that will ensure the results will be the same? Couldn't find anything on javadocs.
Note: Please, don't tell me not to use GregorianCalendar
. I know, I know. I'm just writing an integration for two pieces of code that I'm not allowed to modify, one uses GregorianCalendar
(sigh), the other uses ZonedDateTime
.