The problem is that calling set() or roll() to zero for the seconds and minutes fields of the Calendar contains an apparently invalid Daylight Saving Time calculation. The end result is that our program waits an hour instead of a minute during the DST-to-standard time transition.
Our objective is once a minute to determine what is the next "whole minute", e.g. in a scheduler. We use java.util.Calendar to do this. The algorithm is:
1. Return from wait().
2. Perform some tasks.
3. Get the current time in milliseconds in a Calendar instance.
4. Set the millisecond and second fields to zero in order to determine the current "whole" minute.
5. Add a minute to the Calendar.
6. Determine the UTC of the next "whole" minute from the Calendar.
7. Wait until that time, i.e. repeat.
I've also noticed that calling add() with a negative number of seconds and milliseconds is a reasonable workaround. The bug is isolated to set() and roll().
I've attached a small program to illustrate this. The same problem occurs regardless of JRE version. Run the following with 1.5.0_06 (updated timezone files with the Australia transition on 4/2/2006 at 3am local time):
[sh] TZ=Australia/NSW java addminute "04/02/2006 01:58" 4
Output is as follows:
calendar initialized to 04/02/2006 01:58:00.010 (+1100)
after zeroing seconds and millis: 04/02/2006 01:58:00.000 (+1100)
after adding a minute: 04/02/2006 01:59:00.000 (+1100)
currentTime=1143903480010, nextWholeMinuteUTC=1143903540000, diff=59990
calendar initialized to 04/02/2006 01:59:00.010 (+1100)
after zeroing seconds and millis: 04/02/2006 01:59:00.000 (+1100) << here, zeroing the seconds and millis works...timezone offset correct
after adding a minute: 04/02/2006 02:00:00.000 (+1100)
currentTime=1143903540010, nextWholeMinuteUTC=1143903600000, diff=59990
calendar initialized to 04/02/2006 02:00:00.010 (+1100)
after zeroing seconds and millis: 04/02/2006 02:00:00.000 (+1000) << at 2am, zeroing the seconds and millis FAILS...timezone offset incorrect
after adding a minute: 04/02/2006 02:01:00.000 (+1000)
currentTime=1143903600010, nextWholeMinuteUTC=1143907260000, diff=3659990 << time difference after adding 1 minute is 1 hour!
warning, time diff millis > 60000
calendar initialized to 04/02/2006 02:01:00.010 (+1100)
after zeroing seconds and millis: 04/02/2006 02:01:00.000 (+1000)
after adding a minute: 04/02/2006 02:02:00.000 (+1000)
currentTime=1143903660010, nextWholeMinuteUTC=1143907320000, diff=3659990
warning, time diff millis > 60000