Bug in Calendar when setting time across daylight-saving boundaries?!

Bryce McKinlay mckinlay@redhat.com
Mon Oct 4 22:05:00 GMT 2004


Martin,

I took a quick look at this. On mainline I do not see a problem with 
day-of-month changing, so I guess this has already been fixed - probably 
with Mark Wielaard's recent Calendar improvements.

I did see the problem with the hour-of-day being wrong. The problem here 
is that Calendar.set does not invalidate the DST_OFFSET field even 
though changing other fields could roll the time over a DST boundary. 
Thus, computeTime() applies the DST offset to the resulting Date value 
even if the date is no longer in a DST period.

This patch below should fix the problem. I haven't yet tested this 
extensively. Could you submit a mauve regression test, based on your 
test case?

Thanks

Bryce


2004-10-04  Bryce McKinlay <mckinlay@redhat.com>

        * java/util/Calendar.java (set): Invalidate DST_OFFSET as setting a
        calendar field may roll over a DST boundary.

--- Calendar.java       29 Aug 2004 17:28:09 -0000      1.23
 +++ Calendar.java      4 Oct 2004 22:02:42 -0000
@@ -651,6 +651,10 @@
        isSet[HOUR_OF_DAY] = false;
        break;
       }
+   
+    // We may have rolled over a DST boundary.
+    if (field != DST_OFFSET && field != ZONE_OFFSET)
+      isSet[DST_OFFSET] = false;
   }
 
   /**


Martin Egholm Nielsen wrote:

> Hi there,
>
> I was just about to tear my hear out, when I suddenly discovered that 
> gcj's Calendar had some problems returning a correct Date-instance 
> [getTime()] when you have changed the date of a Calendar-instance 
> across the boundary of daylight-savings.
> I little complicated in short terms, but consider todays date where I 
> live - it's October the 2nd. Hence, we are using daylight-savings. If 
> I then fetch a Calendar instance and change the month to November, the 
> same day of month, and the same hour of day, I have passed the date of 
> daylight savings, but then it goes wrong.
> The calendar instance representing the future date calculates the 
> Date-instance wrong if I invoke #getTime(). The hour of day is an hour 
> short, but the day of month has suddenly gained a day - weird. 
> Consider the following output from an example-application compiled 
> with gcj illustrating the bug:
>
> ======== OUTPUT FROM GCJ ========
> Calendar's date before: Sat Oct 02 10:30:52 GMT+02:00 2004
> Calendar's date after:  Wed Nov 03 09:30:52 GMT+01:00 2004
>
> Calendar reports hour-of-day before: 10
> Calendar reports hour-of-day after:  10
> Calendar's date reports hour-of-day before: 10
> Calendar's date reports hour-of-day after:  9
>
> Calendar reports day-of-month before: 2
> Calendar reports day-of-month after:  2
> Calendar's date reports day-of-month before: 2
> Calendar's date reports day-of-month after:  3
>
>
> Sun's Java returns the expected:
>
> ======== OUTPUT FROM SUN ========
> Calendar's date before: Sat Oct 02 10:11:28 GMT+02:00 2004
> Calendar's date after:  Tue Nov 02 10:11:28 GMT+01:00 2004
>
> Calendar reports hour-of-day before: 10
> Calendar reports hour-of-day after:  10
> Calendar's date reports hour-of-day before: 10
> Calendar's date reports hour-of-day after:  10
>
> Calendar reports day-of-month before: 2
> Calendar reports day-of-month after:  2
> Calendar's date reports day-of-month before: 2
> Calendar's date reports day-of-month after:  2
>
>
> I have attached the example application.
> Does anybody know if this bug has been corrected in recent libgcj's?
> I've seen it with both gcj 3.3.3 and 3.4.0.
>
> Best regards,
>  Martin Egholm
>
>------------------------------------------------------------------------
>
>import java.util.Calendar;
>import java.util.Date;
>import java.util.SimpleTimeZone;
>import java.util.TimeZone;
>
>public class CalendarTest {
>//	private Class c = gnu.java.locale.Calendar.class;
>
>	public static void main(String[] args) {
>		// Create a timezone with daylight savings enabled from the last sunday
>		// of march, and until the last sunday of october:
>		SimpleTimeZone stz = new SimpleTimeZone(60 * 60 * 1000, "MyZone",
>				Calendar.MARCH, -1, Calendar.SUNDAY, 2 * 60 * 60 * 1000,
>				Calendar.OCTOBER, -1, Calendar.SUNDAY, 2 * 60 * 60 * 1000);
>
>		// Register the timezone as the default:
>		TimeZone.setDefault(stz);
>
>		Calendar cal = Calendar.getInstance();
>		Date calendarsDateBefore = cal.getTime();
>		System.out.println("Calendar's date before: " + calendarsDateBefore );
>
>		// Let's store the hour-of-day and day of month for later:
>		int hourOfDayBefore = cal.get(Calendar.HOUR_OF_DAY);
>		int dayOfMonthBefore = cal.get(Calendar.DAY_OF_MONTH);
>
>		int changeMonthTo;
>
>		// Let's test if our current date is in the dst-area:
>		if (stz.inDaylightTime(cal.getTime())) {
>			changeMonthTo = Calendar.NOVEMBER;
>		} // if
>		else {
>			changeMonthTo = Calendar.APRIL;
>		} // else
>
>		// Set the month to a month with different dst-settings that the one
>		// we're in now:
>		cal.set(Calendar.MONTH, changeMonthTo);
>
>		// Specifically set the hour of day and day of month to the same as
>		// before:
>		cal.set(Calendar.HOUR_OF_DAY, hourOfDayBefore);
>		cal.set(Calendar.DAY_OF_MONTH, dayOfMonthBefore);
>
>		Date calendarsDateAfter = cal.getTime();
>		System.out.println("Calendar's date after:  " + calendarsDateAfter );
>
>		int hourOfDayAfter = cal.get(Calendar.HOUR_OF_DAY);
>		int dayOfMonthAfter = cal.get(Calendar.DAY_OF_MONTH);
>		
>		System.out.println();
>		System.out.println("Calendar reports hour-of-day before: "
>				+ hourOfDayBefore);
>		System.out.println("Calendar reports hour-of-day after:  "
>				+ hourOfDayAfter);
>		System.out.println("Calendar's date reports hour-of-day before: "
>				+ calendarsDateBefore.getHours());
>		System.out.println("Calendar's date reports hour-of-day after:  "
>				+ calendarsDateAfter.getHours());
>
>		System.out.println();
>
>		System.out.println("Calendar reports day-of-month before: "
>				+ dayOfMonthBefore);
>		System.out.println("Calendar reports day-of-month after:  "
>				+ dayOfMonthAfter);
>		System.out.println("Calendar's date reports day-of-month before: "
>				+ calendarsDateBefore.getDate());
>		System.out.println("Calendar's date reports day-of-month after:  "
>				+ calendarsDateAfter.getDate());
>	} // main
>} // CalendarTest
>  
>



More information about the Java mailing list