Update: ok, I seem to have found half the answer. If I created my Calendar with a no-argument getInstance, I get WEEK_OF_YEAR = 52. However, if I create it
[See Update below. Incorrect answer.]
For ISO 8601 weeks where week # 1 has the first Thursday, the correct answer 2010-W52
.
For comparison and experiment, try using either Joda-Time or the new java.time package in Java 8 (inspired by Joda-Time). And anyways, you should be using those as the java.util.Date and .Calendar classes are a notoriously troublesome mess.
DateTime dateTime = new DateTime( 2011, 1, 1, 0, 0, 0, DateTimeZone.UTC );
int weekNumber = dateTime.getWeekOfWeekYear();
String output = ISODateTimeFormat.weekDate().print( dateTime );
I assumed incorrectly that java.util.Calendar determined week-of-year by the ISO 8601 standard. It does not. It uses a Locale to influence the result of its getFirstDayOfWeek()
method. It then uses the earliest seven day period beginning with that day as its first week of year. See "First Week" section of doc.
So using Joda-Time or java.time will not help in debugging the problem. I leave this answer to highlight (a) the difference between using a standard week versus a localized week, and (b) the importance of not making assumptions.
firstDayOfWeek
& minimalDaysInFirstWeek
Turns out to be a feature, not a bug.
The cause of the different behaviors you see is two settings reported in your output shown in the Question:
firstDayOfWeek
minimalDaysInFirstWeek
It’s important to read the doc for both the class and subclass:
The second doc explains in detail how those two settings listed above are crucial to determining a localized week.
Note the calendar. The first day of 2011 is a Saturday. The second of the month is a Sunday, and Sunday is the default start-of-week for United States.
On a Mac OS X computer set to United States locale, these settings are both 1
. If the minimum days needed is 1, then the First lands on a localized Week 1. Java reports this.
But on your reported problem machine, these settings are 2 and 4, respectively. I don't know how you got these settings altered from the usual defaults, but you did.
firstDayOfWeek
| 1
versus 2
(Sunday versus Monday)minimalDaysInFirstWeek
| 1
versus 4
The minimum of 4 days means that the First does not qualify as a week in the new year. So it is week 52 of the previous year (2010). The first week of 2011 is January 2, 2011 through January 8.
So the behavior you are seeing matches expectations given the documentation for the java.util.Calendar class in Java 7. The mystery is how did those settings get changed away from the default on your problem machine?
By the way, the doc mentions that settings of 2 & 4 gives you the behavior defined by the ISO 8601 standard, as mentioned in my other answer. That may be the clue as to why these settings are non-default on your problem machine. Someone, a sysadmin or programmer, may be trying to get standard behavior rather than localized behavior.
Let's demonstrate this with some code. We’ll use a modified version of the code from the Question. Our code here explicitly sets the variables at issue. So you can run this example on any of your machines, normal or problem. First we force the use of the settings found by default on a US Locale machine, 1
& 1
. Then we use the settings reported in the Question, 2
& 4
.
Locale l = Locale.getDefault();
System.out.println( l + "\n" );
Long d = new Long( 1293840000000l );
Calendar c = Calendar.getInstance();
c.setTimeZone( TimeZone.getTimeZone( "UTC" ) );
c.setTime( new Date( d ) );
// Running Java 8 Update 11, Mac OS 10.8.5, virtual machine in Parallels 9, hosted on Mac with Mavericks.
// Force the use of default settings found on a machine set for United States locale (using Apple defaults).
c.setFirstDayOfWeek( 1 );
c.setMinimalDaysInFirstWeek( 1 );
// Reports: WEEK_OF_YEAR=1
System.out.println( "Default US settings:\n" + c.toString() + "\n" );
// Using reported settings (Coincides with ISO 8601 Week definition).
c.setFirstDayOfWeek( 2 );
c.setMinimalDaysInFirstWeek( 4 );
// Reports: WEEK_OF_YEAR=52
System.out.println( "Reported settings (ISO 8601):\n" + c.toString() + "\n" );
When run…
en_US
Default US settings:
java.util.GregorianCalendar[time=1293840000000,areFieldsSet=true,areAllFieldsSet=true,lenient=true,zone=sun.util.calendar.ZoneInfo[id="UTC",offset=0,dstSavings=0,useDaylight=false,transitions=0,lastRule=null],firstDayOfWeek=1,minimalDaysInFirstWeek=1,ERA=1,YEAR=2011,MONTH=0,WEEK_OF_YEAR=1,WEEK_OF_MONTH=1,DAY_OF_MONTH=1,DAY_OF_YEAR=1,DAY_OF_WEEK=7,DAY_OF_WEEK_IN_MONTH=1,AM_PM=0,HOUR=0,HOUR_OF_DAY=0,MINUTE=0,SECOND=0,MILLISECOND=0,ZONE_OFFSET=0,DST_OFFSET=0]
Reported settings (ISO 8601):
java.util.GregorianCalendar[time=1293840000000,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=2011,MONTH=0,WEEK_OF_YEAR=52,WEEK_OF_MONTH=0,DAY_OF_MONTH=1,DAY_OF_YEAR=1,DAY_OF_WEEK=7,DAY_OF_WEEK_IN_MONTH=1,AM_PM=0,HOUR=0,HOUR_OF_DAY=0,MINUTE=0,SECOND=0,MILLISECOND=0,ZONE_OFFSET=0,DST_OFFSET=0]
Use ISO 8601 standard weeks!