Problem with Calendar in Java 5.

Hi folks !!

We are moving to Java 5 (too late... I know...) and I found and interesting

issue about Calendar.

Consider the problem of having a date allways in 00h00 time.

One possible solution is what we have in our code:

import java.util.Calendar;

publicclass CalendarTest{

publicstaticvoid main(String[] args){

Calendar cal = Calendar.getInstance();

cal.set(Calendar.DAY_OF_MONTH, 1);

cal.set(Calendar.MONTH, 2);

cal.set(Calendar.YEAR, 2007);

cal.clear(Calendar.HOUR);

cal.clear(Calendar.HOUR_OF_DAY);

cal.clear(Calendar.MINUTE);

cal.clear(Calendar.SECOND);

cal.clear(Calendar.MILLISECOND);

System.out.println(cal.getTime());

System.out.println(cal.getTimeInMillis());

}

}

Compiling and running it with Java 1.4 we'll see the following output (I live in brazil, GMT-3 timezone):

Thu Mar 01 00:00:00 GMT-03:00 2007

1172718000000

But if you compile and run it with Java 1.5 you'll see:

Thu Mar 01 12:00:00 GMT-03:00 2007

1172761200000

The hour wasn't cleared !!

The most interesting is that it happens after noon. If I run it before noon the both outputs are the same.

Now let's see what Java 1.5 JavaDoc says about the "clear(int)" method of Calendar:

"Sets the given calendar field value and the time value (millisecond offset from the Epoch)

of this Calendar undefined. (...) The HOUR_OF_DAY, HOUR and AM_PM fields are handled

independently and the the resolution rule for the time of day is applied. Clearing one of

the fields doesn't reset the hour of day value of this Calendar.

Use set(Calendar.HOUR_OF_DAY, 0) to reset the hour value."

The Java 1.4 JavaDoc just says:

"Clears the value in the given time field."

The solution is to follow the 1.5 Javadoc and use "set(int, 0)" ao inv閟 de "clear()":

publicclass CalendarTest{

publicstaticvoid main(String[] args){

Calendar cal = Calendar.getInstance();

cal.set(Calendar.DAY_OF_MONTH, 1);

cal.set(Calendar.MONTH, 2);

cal.set(Calendar.YEAR, 2007);

cal.set(Calendar.HOUR, 0);

cal.set(Calendar.HOUR_OF_DAY, 0);

cal.set(Calendar.MINUTE, 0);

cal.set(Calendar.SECOND, 0);

cal.set(Calendar.MILLISECOND, 0);

System.out.println(cal.getTime());

System.out.println(cal.getTimeInMillis());

}

}

You can use this solution too:

publicclass CalendarTest{

publicstaticvoid main(String[] args){

Calendar cal = Calendar.getInstance();

cal.clear();

cal.set(Calendar.DAY_OF_MONTH, 1);

cal.set(Calendar.MONTH, 2);

cal.set(Calendar.YEAR, 2007);

System.out.println(cal.getTime());

System.out.println(cal.getTimeInMillis());

}

}

But in my opinion the last one doesn't seem to be the best solution due to definition

of "clear()" method that says the fields will be set undefined, after all undefined

is not the same as zero :)

Can you reproduce this bug in your enviroment ? Do you consider this a bug ?

Thanks for your attention.

[4044 byte] By [ivan.aguirre.bra] at [2007-11-27 2:22:13]
# 1

Calendar has numerous quirky bugs. Try to make sure you call setLenient(false) after initializing the Calendar. Then, make sure you call the setter methods that take the maximum number of arguments (e.g., call set(year, month, day) rather than set(year), set(month), set(day), etc.)

- Saish

Saisha at 2007-7-12 2:25:58 > top of Java-index,Java Essentials,Java Programming...
# 2

I think you should simply call cal.clear(Calendar.AM_PM);

after cal.clear(Calendar.HOUR_OF_DAY);

This would explain the "after noon" behaviour (which is obviously different in Java 5, due to major refactorings of the Calendar class).

In general, be careful with the clear methods of the Calendar class. I suggest you always use the set methods, especially the one taking six arguments (year, month, date, hourOfDay, minute, second). This one works always as expected.

floechena at 2007-7-12 2:25:58 > top of Java-index,Java Essentials,Java Programming...