Project: SWT
Bug 245783 [swt] DateTime gets confused on Aug 31st 2008
Reported: 2008-08-31 05:14:44 | Status: resolved fixed

SWT version: 3.3 and 3.4 Steps To Reproduce: Set the system date to 31st aug 2008, run the following test, then set the date time to any other date and run the test, the test fails on 31st august, and passes on any other day. This happens because DateTime internally uses java.util.Calendar, which has this in it's documentation: <quote> set(f, value) changes calendar field f to value. In addition, it sets an internal member variable to indicate that calendar field f has been changed. Although calendar field f is changed immediately, the calendar's time value in milliseconds is not recomputed until the next call to get(), getTime(), getTimeInMillis(), add(), or roll() is made. Thus, multiple calls to set() do not trigger multiple, unnecessary computations. As a result of changing a calendar field using set(), other calendar fields may also change, depending on the calendar field, the calendar field value, and the calendar system. In addition, get(f) will not necessarily return value set by the call to the set method after the calendar fields have been recomputed. The specifics are determined by the concrete calendar class. Example: Consider a GregorianCalendar originally set to August 31, 1999. Calling set(Calendar.MONTH, Calendar.SEPTEMBER) sets the date to September 31, 1999. This is a temporary internal representation that resolves to October 1, 1999 if getTime()is then called. However, a call to set(Calendar.DAY_OF_MONTH, 30) before the call to getTime() sets the date to September 30, 1999, since no recomputation occurs after set() itself. </quote> The resolution seems to be to call DateTime#setDay() before DateTime#setMonth(), and swapping the two lines in code seems to be a workaround to the issue. Would it make sense for DateTime#setMonth() to be implemented as follows: --- begin fix (macosx) --- public void setMonth (int month) { checkWidget (); if (!isValid(Calendar.MONTH, month)) return; if ((style & SWT.CALENDAR) != 0) { calendar.set(Calendar.DAY, calendar.get(Calendar.DAY_OF_MONTH)); // additional line. calendar.set(Calendar.MONTH, month); } else { dateRec.month = (short)(month + 1); OS.SetControlData (handle, (short)OS.kControlEntireControl, OS.kControlClockLongDateTag, LongDateRec.sizeof, dateRec); OS.GetControlData (handle, (short)OS.kControlEntireControl, OS.kControlClockLongDateTag, LongDateRec.sizeof, dateRec, null); } redraw(); } --- end fix (macosx) --- --- begin test --- public class DateTimeTest extends TestCase { private DateTime dateTime; protected void setUp() throws Exception { Display display = new Display(); Shell shell = new Shell(display); shell.setLayout(new GridLayout(1, false)); dateTime = new DateTime(shell, SWT.DATE | SWT.LONG); dateTime.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); } public void testDateTime() throws Exception { assertAugust31Year2008(); int NOV = 10; dateTime.setYear(2012); dateTime.setMonth(NOV); // Nov is 10 dateTime.setDay(20); // interchange with above to fix test. dateTime.setHours(0); dateTime.setMinutes(0); dateTime.setSeconds(0); assertEquals(NOV, dateTime.getMonth()); } private void assertAugust31Year2008() { Date today = new Date(); assertEquals(07, today.getMonth()); assertEquals(2008 - 1900, today.getYear()); assertEquals(31, today.getDate()); } } --- end test --- More information:

Files changed in fix:
bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/DateTime.java