Reputation: 3976
A week year is in sync with a WEEK_OF_YEAR cycle. All weeks between the first and last weeks (inclusive) have the same week year value. Therefore, the first and last days of a week year may have different calendar year values.
For example, January 1, 1998 is a Thursday. If getFirstDayOfWeek() is MONDAY and getMinimalDaysInFirstWeek() is 4 (ISO 8601 standard compatible setting), then week 1 of 1998 starts on December 29, 1997, and ends on January 4, 1998. The week year is 1998 for the last three days of calendar year 1997. If, however, getFirstDayOfWeek() is SUNDAY, then week 1 of 1998 starts on January 4, 1998, and ends on January 10, 1998; the first three days of 1998 then are part of week 53 of 1997 and their week year is 1997.
As the DOC said, if I set FirstDayOfWeek to SUNDAY and MinimalDaysInFirstWeek to 4, so week year of 1998-01-01 should be 1997, but junit result is 1998.
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.YEAR, 1998);
calendar.set(Calendar.MONTH, 0);
calendar.set(Calendar.DAY_OF_MONTH, 1);
calendar.setMinimalDaysInFirstWeek(4);
calendar.setFirstDayOfWeek(Calendar.SUNDAY);
System.out.println(calendar.getTimeZone());
System.out.println(calendar.getMinimalDaysInFirstWeek());
System.out.println(calendar.getFirstDayOfWeek());
SimpleDateFormat sdf = new SimpleDateFormat("YYYY-MM-dd");
System.out.println(sdf.format(calendar.getTime()));
junit result is: sun.util.calendar.ZoneInfo[id="Asia/Shanghai",offset=28800000,dstSavings=0,useDaylight=false,transitions=29,lastRule=null]
4
1
1998-01-01
Upvotes: 3
Views: 799
Reputation: 86203
TL;DR: The formatter uses its own week numbering
The date formatter is using its own week numbering scheme, not that of the date (in your case that of the Calendar
object). I am demonstrating using java.time the modern Java date and time API. Specifically I am using a LocalDate
. A LocalDate
is always a date in the ISO calendar system.
LocalDate date = LocalDate.of(1998, Month.JANUARY, 1);
DateTimeFormatter baseFormatter = DateTimeFormatter.ofPattern("YYYY-MM-dd");
DateTimeFormatter chinaFormatter = baseFormatter.withLocale(Locale.CHINA);
System.out.println("China: " + date.format(chinaFormatter));
DateTimeFormatter franceFormatter = baseFormatter.withLocale(Locale.FRANCE);
System.out.println("France: " + date.format(franceFormatter));
DateTimeFormatter irelandFormatter = baseFormatter.withLocale(Locale.forLanguageTag("en-IE"));
System.out.println("Ireland: " + date.format(irelandFormatter));
Output from this snippet is:
China: 1998-01-01 France: 1998-01-01 Ireland: 1997-01-01
A different way of obtaining a week year of 1997 from your date is to put your own WeekFields
object together. Then you don’t need to worry about locale.
WeekFields myWeekFields = WeekFields.of(DayOfWeek.SUNDAY, 4);
int weekYear = date.get(myWeekFields.weekBasedYear());
System.out.println("Week year: " + weekYear);
Week year: 1997
java.time??
The date and time classes that you were using, Calendar
and SimpleDateFormat
, are poorly designed and long outdated.
It seems from your document link that you are using Java 8, and if so, there’s absolutely no reason why you should struggle with the old classes. Use java.time as I do above. A backport for Java 6 and 7 exists too.
How come the code in the question didn’t work?
You were taking the time out of your Calendar
using calendar.getTime()
. This returns a Date
(another poorly designed and long outdated class). A Date
is a point in time, nothing more. It hasn’t got any notion of week number or week year. You passed this Date
to your SimpleDateFormat
, which had no way of detecting that the Date
had originally come from a Calendar
object with a certain setting of days in first week and first day of week. Instead the SimpleDateFormat
uses its own definition of weeks. It always does that. Since you had not explicitly set a locale or calendar for the SimpleDateFormat
, it used the default locale of your JVM. This produced a week year of 1998, as it would in the vast majority of locales.
Upvotes: 4