]> granicus.if.org Git - icu/commitdiff
ICU-8753 Fix ICU4J Calendar.add() to handle change in ZONE_OFFSET
authorPeter Edberg <pedberg@unicode.org>
Thu, 15 Sep 2011 04:22:55 +0000 (04:22 +0000)
committerPeter Edberg <pedberg@unicode.org>
Thu, 15 Sep 2011 04:22:55 +0000 (04:22 +0000)
X-SVN-Rev: 30660

icu4j/main/classes/core/src/com/ibm/icu/util/Calendar.java
icu4j/main/tests/core/src/com/ibm/icu/dev/test/calendar/CompatibilityTest.java

index 162db725afc0512d2576376bac0fe4dacf8a53c4..55b170b570660f23e5101d3f2e30712446e7ab1d 100644 (file)
@@ -2995,7 +2995,8 @@ public abstract class Calendar implements Serializable, Cloneable, Comparable<Ca
 
         // We handle most fields in the same way.  The algorithm is to add
         // a computed amount of millis to the current millis.  The only
-        // wrinkle is with DST -- for some fields, like the DAY_OF_MONTH,
+        // wrinkle is with DST (and/or a change to the zone's UTC offset, which
+        // we'll include with DST) -- for some fields, like the DAY_OF_MONTH,
         // we don't want the HOUR to shift due to changes in DST.  If the
         // result of the add operation is to move from DST to Standard, or
         // vice versa, we need to adjust by an hour forward or back,
@@ -3081,14 +3082,14 @@ public abstract class Calendar implements Serializable, Cloneable, Comparable<Ca
         int dst = 0;
         int hour = 0;
         if (keepHourInvariant) {
-            dst = get(DST_OFFSET);
+            dst = get(DST_OFFSET) + get(ZONE_OFFSET);
             hour = internalGet(HOUR_OF_DAY);
         }
 
         setTimeInMillis(getTimeInMillis() + delta);
 
         if (keepHourInvariant) {
-            dst -= get(DST_OFFSET);
+            dst -= get(DST_OFFSET) + get(ZONE_OFFSET);
             if (dst != 0) {
                 // We have done an hour-invariant adjustment but the
                 // DST offset has altered.  We adjust millis to keep
index ce3ae4d98d61ed52d756adf0759f47e8a3eb53f4..41c05dfc6bcc8e7e4da20ddf4fcd6ab2768bd567 100644 (file)
@@ -1,6 +1,6 @@
 /**
  *******************************************************************************
- * Copyright (C) 2000-2009, International Business Machines Corporation and    *
+ * Copyright (C) 2000-2009,2011 International Business Machines Corporation and    *
  * others. All Rights Reserved.                                                *
  *******************************************************************************
  */
@@ -754,6 +754,56 @@ public class CompatibilityTest extends com.ibm.icu.dev.test.TestFmwk {
                    y + "/" + (m+1) + "/" + d);
     }
 
+    // Verify that add works across ZONE_OFFSET and DST_OFFSET transitions
+    public void TestAddAcrossOffsetTransitions() {
+        class TransitionItem {
+            private String zoneName;
+            private int year;
+            private int month;
+            private int day;
+            private int hour;
+            TransitionItem(String zn, int y, int m, int d, int h) {
+                zoneName = zn;
+                year = y;
+                month = m;
+                day = d;
+                hour = h;
+            }
+            public String getZoneName() { return zoneName; }
+            public int getYear() { return year; }
+            public int getMonth() { return month; }
+            public int getDay() { return day; }
+            public int getHour() { return hour; }
+        }
+        final TransitionItem[] transitionItems = { 
+            new TransitionItem( "America/Caracas", 2007, Calendar.DECEMBER,  8, 10 ), // day before change in ZONE_OFFSET
+            new TransitionItem( "US/Pacific",      2011,    Calendar.MARCH, 12, 10 ), // day before change in DST_OFFSET
+        };
+        for (TransitionItem transitionItem: transitionItems) {
+            String zoneName = transitionItem.getZoneName();
+            Calendar cal = null;
+            try {
+                cal = Calendar.getInstance(TimeZone.getTimeZone(zoneName), Locale.ENGLISH);
+            } catch (Exception e) {
+                errln("Error: Calendar.getInstance fails for zone " + zoneName);
+                continue;
+            }
+            int itemHour = transitionItem.getHour();
+            cal.set( transitionItem.getYear(), transitionItem.getMonth(), transitionItem.getDay(), itemHour, 0 );
+            cal.add( Calendar.DATE, 1 );
+            int hr = cal.get( Calendar.HOUR_OF_DAY );
+            if ( hr != itemHour ) {
+                errln("Error: Calendar.add produced wrong hour " + hr + " when adding day across transition for zone " + zoneName);
+            } else {
+                cal.add( Calendar.DATE, -1 );
+                hr = cal.get( Calendar.HOUR_OF_DAY );
+                if ( hr != itemHour ) {
+                    errln("Error: Calendar.add produced wrong hour " + hr + " when subtracting day across transition for zone " + zoneName);
+                }
+            }
+        }
+    }
+
     // Verify that setting fields works.  This test fails when an exception is thrown.
     public void TestFieldSet4781() {
         try {