<i18n dev> Calendar.set(Calendar.DAY_OF_WEEK, ...) changes times as well

Lothar Kimmeringer job at kimmeringer.de
Tue Mar 12 14:20:42 UTC 2024


Hello,

this might be Dunning Kruger at play (at least my Imposter Syndrom
tells me it is ;-) but I think I've found a bug in Calendar, when
working with a different timezonethan the default one.

Attached you can find my test case that is showing the effect but
it breaks down to the following:

         Calendar cal = Calendar.getInstance();
         cal.setTimeInMillis(1709269200000L); // March 01 2024 06:00:00 CET
         cal.setTimeZone(TimeZone.getTimeZone(TIMEZONE));
         assertEquals("Fri Mar 01 06:00:00 CET 2024", cal.getTime().toString(), "check date before change");
         cal.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
         assertEquals("Mon Feb 26 06:00:00 CET 2024", cal.getTime().toString(), "check date after change");

If TIMEZONE is the system's default, the test goes through, if it differs,
the offset time is added to the resulting date after setting the day of
the week. With Europe/Berlin (+0100 at that date) as default and
America/New_York (-0500 at that date) as the timezone being set to the
Calendar, the result is Mon Feb 26 12:00:00 CET 2024 (previous time plus
+1 minus -5).

The workaround for this is using Calendar.add instead of set:

         cal.add(Calendar.DAY_OF_YEAR, -(cal.get(Calendar.DAY_OF_WEEK) - Calendar.MONDAY));

sets the day to monday without changes to the time.

Tested with

  - Java 8.0.312_win_x64
  - Java 11.0.20.1_win_x64
  - Java 17.0.7_win_x64
  - Java 21.0.0_win_x64


Thanks and best regards,

Lothar Kimmeringer
-------------- next part --------------
import static org.junit.jupiter.api.Assertions.*;

import java.util.Calendar;
import java.util.Locale;
import java.util.TimeZone;

import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

class __Test_CalendarSetWeekday {
    
    private Locale defaultLocale;
    private TimeZone defaultTimeZone;

    @BeforeEach
    public void setup() {
        defaultLocale = Locale.getDefault();
        defaultTimeZone = TimeZone.getDefault();
        TimeZone.setDefault(TimeZone.getTimeZone("Europe/Berlin"));
    }
    
    @AfterEach
    public void tearDown() {
        Locale.setDefault(defaultLocale);
        TimeZone.setDefault(defaultTimeZone);
    }
    
    @Test
    void testCalAddingBerlinVsNewYork() {
        Calendar cal = Calendar.getInstance();
        cal.setTimeInMillis(1709269200000L); // March 01 2024
        cal.setTimeZone(TimeZone.getTimeZone("America/New_York"));
        assertEquals("Fri Mar 01 06:00:00 CET 2024", cal.getTime().toString(), "check date before change");
        cal.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
        assertEquals("Mon Feb 26 06:00:00 CET 2024", cal.getTime().toString(), "check date after change");
    }
    
    @Test
    void testCalAddingBerlinVsBerlin() {
        Calendar cal = Calendar.getInstance();
        cal.setTimeInMillis(1709269200000L); // March 01 2024 06:00:00 CET
        cal.setTimeZone(TimeZone.getTimeZone("Europe/Berlin"));
        assertEquals("Fri Mar 01 06:00:00 CET 2024", cal.getTime().toString(), "check date before change");
        cal.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
        assertEquals("Mon Feb 26 06:00:00 CET 2024", cal.getTime().toString(), "check date after change");
    }
    
    
}


More information about the i18n-dev mailing list