ICU-9354 Partially backported JDK TimeZone support (#5975) to eclipse-34 stream to reduce the tzdata maintenance work load.

X-SVN-Rev: 31885
diff --git a/.gitattributes b/.gitattributes
index 66848fa..e301184 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -55,6 +55,7 @@
 eclipseProjectMisc/normSrc.launch -text
 /ee.foundation.jar -text
 /preprocessor.txt -text
+src/com/ibm/icu/ICUConfig.properties -text
 src/com/ibm/icu/dev/data/rbbi/english.dict -text
 src/com/ibm/icu/dev/data/testdata.jar -text
 src/com/ibm/icu/dev/data/thai6.ucs -text
diff --git a/build.properties b/build.properties
index d187470..6156152 100644
--- a/build.properties
+++ b/build.properties
@@ -29,4 +29,4 @@
 icu4j.plugin.impl.version.string=3.8.1
 copyright.eclipse=Licensed Materials - Property of IBM \n (C) Copyright IBM Corp. 2000, 2012. All Rights Reserved. \n IBM is a registered trademark of IBM Corp.
 
-icu4j.eclipse.build.version.string=3.8.1.v20120406
\ No newline at end of file
+icu4j.eclipse.build.version.string=3.8.1.v20120530
\ No newline at end of file
diff --git a/build.xml b/build.xml
index 7f3dae5..2fbdc20 100644
--- a/build.xml
+++ b/build.xml
@@ -1,7 +1,7 @@
 <!--
 /*
 *******************************************************************************
-* Copyright (C) 1997-2009, International Business Machines Corporation and    *
+* Copyright (C) 1997-2012, International Business Machines Corporation and    *
 * others. All Rights Reserved.                                                *
 *******************************************************************************
 * This is the ant build file for ICU4J.  See readme.html for more information.
@@ -287,6 +287,7 @@
     <copy todir="${build.dir}/META-INF">
       <fileset dir="${src.dir}/META-INF" includes="**/*" />
     </copy>
+    <copy file="${src.dir}/com/ibm/icu/ICUConfig.properties" todir="${build.dir}/com/ibm/icu"/>
   </target>
 
   <target name="durationdata" depends="initBase">
@@ -1661,6 +1662,7 @@
         <include name="com/ibm/icu/math/**/*" />
         <include name="com/ibm/icu/impl/**/*" />
         <include name="com/ibm/icu/lang/**/*" />
+        <include name="com/ibm/icu/ICUConfig.properties" />
       </fileset>
       <manifest>
         <attribute name="Built-By" value="${corp}" />
@@ -1691,7 +1693,7 @@
     <!-- icu source -->
     <copy toDir="${eclipse.projects.dir}/plugins/com.ibm.icu/src/com/ibm/icu">
       <fileset dir="src/com/ibm/icu"
-               includes="impl/**/*,lang/**/*,math/**/*,text/**/*,util/**/*"
+               includes="impl/**/*,lang/**/*,math/**/*,text/**/*,util/**/*,ICUConfig.properties"
                excludes="**/.svn/**/*,**/*.jar,**/Transliterator_Han_Latin*.txt" />
     </copy>
     <!-- icu data -->
diff --git a/preprocessor.txt b/preprocessor.txt
index 6118635..882702d 100644
--- a/preprocessor.txt
+++ b/preprocessor.txt
@@ -1,4 +1,4 @@
-# Copyright (C) 2007, International Business Machines Corporation and

+# Copyright (C) 2007-2012, International Business Machines Corporation and

 # others. All Rights Reserved.

 

 ## core sources

@@ -7,6 +7,7 @@
 src/com/ibm/icu/impl/duration/BasicDurationFormat.java

 src/com/ibm/icu/impl/ICUResourceBundleImpl.java

 src/com/ibm/icu/impl/ICUResourceBundleReader.java

+src/com/ibm/icu/impl/JavaTimeZone.java

 src/com/ibm/icu/impl/PatternTokenizer.java

 src/com/ibm/icu/impl/Utility.java

 src/com/ibm/icu/lang/UCharacter.java

diff --git a/src/com/ibm/icu/ICUConfig.properties b/src/com/ibm/icu/ICUConfig.properties
new file mode 100644
index 0000000..46667f9
--- /dev/null
+++ b/src/com/ibm/icu/ICUConfig.properties
@@ -0,0 +1,13 @@
+#*

+#*******************************************************************************

+#* Copyright (C) 2008-2012, International Business Machines Corporation and    *

+#* others. All Rights Reserved.                                                *

+#*******************************************************************************

+#* This is the properties contains ICU runtime configuration 

+#*

+

+#

+# The default TimeZone implementation type used by the ICU TimeZone

+# factory method. [ ICU | JDK ]

+#

+com.ibm.icu.util.TimeZone.DefaultTimeZoneType = JDK

diff --git a/src/com/ibm/icu/dev/test/format/TimeZoneFormatTest.java b/src/com/ibm/icu/dev/test/format/TimeZoneFormatTest.java
index d4fc5c4..d906ae7 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, Google, IBM and  *
+ * Copyright (C) 2007-2012, Google, IBM and  *
  * others. All Rights Reserved. *
  *******************************************************************************
  */
@@ -11,6 +11,7 @@
 import java.text.ParsePosition;
 import java.util.Date;
 
+import com.ibm.icu.impl.ICUConfig;
 import com.ibm.icu.impl.ZoneMeta;
 import com.ibm.icu.lang.UCharacter;
 import com.ibm.icu.text.SimpleDateFormat;
@@ -23,6 +24,13 @@
 
 public class TimeZoneFormatTest extends com.ibm.icu.dev.test.TestFmwk {
 
+    static final boolean isJDKTimeZone;
+
+    static {
+        String type = ICUConfig.get("com.ibm.icu.util.TimeZone.DefaultTimeZoneType", "ICU");
+        isJDKTimeZone = type.equalsIgnoreCase("JDK");        
+    }
+
     public static void main(String[] args) throws Exception {
         new TimeZoneFormatTest().run(args);
     }
@@ -121,30 +129,52 @@
                             int inOffset = inOffsets[0] + inOffsets[1];
                             int outOffset = outOffsets[0] + outOffsets[1];
                             if (inOffset != outOffset) {
-                                errln("Offset round trip failed; tz=" + tzids[tzidx]
-                                    + ", locale=" + LOCALES[locidx] + ", pattern=" + PATTERNS[patidx]
-                                    + ", time=" + DATES[datidx].getTime() + ", str=" + tzstr
-                                    + ", inOffset=" + inOffset + ", outOffset=" + outOffset);
+                                if (isJDKTimeZone) {
+                                    logln("[JDKTZ] Offset round trip failed; tz=" + tzids[tzidx]
+                                            + ", locale=" + LOCALES[locidx] + ", pattern=" + PATTERNS[patidx]
+                                            + ", time=" + DATES[datidx].getTime() + ", str=" + tzstr
+                                            + ", inOffset=" + inOffset + ", outOffset=" + outOffset);                                    
+                                } else {
+                                    errln("Offset round trip failed; tz=" + tzids[tzidx]
+                                            + ", locale=" + LOCALES[locidx] + ", pattern=" + PATTERNS[patidx]
+                                            + ", time=" + DATES[datidx].getTime() + ", str=" + tzstr
+                                            + ", inOffset=" + inOffset + ", outOffset=" + outOffset);
+                                }
                             }
                         } else if (PATTERNS[patidx].equals("z") || PATTERNS[patidx].equals("zzzz")
                                 || PATTERNS[patidx].equals("v") || PATTERNS[patidx].equals("vvvv")
                                 || PATTERNS[patidx].equals("V")) {
                             // Specific or generic: raw offset must be preserved.
                             if (inOffsets[0] != outOffsets[0]) {
-                                errln("Raw offset round trip failed; tz=" + tzids[tzidx]
-                                    + ", locale=" + LOCALES[locidx] + ", pattern=" + PATTERNS[patidx]
-                                    + ", time=" + DATES[datidx].getTime() + ", str=" + tzstr
-                                    + ", inRawOffset=" + inOffsets[0] + ", outRawOffset=" + outOffsets[0]);
+                                if (isJDKTimeZone) {
+                                    logln("[JDKTZ] Raw offset round trip failed; tz=" + tzids[tzidx]
+                                            + ", locale=" + LOCALES[locidx] + ", pattern=" + PATTERNS[patidx]
+                                            + ", time=" + DATES[datidx].getTime() + ", str=" + tzstr
+                                            + ", inRawOffset=" + inOffsets[0] + ", outRawOffset=" + outOffsets[0]);                                    
+                                } else {
+                                    errln("Raw offset round trip failed; tz=" + tzids[tzidx]
+                                            + ", locale=" + LOCALES[locidx] + ", pattern=" + PATTERNS[patidx]
+                                            + ", time=" + DATES[datidx].getTime() + ", str=" + tzstr
+                                            + ", inRawOffset=" + inOffsets[0] + ", outRawOffset=" + outOffsets[0]);
+                                }
                             }
                         } else { // "VVVV"
                             // Location: time zone rule must be preserved.
                             if (!outtz.getID().equals(ZoneMeta.getCanonicalID(tzids[tzidx]))) {
                                 // Canonical ID did not match - check the rules
                                 if (!((BasicTimeZone)outtz).hasEquivalentTransitions(tz, low, high)) {
-                                    errln("Canonical round trip failed; tz=" + tzids[tzidx]
-                                        + ", locale=" + LOCALES[locidx] + ", pattern=" + PATTERNS[patidx]
-                                        + ", time=" + DATES[datidx].getTime() + ", str=" + tzstr
-                                        + ", outtz=" + outtz.getID());
+                                    if (isJDKTimeZone) {
+                                        logln("[JDKTZ] Canonical round trip failed; tz=" + tzids[tzidx]
+                                                + ", locale=" + LOCALES[locidx] + ", pattern=" + PATTERNS[patidx]
+                                                + ", time=" + DATES[datidx].getTime() + ", str=" + tzstr
+                                                + ", outtz=" + outtz.getID());
+                                        
+                                    } else {
+                                        errln("Canonical round trip failed; tz=" + tzids[tzidx]
+                                                + ", locale=" + LOCALES[locidx] + ", pattern=" + PATTERNS[patidx]
+                                                + ", time=" + DATES[datidx].getTime() + ", str=" + tzstr
+                                                + ", outtz=" + outtz.getID());                                        
+                                    }
                                 }
                             }
                         }
@@ -225,7 +255,7 @@
                         // Skip aliases
                         continue;
                     }
-                    BasicTimeZone tz = (BasicTimeZone)TimeZone.getTimeZone(ids[zidx]);
+                    BasicTimeZone tz = (BasicTimeZone)TimeZone.getTimeZone(ids[zidx], 0);
                     sdf.setTimeZone(tz);
 
                     long t = START_TIME;
@@ -279,7 +309,11 @@
                                         .append(", restime=").append(restime)
                                         .append(", diff=").append(restime - testTimes[testidx]);
                                     if (expectedRoundTrip[testidx]) {
-                                        errln("FAIL: " + msg.toString());
+                                        if (isJDKTimeZone) {
+                                            logln("[JDKTZ] " + msg.toString());                                            
+                                        } else {
+                                            errln("FAIL: " + msg.toString());
+                                        }
                                     } else if (REALLY_VERBOSE) {
                                         logln(msg.toString());
                                     }
diff --git a/src/com/ibm/icu/dev/test/serializable/SerializableTest.java b/src/com/ibm/icu/dev/test/serializable/SerializableTest.java
index 4e9b306..4841da5 100644
--- a/src/com/ibm/icu/dev/test/serializable/SerializableTest.java
+++ b/src/com/ibm/icu/dev/test/serializable/SerializableTest.java
@@ -1,7 +1,7 @@
 //##header J2SE15
 /*
  *******************************************************************************
- * Copyright (C) 1996-2007, International Business Machines Corporation and    *
+ * Copyright (C) 1996-2012, International Business Machines Corporation and    *
  * others. All Rights Reserved.                                                *
  *******************************************************************************
  *
@@ -14,6 +14,7 @@
 import java.util.Locale;
 
 import com.ibm.icu.dev.test.TestFmwk;
+import com.ibm.icu.impl.JavaTimeZone;
 import com.ibm.icu.impl.OlsonTimeZone;
 import com.ibm.icu.impl.TimeZoneAdapter;
 import com.ibm.icu.math.BigDecimal;
@@ -579,6 +580,20 @@
         }
     }
 
+    private static class JavaTimeZoneHandler implements Handler {
+        public Object[] getTestObjects() {
+            JavaTimeZone data[] = new JavaTimeZone[1];
+            data[0] = new JavaTimeZone("America/New_York");
+            return data;
+        }
+        public boolean hasSameBehavior(Object a, Object b) {
+            JavaTimeZone jtza = (JavaTimeZone) a;
+            JavaTimeZone jtzb = (JavaTimeZone) b;
+
+            return jtza.equals(jtzb);
+        }
+    }
+
     private static HashMap map = new HashMap();
     
     static {
@@ -637,6 +652,8 @@
 //#endif
         map.put("com.ibm.icu.impl.duration.BasicDurationFormat", new FormatTests.BasicDurationFormatHandler());
         map.put("com.ibm.icu.impl.RelativeDateFormat", new FormatTests.RelativeDateFormatHandler());
+
+        map.put("com.ibm.icu.impl.JavaTimeZone", new JavaTimeZoneHandler());
     }
     
     public SerializableTest()
diff --git a/src/com/ibm/icu/dev/test/timezone/TimeZoneOffsetLocalTest.java b/src/com/ibm/icu/dev/test/timezone/TimeZoneOffsetLocalTest.java
index 6841f20..abe0f92 100644
--- a/src/com/ibm/icu/dev/test/timezone/TimeZoneOffsetLocalTest.java
+++ b/src/com/ibm/icu/dev/test/timezone/TimeZoneOffsetLocalTest.java
@@ -1,6 +1,6 @@
 /*
  *******************************************************************************
- * Copyright (C) 2007, International Business Machines Corporation and         *
+ * Copyright (C) 2007-2012, International Business Machines Corporation and    *
  * others. All Rights Reserved.                                                *
  *******************************************************************************
  */
@@ -113,7 +113,7 @@
         // Set up TimeZone objects - OlsonTimeZone, SimpleTimeZone and RuleBasedTimeZone
         BasicTimeZone[] TESTZONES = new BasicTimeZone[3];
 
-        TESTZONES[0] = (BasicTimeZone)TimeZone.getTimeZone("America/Los_Angeles");
+        TESTZONES[0] = (BasicTimeZone)TimeZone.getTimeZone("America/Los_Angeles", 0);
         TESTZONES[1] = new SimpleTimeZone(-8*HOUR, "Simple Pacific Time",
                                             Calendar.APRIL, 1, Calendar.SUNDAY, 2*HOUR,
                                             Calendar.OCTOBER, -1, Calendar.SUNDAY, 2*HOUR);
diff --git a/src/com/ibm/icu/dev/test/timezone/TimeZoneRuleTest.java b/src/com/ibm/icu/dev/test/timezone/TimeZoneRuleTest.java
index dd0c49c..32999b1 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, International Business Machines Corporation and         *
+ * Copyright (C) 2007-2012, International Business Machines Corporation and    *
  * others. All Rights Reserved.                                                *
  *******************************************************************************
  */
@@ -208,7 +208,7 @@
      */
     public void TestHistoricalRuleBasedTimeZone() {
         // Compare to America/New_York with equivalent RBTZ
-        TimeZone ny = TimeZone.getTimeZone("America/New_York");
+        TimeZone ny = TimeZone.getTimeZone("America/New_York", 0);
 
         //RBTZ
         InitialTimeZoneRule ir = new InitialTimeZoneRule("EST", -5*HOUR, 0);
@@ -321,7 +321,7 @@
     public void TestOlsonTransition() {
         String[] zids = getTestZIDs();
         for (int i = 0; i < zids.length; i++) {
-            TimeZone tz = TimeZone.getTimeZone(zids[i]);
+            TimeZone tz = TimeZone.getTimeZone(zids[i], 0);
             if (tz == null) {
                 break;
             }
@@ -350,7 +350,7 @@
 
         String[] zids = getTestZIDs();
         for (int i = 0; i < zids.length; i++) {
-            TimeZone tz = TimeZone.getTimeZone(zids[i]);
+            TimeZone tz = TimeZone.getTimeZone(zids[i], 0);
             if (tz == null) {
                 break;
             }
@@ -385,9 +385,9 @@
     public void TestHasEquivalentTransitions() {
         // America/New_York and America/Indiana/Indianapolis are equivalent
         // since 2006
-        TimeZone newyork = TimeZone.getTimeZone("America/New_York");
-        TimeZone indianapolis = TimeZone.getTimeZone("America/Indiana/Indianapolis");
-        TimeZone gmt_5 = TimeZone.getTimeZone("Etc/GMT+5");
+        TimeZone newyork = TimeZone.getTimeZone("America/New_York", 0);
+        TimeZone indianapolis = TimeZone.getTimeZone("America/Indiana/Indianapolis", 0);
+        TimeZone gmt_5 = TimeZone.getTimeZone("Etc/GMT+5", 0);
 
         long jan1_1971 = getUTCMillis(1971, Calendar.JANUARY, 1);
         long jan1_2005 = getUTCMillis(2005, Calendar.JANUARY, 1);
@@ -436,7 +436,7 @@
 
         String[] tzids = getTestZIDs();
         for (int i = 0; i < tzids.length; i++) {
-            BasicTimeZone olsontz = (BasicTimeZone)TimeZone.getTimeZone(tzids[i]);
+            BasicTimeZone olsontz = (BasicTimeZone)TimeZone.getTimeZone(tzids[i], 0);
             VTimeZone vtz_org = VTimeZone.create(tzids[i]);
             vtz_org.setTZURL("http://source.icu-project.org/timezone");
             vtz_org.setLastModified(new Date());
@@ -510,7 +510,7 @@
         for (int n = 0; n < startTimes.length; n++) {
             long startTime = startTimes[n];
             for (int i = 0; i < tzids.length; i++) {
-                BasicTimeZone olsontz = (BasicTimeZone)TimeZone.getTimeZone(tzids[i]);
+                BasicTimeZone olsontz = (BasicTimeZone)TimeZone.getTimeZone(tzids[i], 0);
                 VTimeZone vtz_org = VTimeZone.create(tzids[i]);
                 VTimeZone vtz_new = null;
                 try {
@@ -690,7 +690,7 @@
         for (int n = 0; n < testTimes.length; n++) {
             long time = testTimes[n];
             for (int i = 0; i < tzids.length; i++) {
-                BasicTimeZone tz = (BasicTimeZone)TimeZone.getTimeZone(tzids[i]);
+                BasicTimeZone tz = (BasicTimeZone)TimeZone.getTimeZone(tzids[i], 0);
                 TimeZoneRule[] rules = tz.getSimpleTimeZoneRulesNear(time);
                 if (rules == null) {
                     errln("FAIL: Failed to extract simple rules for " + tzids[i] + " at " + time);
@@ -1107,7 +1107,7 @@
      */
     public void TestVTimeZoneCoverage() {
         final String TZID = "Europe/Moscow";
-        BasicTimeZone otz = (BasicTimeZone)TimeZone.getTimeZone(TZID);
+        BasicTimeZone otz = (BasicTimeZone)TimeZone.getTimeZone(TZID, 0);
         VTimeZone vtz = VTimeZone.create(TZID);
 
         // getOffset(era, year, month, day, dayOfWeek, milliseconds)
diff --git a/src/com/ibm/icu/dev/test/timezone/TimeZoneTest.java b/src/com/ibm/icu/dev/test/timezone/TimeZoneTest.java
index 9710ca7..7078d37 100644
--- a/src/com/ibm/icu/dev/test/timezone/TimeZoneTest.java
+++ b/src/com/ibm/icu/dev/test/timezone/TimeZoneTest.java
@@ -1,6 +1,6 @@
 /**
  *******************************************************************************
- * Copyright (C) 2000-2010, International Business Machines Corporation and    *
+ * Copyright (C) 2000-2012, International Business Machines Corporation and    *
  * others. All Rights Reserved.                                                *
  *******************************************************************************
  */
@@ -15,11 +15,11 @@
 import java.lang.reflect.InvocationTargetException;
 import java.util.Arrays;
 import java.util.Date;
-import java.util.Hashtable;
 import java.util.List;
 import java.util.Locale;
 
 import com.ibm.icu.dev.test.TestFmwk;
+import com.ibm.icu.impl.ICUConfig;
 import com.ibm.icu.impl.ICUResourceBundle;
 import com.ibm.icu.impl.OlsonTimeZone;
 import com.ibm.icu.text.SimpleDateFormat;
@@ -40,6 +40,21 @@
 {
     static final int millisPerHour = 3600000;
 
+    // TODO: We should probably read following data at runtime, so we can update
+    // the these values every release with necessary data changes.
+
+    // Some test case data is current date/tzdata version sensitive and producing errors
+    // when year/rule are changed.
+    static final int REFERENCE_YEAR = 2012;
+    static final String REFERENCE_DATA_VERSION = "2012c";
+
+    static final boolean isJDKTimeZone;
+
+    static {
+        String type = ICUConfig.get("com.ibm.icu.util.TimeZone.DefaultTimeZoneType", "ICU");
+        isJDKTimeZone = type.equalsIgnoreCase("JDK");        
+    }
+    
     public static void main(String[] args) throws Exception {
         new TimeZoneTest().run(args);
     }
@@ -106,75 +121,100 @@
      */
     public void TestShortZoneIDs() throws Exception {
 
-        ZoneDescriptor[] JDK_116_REFERENCE_LIST = {
-            new ZoneDescriptor("MIT", -660, true), // updated to false when merging 2010j
-            new ZoneDescriptor("HST", -600, false),
-            new ZoneDescriptor("AST", -540, true),
-            new ZoneDescriptor("PST", -480, true),
-            new ZoneDescriptor("PNT", -420, false),
-            new ZoneDescriptor("MST", -420, false),// updated Aug 2003 aliu
-            new ZoneDescriptor("CST", -360, true),
-            new ZoneDescriptor("IET", -300, true), // updated Feb 2006 srl
-            new ZoneDescriptor("EST", -300, false),// updated Aug 2003 aliu
-            new ZoneDescriptor("PRT", -240, false),
-            new ZoneDescriptor("CNT", -210, true),
-            new ZoneDescriptor("AGT", -180, false), // updated Oct 2009 yoshito
-            new ZoneDescriptor("BET", -180, true),
-            // new ZoneDescriptor("CAT", -60, false), // Wrong:
-            // As of bug 4130885, fix CAT (Central Africa)
-            new ZoneDescriptor("CAT", 120, false), // Africa/Harare
-            new ZoneDescriptor("GMT", 0, false),
-            new ZoneDescriptor("UTC", 0, false),
-            new ZoneDescriptor("ECT", 60, true),
-            new ZoneDescriptor("ART", 120, true),
-            new ZoneDescriptor("EET", 120, true),
-            new ZoneDescriptor("EAT", 180, false),
-            // new ZoneDescriptor("MET", 210, true),
-            // This is a standard Unix zone, so don't remap it - Liu 3Jan01
-            // new ZoneDescriptor("NET", 240, false);
-            // As of bug 4191164, fix NET
-            new ZoneDescriptor("NET", 240, true),
-            // PLT behaves differently under different JDKs, so we don't check it
-            // new ZoneDescriptor("PLT", 300, false), // updated Oct 2003 aliu
-            new ZoneDescriptor("IST", 330, false),
-            new ZoneDescriptor("BST", 360, false), // updated May 2010 - no DST in year 2010+
-            new ZoneDescriptor("VST", 420, false),
-            new ZoneDescriptor("CTT", 480, false), // updated Oct 2003 aliu
-            new ZoneDescriptor("JST", 540, false),
-            new ZoneDescriptor("ACT", 570, false), // updated Oct 2003 aliu
-            new ZoneDescriptor("AET", 600, true),
-            new ZoneDescriptor("SST", 660, false),
-            // new ZoneDescriptor("NST", 720, false),
-            // As of bug 4130885, fix NST (New Zealand)
-            new ZoneDescriptor("NST", 720, true), // Pacific/Auckland
-
-            // [3Jan01 Liu] Three of these zones have been updated.
-            // The CTT and ACT zones just remap to Asia/Shanghai
-            // and Australia/Darwin.  Since those zones have changed,
-            // I have updated the table.  The MET zone used to be mapped
-            // to Asia/Tehran but since MET is a standard Unix zone named
-            // in the source data we no longer do this in icu or icu4j.
-        };
-
-        Hashtable hash = new Hashtable();
-
-        String[] ids = TimeZone.getAvailableIDs();
-        for (int i=0; i<ids.length; ++i) {
-            String id = ids[i];
-            if (id.length() == 3) {
-                hash.put(id, new ZoneDescriptor(TimeZone.getTimeZone(id)));
-            }
+        // This test case is tzdata version sensitive.
+        boolean isNonReferenceTzdataVersion = false;
+        String tzdataVer = TimeZone.getTZDataVersion();
+        if (!tzdataVer.equals(REFERENCE_DATA_VERSION)) {
+            // Note: We want to display a warning message here if
+            // REFERENCE_DATA_VERSION is out of date - so we
+            // do not forget to update the value before GA.
+            isNonReferenceTzdataVersion = true;
+            logln("Warning: Active tzdata version (" + tzdataVer +
+                    ") does not match the reference tzdata version ("
+                    + REFERENCE_DATA_VERSION + ") for this test case data.");
         }
 
-        for (int i=0; i<JDK_116_REFERENCE_LIST.length; ++i) {
-            ZoneDescriptor referenceZone = JDK_116_REFERENCE_LIST[i];
-            ZoneDescriptor currentZone = (ZoneDescriptor)hash.get(referenceZone.getID());
+        if (isJDKTimeZone) {
+            logln("Warning: Using JDK TimeZone.  Some test cases may not return expected results.");
+        }
+
+        // Note: useDaylightTime returns true if DST is observed
+        // in the time zone in the current calendar year.  The test
+        // data is valid for the date after the reference year below.
+        // If system clock is before the year, some test cases may
+        // fail.
+        GregorianCalendar cal = new GregorianCalendar(TimeZone.getTimeZone("Etc/GMT"));
+        cal.set(REFERENCE_YEAR, Calendar.JANUARY, 2); // day 2 in GMT
+
+        boolean isDateBeforeReferenceYear = System.currentTimeMillis() < cal.getTimeInMillis();
+        if (isDateBeforeReferenceYear) {
+            logln("Warning: Past time is set to the system clock.  Some test cases may not return expected results.");
+        }
+
+        ZoneDescriptor[] REFERENCE_LIST = {
+            new ZoneDescriptor("HST", -600, false), // Olson northamerica -10:00
+            new ZoneDescriptor("AST", -540, true),  // ICU Link - America/Anchorage
+            new ZoneDescriptor("PST", -480, true),  // ICU Link - America/Los_Angeles
+            new ZoneDescriptor("PNT", -420, false), // ICU Link - America/Phoenix
+            new ZoneDescriptor("MST", -420, false), // updated Aug 2003 aliu
+            new ZoneDescriptor("CST", -360, true),  // Olson northamerica -7:00
+            new ZoneDescriptor("IET", -300, true),  // ICU Link - America/Indiana/Indianapolis
+            new ZoneDescriptor("EST", -300, false), // Olson northamerica -5:00
+            new ZoneDescriptor("PRT", -240, false), // ICU Link - America/Puerto_Rico
+            new ZoneDescriptor("CNT", -210, true),  // ICU Link - America/St_Johns
+            new ZoneDescriptor("AGT", -180, false), // ICU Link - America/Argentina/Buenos_Aires
+            new ZoneDescriptor("BET", -180, true),  // ICU Link - America/Sao_Paulo
+            new ZoneDescriptor("GMT", 0, false),    // Olson etcetera Link - Etc/GMT
+            new ZoneDescriptor("UTC", 0, false),    // Olson etcetera 0
+            new ZoneDescriptor("ECT", 60, true),    // ICU Link - Europe/Paris
+            new ZoneDescriptor("MET", 60, true),    // Olson europe 1:00 C-Eur
+            new ZoneDescriptor("CAT", 120, false),  // ICU Link - Africa/Harare
+            new ZoneDescriptor("ART", 120, false),  // ICU Link - Africa/Cairo
+            new ZoneDescriptor("EET", 120, true),   // Olson europe 2:00 EU
+            new ZoneDescriptor("EAT", 180, false),  // ICU Link - Africa/Addis_Ababa
+            new ZoneDescriptor("NET", 240, false),  // ICU Link - Asia/Yerevan
+            new ZoneDescriptor("PLT", 300, false),  // ICU Link - Asia/Karachi
+            new ZoneDescriptor("IST", 330, false),  // ICU Link - Asia/Kolkata
+            new ZoneDescriptor("BST", 360, false),  // ICU Link - Asia/Dhaka
+            new ZoneDescriptor("VST", 420, false),  // ICU Link - Asia/Ho_Chi_Minh
+            new ZoneDescriptor("CTT", 480, false),  // ICU Link - Asia/Shanghai
+            new ZoneDescriptor("JST", 540, false),  // ICU Link - Asia/Tokyo
+            new ZoneDescriptor("ACT", 570, false),  // ICU Link - Australia/Darwin
+            new ZoneDescriptor("AET", 600, true),   // ICU Link - Australia/Sydney
+            new ZoneDescriptor("SST", 660, false),  // ICU Link - Pacific/Guadalcanal
+            new ZoneDescriptor("NST", 720, true),   // ICU Link - Pacific/Auckland
+            new ZoneDescriptor("MIT", 780, true),   // ICU Link - Pacific/Apia
+
+            new ZoneDescriptor("Etc/Unknown", 0, false),    // CLDR
+
+            new ZoneDescriptor("SystemV/AST4ADT", -240, true),
+            new ZoneDescriptor("SystemV/EST5EDT", -300, true),
+            new ZoneDescriptor("SystemV/CST6CDT", -360, true),
+            new ZoneDescriptor("SystemV/MST7MDT", -420, true),
+            new ZoneDescriptor("SystemV/PST8PDT", -480, true),
+            new ZoneDescriptor("SystemV/YST9YDT", -540, true),
+            new ZoneDescriptor("SystemV/AST4", -240, false),
+            new ZoneDescriptor("SystemV/EST5", -300, false),
+            new ZoneDescriptor("SystemV/CST6", -360, false),
+            new ZoneDescriptor("SystemV/MST7", -420, false),
+            new ZoneDescriptor("SystemV/PST8", -480, false),
+            new ZoneDescriptor("SystemV/YST9", -540, false),
+            new ZoneDescriptor("SystemV/HST10", -600, false),
+        };
+
+        for (int i=0; i<REFERENCE_LIST.length; ++i) {
+            ZoneDescriptor referenceZone = REFERENCE_LIST[i];
+            ZoneDescriptor currentZone = new ZoneDescriptor(TimeZone.getTimeZone(referenceZone.getID()));
             if (referenceZone.equals(currentZone)) {
                 logln("ok " + referenceZone);
-            }
-            else {
-                warnln("Fail: Expected " + referenceZone +
-                      "; got " + currentZone);
+            } else {
+                if (isNonReferenceTzdataVersion || isJDKTimeZone || isDateBeforeReferenceYear) {
+                    logln("Warning: Expected " + referenceZone +
+                            "; got " + currentZone);
+                } else {
+                    errln("Fail: Expected " + referenceZone +
+                            "; got " + currentZone);
+                }
             }
         }
     }
@@ -341,19 +381,33 @@
                 logln(id + " -> " + zone.getID() + " " + offset);
                 String gotID = zone.getID();
                 if (exp == null && !gotID.equals("GMT")) {
-                    errln("Expected parse failure for " + id +
-                          ", got offset of " + offset +
-                          ", id " + zone.getID());
+                    if (isJDKTimeZone) {
+                        logln("[JDK time zone mode] Expected parse failure with ICU for " + id +
+                                ", got offset of " + offset +
+                                ", id " + zone.getID());
+                    } else {
+                        errln("Expected parse failure for " + id +
+                                ", got offset of " + offset +
+                                ", id " + zone.getID());
+                    }
                 }
                 // JDK 1.3 creates custom zones with the ID "Custom"
                 // JDK 1.4 creates custom zones with IDs of the form "GMT+02:00"
                 // ICU creates custom zones with IDs of the form "GMT+0200"
                 else if (exp != null && (ioffset != exp.intValue() || !(gotID.equals(expectedID)))) {
-                    errln("Expected offset of " + formatOffset(exp.intValue()) +
-                          ", id " + expectedID +
-                          ", for " + id +
-                          ", got offset of " + offset +
-                          ", id " + zone.getID());
+                    if (isJDKTimeZone) {
+                        logln("[JDK time zone mode] Expected offset of " + formatOffset(exp.intValue()) +
+                                "with ICU, id " + expectedID +
+                                ", for " + id +
+                                ", got offset of " + offset +
+                                ", id " + zone.getID());                        
+                    } else {
+                        errln("Expected offset of " + formatOffset(exp.intValue()) +
+                              ", id " + expectedID +
+                              ", for " + id +
+                              ", got offset of " + offset +
+                              ", id " + zone.getID());
+                    }
                 }
             }
         }
diff --git a/src/com/ibm/icu/impl/ICUConfig.java b/src/com/ibm/icu/impl/ICUConfig.java
new file mode 100644
index 0000000..decbc71
--- /dev/null
+++ b/src/com/ibm/icu/impl/ICUConfig.java
@@ -0,0 +1,65 @@
+/*
+ *******************************************************************************
+ * Copyright (C) 2008-2012, International Business Machines Corporation and    *
+ * others. All Rights Reserved.                                                *
+ *******************************************************************************
+ */
+package com.ibm.icu.impl;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.MissingResourceException;
+import java.util.Properties;
+
+/**
+ * ICUConfig is a class used for accessing ICU4J runtime configuration.
+ */
+public class ICUConfig {
+    public static final String CONFIG_PROPS_FILE = "/com/ibm/icu/ICUConfig.properties";
+    private static final Properties CONFIG_PROPS;
+
+    static {
+        CONFIG_PROPS = new Properties();
+        try {
+            InputStream is = ICUData.getStream(CONFIG_PROPS_FILE);
+            if (is != null) {
+                CONFIG_PROPS.load(is);
+            }
+        } catch (MissingResourceException mre) {
+            // If it does not exist, ignore.
+        } catch (IOException ioe) {
+            // Any IO errors, ignore
+        }
+    }
+
+    /**
+     * Get ICU configuration property value for the given name.
+     * @param name The configuration property name
+     * @return The configuration property value, or null if it does not exist.
+     */
+    public static String get(String name) {
+        return get(name, null);
+    }
+
+    /**
+     * Get ICU configuration property value for the given name.
+     * @param name The configuration property name
+     * @param def The default value
+     * @return The configuration property value.  If the property does not
+     * exist, <code>def</code> is returned.
+     */
+    public static String get(String name, String def) {
+        String val = null;
+        // Try the system property first
+        try {
+            val = System.getProperty(name);
+        } catch (SecurityException e) {
+            // Ignore and fall through
+        }
+
+        if (val == null) {
+            val = CONFIG_PROPS.getProperty(name, def);
+        }
+        return val;
+    }
+}
diff --git a/src/com/ibm/icu/impl/JavaTimeZone.java b/src/com/ibm/icu/impl/JavaTimeZone.java
new file mode 100644
index 0000000..d9ceb77
--- /dev/null
+++ b/src/com/ibm/icu/impl/JavaTimeZone.java
@@ -0,0 +1,394 @@
+//##header J2SE15
+/*
+ *******************************************************************************
+ * Copyright (C) 2008-2012, International Business Machines Corporation and    *
+ * others. All Rights Reserved.                                                *
+ *******************************************************************************
+ */
+package com.ibm.icu.impl;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.text.ParsePosition;
+import java.util.Date;
+import java.util.TreeSet;
+
+import com.ibm.icu.text.NumberFormat;
+import com.ibm.icu.util.TimeZone;
+
+/**
+ * JavaTimeZone inherits com.ibm.icu.util.TimeZone and wraps java.util.TimeZone.
+ * We used to have JDKTimeZone which wrapped Java TimeZone and used it as primary
+ * TimeZone implementation until ICU4J 3.4.1.  This class works exactly like
+ * JDKTimeZone and allows ICU users who use ICU4J and JDK date/time/calendar
+ * services in mix to maintain only JDK timezone rules.
+ *
+ * This TimeZone subclass is returned by the TimeZone factory method getTimeZone(String)
+ * when the default timezone type in TimeZone class is TimeZone.TIMEZONE_JDK.
+ */
+public class JavaTimeZone extends TimeZone {
+
+    private static final long serialVersionUID = 6977448185543929364L;
+
+    private static final TreeSet AVAILABLESET;
+
+    private java.util.TimeZone javatz;
+    private transient java.util.Calendar javacal;
+
+    static {
+        AVAILABLESET = new TreeSet();
+        String[] availableIds = java.util.TimeZone.getAvailableIDs();
+        for (int i = 0; i < availableIds.length; i++) {
+            AVAILABLESET.add(availableIds[i]);
+        }
+    }
+
+    /**
+     * Constructs a JavaTimeZone with the default Java TimeZone
+     */
+    public JavaTimeZone() {
+        javatz = java.util.TimeZone.getDefault();
+        setID(javatz.getID());
+        javacal = new java.util.GregorianCalendar(javatz);
+    }
+
+    /**
+     * Constructs a JavaTimeZone with the given timezone ID.
+     * @param id A timezone ID, either a system ID or a custom ID.
+     */
+    public JavaTimeZone(String id) {
+        if (AVAILABLESET.contains(id)) {
+            javatz = java.util.TimeZone.getTimeZone(id);
+        }
+
+        if (javatz == null) {
+            // Use ICU's canonical ID mapping
+            if (id.equals("Etc/Unknown")) {
+                // Special CLDR ID
+                javatz = java.util.TimeZone.getTimeZone("GMT");
+                javatz.setID("Etc/Unknown");
+                
+            } else {
+                String canonicalID = ZoneMeta.getOlsonCanonicalID(id);
+                if (canonicalID != null && AVAILABLESET.contains(canonicalID)) {
+                    javatz = java.util.TimeZone.getTimeZone(canonicalID);
+                }
+            }
+        }
+
+        if (javatz == null){
+            int[] fields = new int[4];
+            if (parseCustomID(id, fields)) {
+                // JDK does not support offset seconds.
+                // If custom ID, we create java.util.SimpleTimeZone here.
+                id = formatCustomID(fields[1], fields[2], fields[3], fields[0] < 0);
+                int offset = fields[0] * ((fields[1] * 60 + fields[2]) * 60 + fields[3]) * 1000;
+                javatz = new java.util.SimpleTimeZone(offset, id);
+            }
+        }
+
+        if (javatz == null) {
+            // Final fallback
+            id = "GMT";
+            javatz = java.util.TimeZone.getTimeZone(id);
+        }
+        setID(id);
+        javacal = new java.util.GregorianCalendar(javatz);
+    }
+
+    /* (non-Javadoc)
+     * @see com.ibm.icu.util.TimeZone#getOffset(int, int, int, int, int, int)
+     */
+    public int getOffset(int era, int year, int month, int day, int dayOfWeek, int milliseconds) {
+        return javatz.getOffset(era, year, month, day, dayOfWeek, milliseconds);
+    }
+
+    /* (non-Javadoc)
+     * @see com.ibm.icu.util.TimeZone#getOffset(long, boolean, int[])
+     */
+    public void getOffset(long date, boolean local, int[] offsets) {
+        synchronized (javacal) {
+            if (local) {
+                int fields[] = new int[6];
+                Grego.timeToFields(date, fields);
+                int hour, min, sec, mil;
+                int tmp = fields[5];
+                mil = tmp % 1000;
+                tmp /= 1000;
+                sec = tmp % 60;
+                tmp /= 60;
+                min = tmp % 60;
+                hour = tmp / 60;
+                javacal.clear();
+                javacal.set(fields[0], fields[1], fields[2], hour, min, sec);
+                javacal.set(java.util.Calendar.MILLISECOND, mil);
+
+                int doy1, hour1, min1, sec1, mil1;
+                doy1 = javacal.get(java.util.Calendar.DAY_OF_YEAR);
+                hour1 = javacal.get(java.util.Calendar.HOUR_OF_DAY);
+                min1 = javacal.get(java.util.Calendar.MINUTE);
+                sec1 = javacal.get(java.util.Calendar.SECOND);
+                mil1 = javacal.get(java.util.Calendar.MILLISECOND);
+
+                if (fields[4] != doy1 || hour != hour1 || min != min1 || sec != sec1 || mil != mil1) {
+                    // Calendar field(s) were changed due to the adjustment for non-existing time
+                    // Note: This code does not support non-existing local time at year boundary properly.
+                    // But, it should work fine for real timezones.
+                    int dayDelta = Math.abs(doy1 - fields[4]) > 1 ? 1 : doy1 - fields[4];
+                    int delta = ((((dayDelta * 24) + hour1 - hour) * 60 + min1 - min) * 60 + sec1 - sec) * 1000 + mil1 - mil;
+
+                    // In this case, we use the offsets before the transition
+//#if defined(FOUNDATION10) || defined(J2SE13)
+//##                    javacal.setTime(new Date(javacal.getTime().getTime() - delta - 1));
+//#else
+                   javacal.setTimeInMillis(javacal.getTimeInMillis() - delta - 1);
+//#endif
+                }
+            } else {
+//#if defined(FOUNDATION10) || defined(J2SE13)
+//##                javacal.setTime(new Date(date));
+//#else
+                javacal.setTimeInMillis(date);
+//#endif
+            }
+            offsets[0] = javacal.get(java.util.Calendar.ZONE_OFFSET);
+            offsets[1] = javacal.get(java.util.Calendar.DST_OFFSET);
+        }
+    }
+
+    /* (non-Javadoc)
+     * @see com.ibm.icu.util.TimeZone#getRawOffset()
+     */
+    public int getRawOffset() {
+        return javatz.getRawOffset();
+    }
+
+    /* (non-Javadoc)
+     * @see com.ibm.icu.util.TimeZone#inDaylightTime(java.util.Date)
+     */
+    public boolean inDaylightTime(Date date) {
+        return javatz.inDaylightTime(date);
+    }
+
+    /* (non-Javadoc)
+     * @see com.ibm.icu.util.TimeZone#setRawOffset(int)
+     */
+    public void setRawOffset(int offsetMillis) {
+        javatz.setRawOffset(offsetMillis);
+    }
+
+    /* (non-Javadoc)
+     * @see com.ibm.icu.util.TimeZone#useDaylightTime()
+     */
+    public boolean useDaylightTime() {
+        return javatz.useDaylightTime();
+    }
+
+    /* (non-Javadoc)
+     * @see com.ibm.icu.util.TimeZone#getDSTSavings()
+     */
+    public int getDSTSavings() {
+        int dstSavings = super.getDSTSavings();
+        try {
+            // hack so test compiles and runs in both JDK 1.3 and JDK 1.4+
+            final Object[] args = new Object[0];
+            final Class[] argtypes = new Class[0];
+            java.lang.reflect.Method m = javatz.getClass().getMethod("getDSTSavings", argtypes); 
+            dstSavings = ((Integer) m.invoke(javatz, args)).intValue();
+        } catch (Exception e) {
+            // just use the result returned by super.getDSTSavings()
+        }
+        return dstSavings;
+    }
+
+    public java.util.TimeZone unwrap() {
+        return javatz;
+    }
+
+    /* (non-Javadoc)
+     * @see com.ibm.icu.util.TimeZone#clone()
+     */
+    public Object clone() {
+        JavaTimeZone other = (JavaTimeZone)super.clone();
+        other.javatz = (java.util.TimeZone)javatz.clone();
+        return other;
+    }
+
+    /* (non-Javadoc)
+     * @see com.ibm.icu.util.TimeZone#hashCode()
+     */
+    public int hashCode() {
+        return super.hashCode() + javatz.hashCode();
+    }
+
+    private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException {
+        s.defaultReadObject();
+        javacal = new java.util.GregorianCalendar(javatz);
+    }
+
+
+    private static final String kGMT_ID   = "GMT";
+    private static final String kCUSTOM_TZ_PREFIX = "GMT";
+
+    // Maximum value of valid custom time zone hour/min
+    private static final int kMAX_CUSTOM_HOUR = 23;
+    private static final int kMAX_CUSTOM_MIN = 59;
+    private static final int kMAX_CUSTOM_SEC = 59;
+
+    /*
+     * Parses the given custom time zone identifier
+     * @param id id A string of the form GMT[+-]hh:mm, GMT[+-]hhmm, or
+     * GMT[+-]hh.
+     * @param fields An array of int (length = 4) to receive the parsed
+     * offset time fields.  The sign is set to fields[0] (-1 or 1),
+     * hour is set to fields[1], minute is set to fields[2] and second is
+     * set to fields[3].
+     * @return Returns true when the given custom id is valid.
+     */
+    static boolean parseCustomID(String id, int[] fields) {
+        NumberFormat numberFormat = null;
+        String idUppercase = id.toUpperCase();
+
+        if (id != null && id.length() > kGMT_ID.length() &&
+            idUppercase.startsWith(kGMT_ID)) {
+            ParsePosition pos = new ParsePosition(kGMT_ID.length());
+            int sign = 1;
+            int hour = 0;
+            int min = 0;
+            int sec = 0;
+
+            if (id.charAt(pos.getIndex()) == 0x002D /*'-'*/) {
+                sign = -1;
+            } else if (id.charAt(pos.getIndex()) != 0x002B /*'+'*/) {
+                return false;
+            }
+            pos.setIndex(pos.getIndex() + 1);
+
+            numberFormat = NumberFormat.getInstance();
+            numberFormat.setParseIntegerOnly(true);
+
+            // Look for either hh:mm, hhmm, or hh
+            int start = pos.getIndex();
+
+            Number n = numberFormat.parse(id, pos);
+            if (pos.getIndex() == start) {
+                return false;
+            }
+            hour = n.intValue();
+
+            if (pos.getIndex() < id.length()){
+                if (pos.getIndex() - start > 2
+                        || id.charAt(pos.getIndex()) != 0x003A /*':'*/) {
+                    return false;
+                }
+                // hh:mm
+                pos.setIndex(pos.getIndex() + 1);
+                int oldPos = pos.getIndex();
+                n = numberFormat.parse(id, pos);
+                if ((pos.getIndex() - oldPos) != 2) {
+                    // must be 2 digits
+                    return false;
+                }
+                min = n.intValue();
+                if (pos.getIndex() < id.length()) {
+                    if (id.charAt(pos.getIndex()) != 0x003A /*':'*/) {
+                        return false;
+                    }
+                    // [:ss]
+                    pos.setIndex(pos.getIndex() + 1);
+                    oldPos = pos.getIndex();
+                    n = numberFormat.parse(id, pos);
+                    if (pos.getIndex() != id.length()
+                            || (pos.getIndex() - oldPos) != 2) {
+                        return false;
+                    }
+                    sec = n.intValue();
+                }
+            } else {
+                // Supported formats are below -
+                //
+                // HHmmss
+                // Hmmss
+                // HHmm
+                // Hmm
+                // HH
+                // H
+
+                int length = pos.getIndex() - start;
+                if (length <= 0 || 6 < length) {
+                    // invalid length
+                    return false;
+                }
+                switch (length) {
+                    case 1:
+                    case 2:
+                        // already set to hour
+                        break;
+                    case 3:
+                    case 4:
+                        min = hour % 100;
+                        hour /= 100;
+                        break;
+                    case 5:
+                    case 6:
+                        sec = hour % 100;
+                        min = (hour/100) % 100;
+                        hour /= 10000;
+                        break;
+                }
+            }
+
+            if (hour <= kMAX_CUSTOM_HOUR && min <= kMAX_CUSTOM_MIN && sec <= kMAX_CUSTOM_SEC) {
+                if (fields != null) {
+                    if (fields.length >= 1) {
+                        fields[0] = sign;
+                    }
+                    if (fields.length >= 2) {
+                        fields[1] = hour;
+                    }
+                    if (fields.length >= 3) {
+                        fields[2] = min;
+                    }
+                    if (fields.length >= 4) {
+                        fields[3] = sec;
+                    }
+                }
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /*
+     * Returns the normalized custom TimeZone ID
+     */
+    static String formatCustomID(int hour, int min, int sec, boolean negative) {
+        // Create normalized time zone ID - GMT[+|-]hhmm[ss]
+        StringBuffer zid = new StringBuffer(kCUSTOM_TZ_PREFIX);
+        if (hour != 0 || min != 0) {
+            if(negative) {
+                zid.append('-');
+            } else {
+                zid.append('+');
+            }
+            // Always use US-ASCII digits
+            if (hour < 10) {
+                zid.append('0');
+            }
+            zid.append(hour);
+            if (min < 10) {
+                zid.append('0');
+            }
+            zid.append(min);
+
+            if (sec != 0) {
+                // Optional second field
+                if (sec < 10) {
+                    zid.append('0');
+                }
+                zid.append(sec);
+            }
+        }
+        return zid.toString();
+    }
+}
diff --git a/src/com/ibm/icu/impl/data/icudata.jar b/src/com/ibm/icu/impl/data/icudata.jar
index cdce91e..86d8c57 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:fc44b1203dde80ce45566deee764eb77bc69f8dc2f87e72a07f36798846862fa
-size 5450591
+oid sha256:d580ce04b0d0fceafce80c6cd40e6f2d8ece3f1e0570b6c218f74b234f91d3a0
+size 5456288
diff --git a/src/com/ibm/icu/util/TimeZone.java b/src/com/ibm/icu/util/TimeZone.java
index 87e8abe..de8fea7 100644
--- a/src/com/ibm/icu/util/TimeZone.java
+++ b/src/com/ibm/icu/util/TimeZone.java
@@ -1,7 +1,7 @@
 /*
  * @(#)TimeZone.java    1.51 00/01/19
  *
- * Copyright (C) 1996-2007, International Business Machines
+ * Copyright (C) 1996-2012, International Business Machines
  * Corporation and others.  All Rights Reserved.
  */
 
@@ -14,6 +14,8 @@
 import java.util.Locale;
 
 import com.ibm.icu.impl.Grego;
+import com.ibm.icu.impl.ICUConfig;
+import com.ibm.icu.impl.JavaTimeZone;
 import com.ibm.icu.impl.TimeZoneAdapter;
 import com.ibm.icu.impl.ZoneMeta;
 import com.ibm.icu.text.SimpleDateFormat;
@@ -83,6 +85,19 @@
     }
 
     /**
+     * A time zone implementation type indicating ICU's own TimeZone used by
+     * <code>getTimeZone</code>, <code>setDefaultTimeZoneType</code>
+     * and <code>getDefaultTimeZoneType</code>.
+     */
+    private static final int TIMEZONE_ICU = 0;
+    /**
+     * A time zone implementation type indicating JDK TimeZone used by
+     * <code>getTimeZone</code>, <code>setDefaultTimeZoneType</code>
+     * and <code>getDefaultTimeZoneType</code>.
+     */
+    private static final int TIMEZONE_JDK = 1;
+
+    /**
      * A style specifier for <code>getDisplayName()</code> indicating
      * a short name, such as "PST."
      * @see #LONG
@@ -576,24 +591,45 @@
      * @stable ICU 2.0
      */
     public static synchronized TimeZone getTimeZone(String ID) {
-        /* We first try to lookup the zone ID in our system list.  If this
-         * fails, we try to parse it as a custom string GMT[+-]hh:mm.  If
-         * all else fails, we return GMT, which is probably not what the
-         * user wants, but at least is a functioning TimeZone object.
-         *
-         * We cannot return NULL, because that would break compatibility
-         * with the JDK.
-         */
-        if(ID==null){
-            throw new NullPointerException();
-        }
-        TimeZone result = ZoneMeta.getSystemTimeZone(ID);
-        
-        if (result == null) {
-            result = ZoneMeta.getCustomTimeZone(ID);
-        }
-        if (result == null) {
-            result = ZoneMeta.getGMT();
+        return getTimeZone(ID, TZ_IMPL);
+    }
+
+    /**
+     * Gets the <code>TimeZone</code> for the given ID and the timezone type.
+     * @param ID the ID for a <code>TimeZone</code>, either an abbreviation
+     * such as "PST", a full name such as "America/Los_Angeles", or a custom
+     * ID such as "GMT-8:00". Note that the support of abbreviations is
+     * for JDK 1.1.x compatibility only and full names should be used.
+     * @param type Timezone type, either <code>TIMEZONE_ICU</code> or <code>TIMEZONE_JDK</code>.
+     * @return the specified <code>TimeZone</code>, or the GMT zone if the given ID
+     * cannot be understood.
+     * @internal
+     * @deprecated This API is ICU internal only.
+     */
+    public static synchronized TimeZone getTimeZone(String ID, int type) {
+        TimeZone result;
+        if (type == TIMEZONE_JDK) {
+            result = new JavaTimeZone(ID);
+        } else {
+            /* We first try to lookup the zone ID in our system list.  If this
+             * fails, we try to parse it as a custom string GMT[+-]hh:mm.  If
+             * all else fails, we return GMT, which is probably not what the
+             * user wants, but at least is a functioning TimeZone object.
+             *
+             * We cannot return NULL, because that would break compatibility
+             * with the JDK.
+             */
+            if(ID==null){
+                throw new NullPointerException();
+            }
+            result = ZoneMeta.getSystemTimeZone(ID);
+            
+            if (result == null) {
+                result = ZoneMeta.getCustomTimeZone(ID);
+            }
+            if (result == null) {
+                result = ZoneMeta.getGMT();
+            }
         }
         return result;
     }
@@ -691,8 +727,12 @@
      */
     public static synchronized TimeZone getDefault() {
         if (defaultZone == null) {
-            java.util.TimeZone temp=java.util.TimeZone.getDefault();
-            defaultZone = getTimeZone(temp.getID());
+            if (TZ_IMPL == TIMEZONE_JDK) {
+                defaultZone = new JavaTimeZone();
+            } else {
+                java.util.TimeZone temp = java.util.TimeZone.getDefault();
+                defaultZone = getTimeZone(temp.getID());
+            }
         }
         return (TimeZone) defaultZone.clone();
     }
@@ -706,14 +746,36 @@
      * @stable ICU 2.0
      */
     public static synchronized void setDefault(TimeZone tz) {
-        
         defaultZone = tz;
+        java.util.TimeZone jdkZone = null;
+        if (defaultZone instanceof JavaTimeZone) {
+            jdkZone = ((JavaTimeZone)defaultZone).unwrap();
+        } else {
         // Keep java.util.TimeZone default in sync so java.util.Date
         // can interoperate with com.ibm.icu.util classes.
-        java.util.TimeZone jdkZone = null;
+
         if (tz != null) {
+                if (tz instanceof com.ibm.icu.impl.OlsonTimeZone) {
+                    // Because of the lack of APIs supporting historic
+                    // zone offset/dst saving in JDK TimeZone,
+                    // wrapping ICU TimeZone with JDK TimeZone will
+                    // cause historic offset calculation in Calendar/Date.
+                    // JDK calendar implementation calls getRawOffset() and
+                    // getDSTSavings() when the instance of JDK TimeZone
+                    // is not an instance of JDK internal TimeZone subclass
+                    // (sun.util.calendar.ZoneInfo).  Ticket#6459
+                    String icuID = tz.getID();
+                    jdkZone = java.util.TimeZone.getTimeZone(icuID);
+                    if (!icuID.equals(jdkZone.getID())) {
+                        // JDK does not know the ID..
+                        jdkZone = null;
+                    }
+                }
+                if (jdkZone == null) {
             jdkZone = TimeZoneAdapter.wrap(tz);
         }
+            }
+        }
         java.util.TimeZone.setDefault(jdkZone);
     }
 
@@ -808,6 +870,24 @@
      */
     private static String TZDATA_VERSION = null;
 
+    /**
+     * TimeZone implementation type
+     */
+    private static int TZ_IMPL = TIMEZONE_ICU;
+
+    /**
+     * TimeZone implementation type initialization
+     */
+    private static final String TZIMPL_CONFIG_KEY = "com.ibm.icu.util.TimeZone.DefaultTimeZoneType";
+    private static final String TZIMPL_CONFIG_ICU = "ICU";
+    private static final String TZIMPL_CONFIG_JDK = "JDK";
+
+    static {
+        String type = ICUConfig.get(TZIMPL_CONFIG_KEY, TZIMPL_CONFIG_ICU);
+        if (type.equalsIgnoreCase(TZIMPL_CONFIG_JDK)) {
+            TZ_IMPL = TIMEZONE_JDK;
+        }
+    }
 }
 
 //eof
diff --git a/src/com/ibm/icu/util/VTimeZone.java b/src/com/ibm/icu/util/VTimeZone.java
index 03bd04e..0bd393e 100644
--- a/src/com/ibm/icu/util/VTimeZone.java
+++ b/src/com/ibm/icu/util/VTimeZone.java
@@ -1,6 +1,6 @@
 /*
  *******************************************************************************
- * Copyright (C) 2007, International Business Machines Corporation and         *
+ * Copyright (C) 2007-2012, International Business Machines Corporation and    *
  * others. All Rights Reserved.                                                *
  *******************************************************************************
  */
@@ -49,7 +49,7 @@
      */
     public static VTimeZone create(String tzid) {
         VTimeZone vtz = new VTimeZone();
-        vtz.tz = (BasicTimeZone)TimeZone.getTimeZone(tzid);
+        vtz.tz = (BasicTimeZone)TimeZone.getTimeZone(tzid, 0);
         vtz.olsonzid = vtz.tz.getID();
         vtz.setID(tzid);