]> gitweb.fperrin.net Git - Dictionary.git/blobdiff - jars/icu4j-52_1/main/classes/core/src/com/ibm/icu/util/TimeZone.java
Upgrade ICU4J.
[Dictionary.git] / jars / icu4j-52_1 / main / classes / core / src / com / ibm / icu / util / TimeZone.java
similarity index 76%
rename from jars/icu4j-4_8_1_1/main/classes/core/src/com/ibm/icu/util/TimeZone.java
rename to jars/icu4j-52_1/main/classes/core/src/com/ibm/icu/util/TimeZone.java
index 604f80b35395612460819591d324ef1e814add9b..af7804a11ccfcbd63b2986bfc0fb28c9a86f1129 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * @(#)TimeZone.java    1.51 00/01/19
  *
- * Copyright (C) 1996-2011, International Business Machines
+ * Copyright (C) 1996-2013, International Business Machines
  * Corporation and others.  All Rights Reserved.
  */
 
@@ -12,10 +12,11 @@ import java.util.Date;
 import java.util.Locale;
 import java.util.MissingResourceException;
 import java.util.Set;
+import java.util.logging.Logger;
 
 import com.ibm.icu.impl.Grego;
 import com.ibm.icu.impl.ICUConfig;
-import com.ibm.icu.impl.ICULogger;
+import com.ibm.icu.impl.ICUResourceBundle;
 import com.ibm.icu.impl.JavaTimeZone;
 import com.ibm.icu.impl.TimeZoneAdapter;
 import com.ibm.icu.impl.ZoneMeta;
@@ -48,7 +49,8 @@ import com.ibm.icu.util.ULocale.Category;
  * </pre>
  * </blockquote>
  * You can use the {@link #getAvailableIDs()} method to iterate through
- * all the supported time zone IDs. You can then choose a
+ * all the supported time zone IDs, or getCanonicalID method to check
+ * if a time zone ID is supported or not. You can then choose a
  * supported ID to get a <code>TimeZone</code>.
  * If the time zone you want is not represented by one of the
  * supported IDs, then you can create a custom time zone ID with
@@ -62,8 +64,13 @@ import com.ibm.icu.util.ULocale.Category;
  *
  * For example, you might specify GMT+14:00 as a custom
  * time zone ID.  The <code>TimeZone</code> that is returned
- * when you specify a custom time zone ID does not include
- * daylight savings time.
+ * when you specify a custom time zone ID uses the specified
+ * offset from GMT(=UTC) and does not observe daylight saving
+ * time. For example, you might specify GMT+14:00 as a custom
+ * time zone ID to create a TimeZone representing 14 hours ahead
+ * of GMT (with no daylight saving time). In addition, 
+ * <code>getCanonicalID</code> can also be used to
+ * normalize a custom time zone ID.
  *
  * <p>For compatibility with JDK 1.1.x, some other three-letter time zone IDs
  * (such as "PST", "CTT", "AST") are also supported. However, <strong>their
@@ -104,14 +111,11 @@ import com.ibm.icu.util.ULocale.Category;
  * @author       Mark Davis, David Goldsmith, Chen-Lieh Huang, Alan Liu
  * @stable ICU 2.0
  */
-abstract public class TimeZone implements Serializable, Cloneable {
+abstract public class TimeZone implements Serializable, Cloneable, Freezable<TimeZone> {
     /**
-     * {@icu} A logger for TimeZone. Will be null if logging is not on by way of system
-     * property: "icu4j.debug.logging"
-     * @draft ICU 4.4
-     * @provisional This API might change or be removed in a future release.
+     * Logger instance for this class
      */
-    public static ICULogger TimeZoneLogger = ICULogger.getICULogger(TimeZone.class.getName());
+    private static final Logger LOGGER = Logger.getLogger("com.ibm.icu.util.TimeZone");
 
     // using serialver from jdk1.4.2_05
     private static final long serialVersionUID = -744942128318337471L;
@@ -124,6 +128,19 @@ abstract public class TimeZone implements Serializable, Cloneable {
     public TimeZone() {
     }
 
+    /**
+     * Constructing a TimeZone with the given time zone ID.
+     * @param ID the time zone ID.
+     * @internal
+     * @deprecated This API is ICU internal only.
+     */
+    protected TimeZone(String ID) {
+        if (ID == null) {
+            throw new NullPointerException();
+        }
+        this.ID = ID;
+    }
+
     /**
      * {@icu} A time zone implementation type indicating ICU's own TimeZone used by
      * <code>getTimeZone</code>, <code>setDefaultTimeZoneType</code>
@@ -208,36 +225,59 @@ abstract public class TimeZone implements Serializable, Cloneable {
      * {@icu} The time zone ID reserved for unknown time zone.
      * @see #getTimeZone(String)
      * 
-     * @draft ICU 4.8
-     * @provisional This API might change or be removed in a future release.
+     * @stable ICU 4.8
      */
     public static final String UNKNOWN_ZONE_ID = "Etc/Unknown";
 
+    /**
+     * The canonical ID for GMT(UTC) time zone.
+     */
+    static final String GMT_ZONE_ID = "Etc/GMT";
+
+    /**
+     * {@icu} The immutable (frozen) "unknown" time zone.
+     * It behaves like the GMT/UTC time zone but has the UNKNOWN_ZONE_ID = "Etc/Unknown".
+     * {@link TimeZone#getTimeZone(String)} returns a mutable clone of this
+     * time zone if the input ID is not recognized.
+     *
+     * @see #UNKNOWN_ZONE_ID
+     * @see #getTimeZone(String)
+     * 
+     * @stable ICU 49
+     */
+    public static final TimeZone UNKNOWN_ZONE = new SimpleTimeZone(0, UNKNOWN_ZONE_ID).freeze();
+
+    /**
+     * {@icu} The immutable GMT (=UTC) time zone. Its ID is "Etc/GMT".
+     *
+     * @stable ICU 49
+     */
+    public static final TimeZone GMT_ZONE = new SimpleTimeZone(0, GMT_ZONE_ID).freeze();
+
     /**
      * {@icu} System time zone type constants used by filtering zones in
      * {@link TimeZone#getAvailableIDs(SystemTimeZoneType, String, Integer)}
      *
-     * @draft ICU 4.8
-     * @provisional This API might change or be removed in a future release.
+     * @stable ICU 4.8
      */
     public enum SystemTimeZoneType {
         /**
          * Any system zones.
-         * @draft ICU 4.8
+         * @stable ICU 4.8
          * @provisional This API might change or be removed in a future release.
          */
         ANY,
 
         /**
          * Canonical system zones.
-         * @draft ICU 4.8
+         * @stable ICU 4.8
          * @provisional This API might change or be removed in a future release.
          */
         CANONICAL,
 
         /**
          * Canonical system zones associated with actual locations.
-         * @draft ICU 4.8
+         * @stable ICU 4.8
          * @provisional This API might change or be removed in a future release.
          */
         CANONICAL_LOCATION,
@@ -369,6 +409,9 @@ abstract public class TimeZone implements Serializable, Cloneable {
         if (ID == null) {
             throw new NullPointerException();
         }
+        if (isFrozen()) {
+            throw new UnsupportedOperationException("Attempt to modify a frozen TimeZone instance.");
+        }
         this.ID = ID;
     }
 
@@ -517,7 +560,8 @@ abstract public class TimeZone implements Serializable, Cloneable {
             if (daylight && timeType.value == TimeType.STANDARD ||
                     !daylight && timeType.value == TimeType.DAYLIGHT) {
                 int offset = daylight ? getRawOffset() + getDSTSavings() : getRawOffset();
-                result = tzfmt.formatOffsetLocalizedGMT(offset);
+                result = (style == SHORT_GENERIC) ?
+                        tzfmt.formatOffsetShortLocalizedGMT(offset) : tzfmt.formatOffsetLocalizedGMT(offset);
             }
 
         } else if (style == LONG_GMT || style == SHORT_GMT) {
@@ -529,7 +573,7 @@ abstract public class TimeZone implements Serializable, Cloneable {
                 result = tzfmt.formatOffsetLocalizedGMT(offset);
                 break;
             case SHORT_GMT:
-                result = tzfmt.formatOffsetRFC822(offset);
+                result = tzfmt.formatOffsetISO8601Basic(offset, false, false, false);
                 break;
             }
         } else {
@@ -545,10 +589,8 @@ abstract public class TimeZone implements Serializable, Cloneable {
                 nameType = daylight ? NameType.LONG_DAYLIGHT : NameType.LONG_STANDARD;
                 break;
             case SHORT:
-                nameType = daylight ? NameType.SHORT_DAYLIGHT : NameType.SHORT_STANDARD;
-                break;
             case SHORT_COMMONLY_USED:
-                nameType = daylight ? NameType.SHORT_DAYLIGHT_COMMONLY_USED : NameType.SHORT_STANDARD_COMMONLY_USED;
+                nameType = daylight ? NameType.SHORT_DAYLIGHT : NameType.SHORT_STANDARD;
                 break;
             }
             result = tznames.getDisplayName(ZoneMeta.getCanonicalCLDRID(this), nameType, date);
@@ -556,7 +598,8 @@ abstract public class TimeZone implements Serializable, Cloneable {
                 // Fallback to localized GMT
                 TimeZoneFormat tzfmt = TimeZoneFormat.getInstance(locale);
                 int offset = daylight && useDaylightTime() ? getRawOffset() + getDSTSavings() : getRawOffset();
-                result = tzfmt.formatOffsetLocalizedGMT(offset);
+                result = (style == LONG) ?
+                        tzfmt.formatOffsetLocalizedGMT(offset) : tzfmt.formatOffsetShortLocalizedGMT(offset);
             }
         }
         assert(result != null);
@@ -604,6 +647,35 @@ abstract public class TimeZone implements Serializable, Cloneable {
      */
     abstract public boolean useDaylightTime();
 
+    /**
+     * Queries if this time zone is in daylight saving time or will observe
+     * daylight saving time at any future time.
+     * <p>The default implementation in this class returns <code>true</code> if {@link #useDaylightTime()}
+     * or {@link #inDaylightTime(Date) inDaylightTime(new Date())} returns <code>true</code>.
+     * <p>
+     * <strong>Note:</strong> This method was added for JDK compatibility support.
+     * The JDK's <code>useDaylightTime()</code> only checks the last known rule(s), therefore
+     * it may return false even the zone observes daylight saving time currently. JDK added
+     * <code>observesDaylightTime()</code> to resolve the issue. In ICU, {@link #useDaylightTime()}
+     * works differently. The ICU implementation checks if the zone uses daylight saving time
+     * in the current calendar year. Therefore, it will never return <code>false</code> if
+     * daylight saving time is currently used.
+     * <p>
+     * ICU's TimeZone subclass implementations override this method to support the same behavior
+     * with JDK's <code>observesDaylightSavingTime()</code>. Unlike {@link #useDaylightTime()},
+     * the implementation does not take past daylight saving time into account, so
+     * that this method may return <code>false</code> even when {@link #useDaylightTime()} returns
+     * <code>true</code>.
+     * 
+     * @return <code>true</code> if this time zone is in daylight saving time or will observe
+     * daylight saving time at any future time.
+     * @see #useDaylightTime
+     * @stable ICU 49
+     */
+    public boolean observesDaylightTime() {
+        return useDaylightTime() || inDaylightTime(new Date());
+    }
+
     /**
      * Queries if the given date is in daylight savings time in
      * this time zone.
@@ -621,13 +693,32 @@ abstract public class TimeZone implements Serializable, Cloneable {
      * or a custom ID such as "GMT-8:00". Note that the support of abbreviations,
      * such as "PST", is for JDK 1.1.x compatibility only and full names should be used.
      *
-     * @return the specified <code>TimeZone</code>, or the GMT zone with ID "Etc/Unknown"
-     * if the given ID cannot be understood.
-     * @see #UNKNOWN_ZONE_ID
+     * @return the specified <code>TimeZone</code>, or a mutable clone of the UNKNOWN_ZONE
+     * if the given ID cannot be understood or if the given ID is "Etc/Unknown".
+     * @see #UNKNOWN_ZONE
      * @stable ICU 2.0
      */
-    public static synchronized TimeZone getTimeZone(String ID) {
-        return getTimeZone(ID, TZ_IMPL);
+    public static TimeZone getTimeZone(String ID) {
+        return getTimeZone(ID, TZ_IMPL, false);
+    }
+
+    /**
+     * Gets the <code>TimeZone</code> for the given ID. The instance of <code>TimeZone</code>
+     * returned by this method is immutable. Any methods mutate the instance({@link #setID(String)},
+     * {@link #setRawOffset(int)}) will throw <code>UnsupportedOperationException</code> upon its
+     * invocation.
+     *
+     * @param ID the ID for a <code>TimeZone</code>, such as "America/Los_Angeles",
+     * or a custom ID such as "GMT-8:00". Note that the support of abbreviations,
+     * such as "PST", is for JDK 1.1.x compatibility only and full names should be used.
+     *
+     * @return the specified <code>TimeZone</code>, or the UNKNOWN_ZONE
+     * if the given ID cannot be understood.
+     * @see #UNKNOWN_ZONE
+     * @stable ICU 49
+     */
+    public static TimeZone getFrozenTimeZone(String ID) {
+        return getTimeZone(ID, TZ_IMPL, true);
     }
 
     /**
@@ -637,14 +728,30 @@ abstract public class TimeZone implements Serializable, Cloneable {
      * "PST", is for JDK 1.1.x compatibility only and full names should be used.
      * @param type Time zone 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.
+     * @return the specified <code>TimeZone</code>, or a mutable clone of the UNKNOWN_ZONE if the given ID
+     * cannot be understood or if the given ID is "Etc/Unknown".
+     * @see #UNKNOWN_ZONE
      * @stable ICU 4.0
      */
-    public static synchronized TimeZone getTimeZone(String ID, int type) {
+    public static TimeZone getTimeZone(String ID, int type) {
+        return getTimeZone(ID, type, false);
+    }
+
+    /**
+     * Gets the <code>TimeZone</code> for the given ID and the timezone type.
+     * @param ID time zone ID
+     * @param type time zone implementation type, TIMEZONE_JDK or TIMEZONE_ICU 
+     * @param frozen specify if the returned object can be frozen
+     * @return the specified <code>TimeZone</code> or UNKNOWN_ZONE if the given ID
+     * cannot be understood.
+     */
+    private static synchronized TimeZone getTimeZone(String ID, int type, boolean frozen) {
         TimeZone result;
         if (type == TIMEZONE_JDK) {
-            result = new JavaTimeZone(ID);
+            result = JavaTimeZone.createTimeZone(ID);
+            if (result != null) {
+                return frozen ? result.freeze() : result;
+            }
         } 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
@@ -658,20 +765,18 @@ abstract public class TimeZone implements Serializable, Cloneable {
                 throw new NullPointerException();
             }
             result = ZoneMeta.getSystemTimeZone(ID);
+        }
 
-            if (result == null) {
-                result = ZoneMeta.getCustomTimeZone(ID);
-            }
-            if (result == null) {
-                /* Log that timezone is using GMT if logging is on. */
-                if (TimeZoneLogger != null && TimeZoneLogger.isLoggingOn()) {
-                    TimeZoneLogger.warning(
-                        "\"" +ID + "\" is a bogus id so timezone is falling back to Etc/Unknown(GMT).");
-                }
-                result = new SimpleTimeZone(0, UNKNOWN_ZONE_ID);
-            }
+        if (result == null) {
+            result = ZoneMeta.getCustomTimeZone(ID);
         }
-        return result;
+
+        if (result == null) {
+            LOGGER.fine("\"" +ID + "\" is a bogus id so timezone is falling back to Etc/Unknown(GMT).");
+            result = UNKNOWN_ZONE;
+        }
+
+        return frozen ? result : result.cloneAsThawed();
     }
 
     /**
@@ -709,8 +814,7 @@ abstract public class TimeZone implements Serializable, Cloneable {
      * @return an immutable set of system time zone IDs.
      * @see SystemTimeZoneType
      * 
-     * @draft ICU 4.8
-     * @provisional This API might change or be removed in a future release.
+     * @stable ICU 4.8
      */ 
     public static Set<String> getAvailableIDs(SystemTimeZoneType zoneType,
             String region, Integer rawOffset) {
@@ -821,10 +925,10 @@ abstract public class TimeZone implements Serializable, Cloneable {
                 defaultZone = new JavaTimeZone();
             } else {
                 java.util.TimeZone temp = java.util.TimeZone.getDefault();
-                defaultZone = getTimeZone(temp.getID());
+                defaultZone = getFrozenTimeZone(temp.getID());
             }
         }
-        return (TimeZone) defaultZone.clone();
+        return defaultZone.cloneAsThawed();
     }
 
     /**
@@ -889,13 +993,10 @@ abstract public class TimeZone implements Serializable, Cloneable {
      * @stable ICU 2.0
      */
     public Object clone() {
-        try {
-            TimeZone other = (TimeZone) super.clone();
-            other.ID = ID;
-            return other;
-        } catch (CloneNotSupportedException e) {
-            throw new IllegalStateException();
+        if (isFrozen()) {
+            return this;
         }
+        return cloneAsThawed();
     }
 
     /**
@@ -996,8 +1097,7 @@ abstract public class TimeZone implements Serializable, Cloneable {
      * @throws IllegalArgumentException if <code>id</code> is not a known system ID. 
      * @see #getAvailableIDs(String) 
      * 
-     * @draft ICU 4.8
-     * @provisional This API might change or be removed in a future release.
+     * @stable ICU 4.8
      */ 
     public static String getRegion(String id) {
         String region = null;
@@ -1013,6 +1113,153 @@ abstract public class TimeZone implements Serializable, Cloneable {
         return region;
     }
 
+    /**
+     * {@icu} Converts a system time zone ID to an equivalent Windows time zone ID. For example,
+     * Windows time zone ID "Pacific Standard Time" is returned for input "America/Los_Angeles".
+     * 
+     * <p>There are system time zones that cannot be mapped to Windows zones. When the input
+     * system time zone ID is unknown or unmappable to a Windows time zone, then this
+     * method returns <code>null</code>.
+     * 
+     * <p>This implementation utilizes <a href="http://unicode.org/cldr/charts/supplemental/zone_tzid.html">
+     * Zone-Tzid mapping data<a>. The mapping data is updated time to time. To get the latest changes,
+     * please read the ICU user guide section <a href="http://userguide.icu-project.org/datetime/timezone#TOC-Updating-the-Time-Zone-Data">
+     * Updating the Time Zone Data</a>.
+     * 
+     * @param id A system time zone ID
+     * @return A Windows time zone ID mapped from the input system time zone ID,
+     * or <code>null</code> when the input ID is unknown or unmappable.
+     * @see #getIDForWindowsID(String, String)
+     * 
+     * @draft ICU 52
+     * @provisional This API might change or be removed in a future release.
+     */
+    public static String getWindowsID(String id) {
+        // canonicalize the input ID
+        boolean[] isSystemID = {false};
+        id = getCanonicalID(id, isSystemID);
+        if (!isSystemID[0]) {
+            // mapping data is only applicable to tz database IDs
+            return null; 
+        }
+
+        UResourceBundle top = UResourceBundle.getBundleInstance(
+                ICUResourceBundle.ICU_BASE_NAME, "windowsZones", ICUResourceBundle.ICU_DATA_CLASS_LOADER);
+        UResourceBundle mapTimezones = top.get("mapTimezones");
+
+        UResourceBundleIterator resitr = mapTimezones.getIterator();
+        while (resitr.hasNext()) {
+            UResourceBundle winzone = resitr.next();
+            if (winzone.getType() != UResourceBundle.TABLE) {
+                continue;
+            }
+            UResourceBundleIterator rgitr = winzone.getIterator();
+            while (rgitr.hasNext()) {
+                UResourceBundle regionalData = rgitr.next();
+                if (regionalData.getType() != UResourceBundle.STRING) {
+                    continue;
+                }
+                String[] tzids = regionalData.getString().split(" ");
+                for (String tzid : tzids) {
+                    if (tzid.equals(id)) {
+                        return winzone.getKey();
+                    }
+                }
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * {@icu} Converts a Windows time zone ID to an equivalent system time zone ID
+     * for a region. For example, system time zone ID "America/Los_Angeles" is returned 
+     * for input Windows ID "Pacific Standard Time" and region "US" (or <code>null</code>),
+     * "America/Vancouver" is returned for the same Windows ID "Pacific Standard Time" and
+     * region "CA".
+     * 
+     * <p>Not all Windows time zones can be mapped to system time zones. When the input
+     * Windows time zone ID is unknown or unmappable to a system time zone, then this
+     * method returns <code>null</code>.
+     *
+     * <p>This implementation utilizes <a href="http://unicode.org/cldr/charts/supplemental/zone_tzid.html">
+     * Zone-Tzid mapping data<a>. The mapping data is updated time to time. To get the latest changes,
+     * please read the ICU user guide section <a href="http://userguide.icu-project.org/datetime/timezone#TOC-Updating-the-Time-Zone-Data">
+     * Updating the Time Zone Data</a>.
+     *
+     * @param winid A Windows time zone ID
+     * @param region A region code, or <code>null</code> if no regional preference.
+     * @return A system time zone ID mapped from the input Windows time zone ID,
+     * or <code>null</code> when the input ID is unknown or unmappable.
+     * @see #getWindowsID(String)
+     * 
+     * @draft ICU 52
+     * @provisional This API might change or be removed in a future release.
+     */
+    public static String getIDForWindowsID(String winid, String region) {
+        String id = null;
+
+        UResourceBundle top = UResourceBundle.getBundleInstance(
+                ICUResourceBundle.ICU_BASE_NAME, "windowsZones", ICUResourceBundle.ICU_DATA_CLASS_LOADER);
+        UResourceBundle mapTimezones = top.get("mapTimezones");
+
+        try {
+            UResourceBundle zones = mapTimezones.get(winid);
+            if (region != null) {
+                try {
+                    id = zones.getString(region);
+                    if (id != null) {
+                        // first ID delimited by space is the default one
+                        int endIdx = id.indexOf(' ');
+                        if (endIdx > 0) {
+                            id = id.substring(0, endIdx);
+                        }
+                    }
+                } catch (MissingResourceException e) {
+                    // no explicit region mapping found
+                }
+            }
+            if (id == null) {
+                id = zones.getString("001");
+            }
+        } catch (MissingResourceException e) {
+            // no mapping data found
+        }
+
+        return id;
+    }
+
+    // Freezable stuffs
+
+    /**
+     * {@inheritDoc}
+     * @stable ICU 49
+     */
+    public boolean isFrozen() {
+        return false;
+    }
+
+    /**
+     * {@inheritDoc}
+     * @stable ICU 49
+     */
+    public TimeZone freeze() {
+        throw new UnsupportedOperationException("Needs to be implemented by the subclass.");
+    }
+
+    /**
+     * {@inheritDoc}
+     * @stable ICU 49
+     */
+    public TimeZone cloneAsThawed() {
+        try {
+            TimeZone other = (TimeZone) super.clone();
+            return other;
+        } catch (CloneNotSupportedException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
     // =======================privates===============================
 
     /**