Understanding java.util.Calendar WEEK_OF_YEAR
From java.util.Calendar javadoc:
First Week
Calendar defines a locale-specific seven day week using two
parameters: the first day of the week and the minimal days in first
week (from 1 to 7). These numbers are taken from the locale resource
data when a Calendar is constructed. They may also be specified
explicitly through the methods for setting their values.When setting or getting the WEEK_OF_MONTH or WEEK_OF_YEAR fields,
Calendar must determine the first week of the month or year as a
reference point. The first week of a month or year is defined as the
earliest seven day period beginning on getFirstDayOfWeek() and
containing at least getMinimalDaysInFirstWeek() days of that month or
year. Weeks numbered ..., -1, 0 precede the first week; weeks numbered
2, 3,... follow it. Note that the normalized numbering returned by
get() may be different. For example, a specific Calendar subclass may
designate the week before week 1 of a year as week n of the previous
year.
So it's locale-specific. In your case, if the week contains days from new year, it is counted as week 1 from the new year.
You can change this behavior by using Calendar#setMinimalDaysInFirstWeek(int).
Java Calendar WEEK_OF_YEAR not ISO-8601compliant?
As I noted in my comment, the default behavior is locale specific. Some locales will give 3, some will give 2.
Luckily, you can specify the number of days that has to be present in the first week of the year, for a given Calendar
. As you write above, for ISO 8601, this number is 4
, thus the following code should work:
Calendar c = Calendar.getInstance();
c.setMinimalDaysInFirstWeek(4); // For ISO 8601
System.out.println(c.getTime());
System.out.println(c.get(Calendar.WEEK_OF_YEAR));
This should make the output correct regardless of locale.
Test output:
Mon Jan 11 14:54:22 CET 2016
2
A bug in week of year in Java Calendar?
Try setting Monday as first day of the week.
cal.setFirstDayOfWeek(Calendar.MONDAY);
WEEK_OF_YEAR inconsistent on different machines
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:
- java.util.Calendar
- java.util.GregorianCalendar
The second doc explains in detail how those two settings listed above are crucial to determining a localized week.
Calendar
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
versus2
(Sunday versus Monday)minimalDaysInFirstWeek
|1
versus4
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?
ISO 8601
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.
Example Code
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]
Moral Of The Story
Use ISO 8601 standard weeks! /p>
Thanks to Marco13, whose comments on the Question sparked this answer.
WEEK_OF_YEAR is same for two dates
Move back to starting day of the week I'm getting expected result. In my case Sunday is the starting day of week. So i setted cal.set(Calendar.DAY_OF_WEEK, Calendar.SUNDAY)
, this resolved my problem.
public static void main(String[] args) throws ParseException {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Date procDate = sdf.parse("2016-01-01");
Calendar cal = Calendar.getInstance(Locale.UK);
cal.setFirstDayOfWeek(Calendar.SUNDAY);
cal.setTime(procDate);
cal.set(Calendar.DAY_OF_WEEK, Calendar.SUNDAY); //Starting day of week
System.out.println(cal.get(Calendar.WEEK_OF_YEAR) );
System.out.println(cal.get(Calendar.YEAR) );
procDate = sdf.parse("2016-12-27");
cal.setTime(procDate);
cal.set(Calendar.DAY_OF_WEEK, Calendar.SUNDAY); //Starting day of week
System.out.println(cal.get(Calendar.WEEK_OF_YEAR) );
System.out.println(cal.get(Calendar.YEAR) );
}
Output:
52
2015
52
2016
Related Topics
Arraylist or List Declaration in Java
How to Serve Jsps from Inside a Jar in Lib, or Is There a Workaround
Transform Java Future into a Completablefuture
Change a Method at Runtime via a Hot Swap Mechanism
Which Artifacts Should I Use for Jaxb Ri in My Maven Project
How to View Tomcat Log Files in Eclipse
Comparing Time Is Incorrect When Picking 12:00
Differencebetween Local and Instance Variables in Java
Jtable Row Hightlighter Based on Value from Tablecell
Priorityqueue Not Sorting on Add
Should a "Static Final Logger" Be Declared in Upper-Case
Array Initialization Differences Java
Meaning of New Class(...){{...}} Initialization Idiom
Setter Methods or Constructors
How to Change the Size of the Font of a Jlabel to Take the Maximum Size