Monday, May 31, 2010

java.util.Calendar and last, not exactly, day of month


Consider the following code :

Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.YEAR, 2009);
calendar.set(Calendar.MONTH, Calendar.FEBRUARY);
calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMaximum(Calendar.DAY_OF_MONTH));
return calendar.getTime();

What's strange or wrong with this? This code looks correct at first look and expected
result should be 28 Feb 2009. Unfortunately it's not always so!!

Suppose to run the above code on 31-May-2009 at 12:00 AM, the result will be 3 Mar 2009!

The reason have to be found on lenient Calendar mechanism. This Calendar property, infact, by default is set to true and doesn't throw any kind of Exception when time interpretation is not correct.

This is javadoc about it:


When a Calendar is lenient, it accepts a wider range of field values than it produces. For example, a lenient GregorianCalendar interprets MONTH == JANUARY, DAY_OF_MONTH == 32 as February 1. A non-lenient GregorianCalendar throws an exception when given out-of-range field settings. When calendars recompute field values for return by get(), they normalize them. For example, a GregorianCalendar always produces DAY_OF_MONTH values between 1 and the length of the month.
It means that,in our case, if we really want to get the last day of month, we have to
write this simple code:


Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.YEAR, 2009);
calendar.set(Calendar.MONTH, Calendar.FEBRUARY);
calendar.set(Calendar.DAY_OF_MONTH, 1);
calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMaximum(Calendar.DAY_OF_MONTH));
return calendar.getTime();

and however, it's not a so bad idea, sometimes, to set lenient property to false and getting an IllegalArgumentsException, always better then abnormal runtime behavior.

Hope it can be helpful.