I tried the following piece of code:
Calendar c1 = Calendar.getInstance();
c1.set(Calendar.YEAR, 0);
c1.set(Calendar.DAY_OF_YEAR, 1);
Date d1 = c1.getTime();
Calendar c2 = Calendar.getInstance();
c2.setTime(d1);
c2.set(Calendar.YEAR, 2001);
c2.set(Calendar.DAY_OF_YEAR, 1);
System.out.println(c2.getTime().toString());
Calendar c3 = Calendar.getInstance();
c3.set(Calendar.YEAR, 2000);
c3.set(Calendar.DAY_OF_YEAR, 1);
Date d2 = c3.getTime();
Calendar c4 = Calendar.getInstance();
c4.setTime(d2);
c4.set(Calendar.YEAR, 2001);
c4.set(Calendar.DAY_OF_YEAR, 1);
System.out.println(c4.getTime().toString());
The result is:
Wed Jan 01 23:47:00 CET 2001
Mon Jan 01 23:47:00 CET 2001
What is wrong? Shouldn't I use Calendar in this way for setting YEAR?
The year is relative to the era. By setting the year to something less or equal to 0 the calendar automatically corrects this by switching the era (from AD to BC or from BC to AD). This behaviour is better known from the other fields. E.g. if you set the month to something negative the year gets decremented accordingly.
Those corrections aren't made individually but rather they are made all at once, usually when you call getTime()
to read out the resulting date.
Calendar c1 = Calendar.getInstance(); // August 16th, 2012 AD
c1.set(Calendar.YEAR, 0); // August 16th, 0 AD
c1.set(Calendar.DAY_OF_YEAR, 1); // January 1st, 0 AD
Date d1 = c1.getTime(); // January 1st, 1 BC (corrected)
Calendar c2 = Calendar.getInstance();
c2.setTime(d1);
c2.set(Calendar.YEAR, 2001); // January 1st, 2001 BC
c2.set(Calendar.DAY_OF_YEAR, 1);
System.out.println(c2.getTime()); // prints "Wed Jan 01 05:35:00 CET 2001"
// because 01/01/2001 BC was a Wednesday
So instead of setting the year to 2001 you would have to set it to -2000 (because year 0 doesn't exist at all). Or you could explicitly set the era:
c2.set(Calendar.ERA, GregorianCalendar.AD);
Another way to solve this "bug" is by not reading out the time before the complete date is set:
Calendar c1 = Calendar.getInstance(); // August 16th, 2012 AD
c1.set(Calendar.YEAR, 0); // August 16th, 0 AD
c1.set(Calendar.DAY_OF_YEAR, 1); // January 1st, 0 AD
c1.set(Calendar.YEAR, 2001); // January 1st, 2001 AD
System.out.println(c1.getTime()); // prints the expected date
To output the era of a date you can use "G" in the pattern of a SimpleDateFormat
:
new SimpleDateFormat("E MMM dd HH:mm:ss z yyyy G").format(c2.getTime())
// "Wed Jan 01 05:35:00 CET 2001 BC"
In both cases, immediately prior to printing your output, you set the year to 2001. In both cases, the output reflected that year. Were you expecting a different output?