ICU-11353 Backported the fix for #8753 to eclipse34 maintenance branch with tzdata and test updates.

X-SVN-Rev: 36698
diff --git a/src/com/ibm/icu/dev/test/calendar/CompatibilityTest.java b/src/com/ibm/icu/dev/test/calendar/CompatibilityTest.java
index bfa1447..004efd1 100644
--- a/src/com/ibm/icu/dev/test/calendar/CompatibilityTest.java
+++ b/src/com/ibm/icu/dev/test/calendar/CompatibilityTest.java
@@ -1,6 +1,6 @@
 /**
  *******************************************************************************
- * Copyright (C) 2000-2005, International Business Machines Corporation and    *
+ * Copyright (C) 2000-2014, International Business Machines Corporation and    *
  * others. All Rights Reserved.                                                *
  *******************************************************************************
  */
@@ -744,6 +744,57 @@
                    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 (int i = 0; i < transitionItems.length; i++) {
+            TransitionItem transitionItem = transitionItems[i];
+            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 {
diff --git a/src/com/ibm/icu/dev/test/format/DateFormatTest.java b/src/com/ibm/icu/dev/test/format/DateFormatTest.java
index 22a44c4..4f7a824 100644
--- a/src/com/ibm/icu/dev/test/format/DateFormatTest.java
+++ b/src/com/ibm/icu/dev/test/format/DateFormatTest.java
@@ -1,7 +1,7 @@
 //##header J2SE15
 /*
  *******************************************************************************
- * Copyright (C) 2001-2008, International Business Machines Corporation and    *
+ * Copyright (C) 2001-2014, International Business Machines Corporation and    *
  * others. All Rights Reserved.                                                *
  *******************************************************************************
  */
@@ -1671,11 +1671,11 @@
         DateFormat fmt = DateFormat.getDateInstance(DateFormat.SHORT, Locale.US);
         Calendar cal = Calendar.getInstance();
         cal.clear();
-        cal.set(117 + 1900, Calendar.JUNE, 5);
-        parse2DigitYear(fmt, "6/5/17", cal.getTime());
+        cal.set(130 + 1900, Calendar.JUNE, 5);
+        parse2DigitYear(fmt, "6/5/30", cal.getTime());
         cal.clear();
-        cal.set(34 + 1900, Calendar.JUNE, 4);
-        parse2DigitYear(fmt, "6/4/34", cal.getTime());
+        cal.set(50 + 1900, Calendar.JUNE, 4);
+        parse2DigitYear(fmt, "6/4/50", cal.getTime());
     }
     
     // internal test subroutine, used by TestTwoDigitYear
diff --git a/src/com/ibm/icu/dev/test/format/TimeZoneFormatTest.java b/src/com/ibm/icu/dev/test/format/TimeZoneFormatTest.java
index d906ae7..ac8d501 100644
--- a/src/com/ibm/icu/dev/test/format/TimeZoneFormatTest.java
+++ b/src/com/ibm/icu/dev/test/format/TimeZoneFormatTest.java
@@ -1,6 +1,6 @@
 /*
  *******************************************************************************
- * Copyright (C) 2007-2012, Google, IBM and  *
+ * Copyright (C) 2007-2014, Google, IBM and  *
  * others. All Rights Reserved. *
  *******************************************************************************
  */
@@ -255,6 +255,14 @@
                         // Skip aliases
                         continue;
                     }
+
+                    if(ids[zidx].equals("Asia/Chita") || ids[zidx].equals("Asia/Srednekolymsk")) {
+                        // These zones were added after ICU 3.8 and works fine with later
+                        // versions of ICU
+                        logln("INFO: Skipping " + ids[zidx] + " for now");
+                        continue;
+                    }
+
                     BasicTimeZone tz = (BasicTimeZone)TimeZone.getTimeZone(ids[zidx], 0);
                     sdf.setTimeZone(tz);
 
diff --git a/src/com/ibm/icu/dev/test/timezone/TimeZoneRuleTest.java b/src/com/ibm/icu/dev/test/timezone/TimeZoneRuleTest.java
index 32999b1..d70b0ca 100644
--- a/src/com/ibm/icu/dev/test/timezone/TimeZoneRuleTest.java
+++ b/src/com/ibm/icu/dev/test/timezone/TimeZoneRuleTest.java
@@ -1,6 +1,6 @@
 /*
  *******************************************************************************
- * Copyright (C) 2007-2012, International Business Machines Corporation and    *
+ * Copyright (C) 2007-2014, International Business Machines Corporation and    *
  * others. All Rights Reserved.                                                *
  *******************************************************************************
  */
@@ -436,6 +436,12 @@
 
         String[] tzids = getTestZIDs();
         for (int i = 0; i < tzids.length; i++) {
+
+            if (tzids[i].equals("Africa/Cairo")) {
+                logln("INFO: Skipping Africa/Cairo - this is a known issue resolved by #7008 in later versions");
+                continue;
+            }
+
             BasicTimeZone olsontz = (BasicTimeZone)TimeZone.getTimeZone(tzids[i], 0);
             VTimeZone vtz_org = VTimeZone.create(tzids[i]);
             vtz_org.setTZURL("http://source.icu-project.org/timezone");
@@ -510,6 +516,12 @@
         for (int n = 0; n < startTimes.length; n++) {
             long startTime = startTimes[n];
             for (int i = 0; i < tzids.length; i++) {
+
+                if (tzids[i].equals("Africa/Cairo")) {
+                    logln("INFO: Skipping Africa/Cairo - this is a known issue resolved by #7008 in later versions");
+                    continue;
+                }
+
                 BasicTimeZone olsontz = (BasicTimeZone)TimeZone.getTimeZone(tzids[i], 0);
                 VTimeZone vtz_org = VTimeZone.create(tzids[i]);
                 VTimeZone vtz_new = null;
diff --git a/src/com/ibm/icu/impl/data/icudata.jar b/src/com/ibm/icu/impl/data/icudata.jar
index 86d8c57..2c2c00c 100755
--- a/src/com/ibm/icu/impl/data/icudata.jar
+++ b/src/com/ibm/icu/impl/data/icudata.jar
@@ -1,3 +1,3 @@
 version https://git-lfs.github.com/spec/v1
-oid sha256:d580ce04b0d0fceafce80c6cd40e6f2d8ece3f1e0570b6c218f74b234f91d3a0
-size 5456288
+oid sha256:724a49242905d57b9f63de1e78f27f5e70a0b52c85e95028009ba9b0d0aec81c
+size 5464757
diff --git a/src/com/ibm/icu/util/Calendar.java b/src/com/ibm/icu/util/Calendar.java
index 779b12a..3932f1e 100644
--- a/src/com/ibm/icu/util/Calendar.java
+++ b/src/com/ibm/icu/util/Calendar.java
@@ -1,5 +1,5 @@
 /*
-*   Copyright (C) 1996-2007, International Business Machines
+*   Copyright (C) 1996-2014, International Business Machines
 *   Corporation and others.  All Rights Reserved.
 */
 
@@ -2798,7 +2798,8 @@
 
         // 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,
@@ -2878,30 +2879,30 @@
         }
 
         // In order to keep the hour invariant (for fields where this is
-        // appropriate), record the DST_OFFSET before and after the add()
-        // operation.  If it has changed, then adjust the millis to
-        // compensate.
-        int dst = 0;
+        // appropriate), check the combined DST & ZONE offset before and
+        // after the add() operation. If it changes, then adjust the millis
+        // to compensate.
+        int prevOffset = 0;
         int hour = 0;
         if (keepHourInvariant) {
-            dst = get(DST_OFFSET);
+            prevOffset = get(ZONE_OFFSET) + get(DST_OFFSET);
             hour = internalGet(HOUR_OF_DAY);
         }
 
         setTimeInMillis(getTimeInMillis() + delta);
 
         if (keepHourInvariant) {
-            dst -= get(DST_OFFSET);
-            if (dst != 0) {
+            int newOffset = get(ZONE_OFFSET) + get(DST_OFFSET);
+            if (newOffset != prevOffset) {
                 // We have done an hour-invariant adjustment but the
-                // DST offset has altered.  We adjust millis to keep
+                // combined offset has changed. We adjust millis to keep
                 // the hour constant.  In cases such as midnight after
                 // a DST change which occurs at midnight, there is the
                 // danger of adjusting into a different day.  To avoid
                 // this we make the adjustment only if it actually
                 // maintains the hour.
                 long t = time;
-                setTimeInMillis(time + dst);
+                setTimeInMillis(time + prevOffset - newOffset);
                 if (get(HOUR_OF_DAY) != hour) {
                     setTimeInMillis(t);
                 }