Home » openjdk-7 » java » util » [javadoc | source]

    1   /*
    2    * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved.
    3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    4    *
    5    * This code is free software; you can redistribute it and/or modify it
    6    * under the terms of the GNU General Public License version 2 only, as
    7    * published by the Free Software Foundation.  Oracle designates this
    8    * particular file as subject to the "Classpath" exception as provided
    9    * by Oracle in the LICENSE file that accompanied this code.
   10    *
   11    * This code is distributed in the hope that it will be useful, but WITHOUT
   12    * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   13    * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   14    * version 2 for more details (a copy is included in the LICENSE file that
   15    * accompanied this code).
   16    *
   17    * You should have received a copy of the GNU General Public License version
   18    * 2 along with this work; if not, write to the Free Software Foundation,
   19    * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   20    *
   21    * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   22    * or visit www.oracle.com if you need additional information or have any
   23    * questions.
   24    */
   25   
   26   /*
   27    * (C) Copyright Taligent, Inc. 1996 - All Rights Reserved
   28    * (C) Copyright IBM Corp. 1996 - All Rights Reserved
   29    *
   30    *   The original version of this source code and documentation is copyrighted
   31    * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
   32    * materials are provided under terms of a License Agreement between Taligent
   33    * and Sun. This technology is protected by multiple US and International
   34    * patents. This notice and attribution to Taligent may not be removed.
   35    *   Taligent is a registered trademark of Taligent, Inc.
   36    *
   37    */
   38   
   39   package java.util;
   40   
   41   import java.io.Serializable;
   42   import java.lang.ref.SoftReference;
   43   import java.security.AccessController;
   44   import java.security.PrivilegedAction;
   45   import java.util.concurrent.ConcurrentHashMap;
   46   import sun.security.action.GetPropertyAction;
   47   import sun.util.TimeZoneNameUtility;
   48   import sun.util.calendar.ZoneInfo;
   49   import sun.util.calendar.ZoneInfoFile;
   50   
   51   /**
   52    * <code>TimeZone</code> represents a time zone offset, and also figures out daylight
   53    * savings.
   54    *
   55    * <p>
   56    * Typically, you get a <code>TimeZone</code> using <code>getDefault</code>
   57    * which creates a <code>TimeZone</code> based on the time zone where the program
   58    * is running. For example, for a program running in Japan, <code>getDefault</code>
   59    * creates a <code>TimeZone</code> object based on Japanese Standard Time.
   60    *
   61    * <p>
   62    * You can also get a <code>TimeZone</code> using <code>getTimeZone</code>
   63    * along with a time zone ID. For instance, the time zone ID for the
   64    * U.S. Pacific Time zone is "America/Los_Angeles". So, you can get a
   65    * U.S. Pacific Time <code>TimeZone</code> object with:
   66    * <blockquote><pre>
   67    * TimeZone tz = TimeZone.getTimeZone("America/Los_Angeles");
   68    * </pre></blockquote>
   69    * You can use the <code>getAvailableIDs</code> method to iterate through
   70    * all the supported time zone IDs. You can then choose a
   71    * supported ID to get a <code>TimeZone</code>.
   72    * If the time zone you want is not represented by one of the
   73    * supported IDs, then a custom time zone ID can be specified to
   74    * produce a TimeZone. The syntax of a custom time zone ID is:
   75    *
   76    * <blockquote><pre>
   77    * <a name="CustomID"><i>CustomID:</i></a>
   78    *         <code>GMT</code> <i>Sign</i> <i>Hours</i> <code>:</code> <i>Minutes</i>
   79    *         <code>GMT</code> <i>Sign</i> <i>Hours</i> <i>Minutes</i>
   80    *         <code>GMT</code> <i>Sign</i> <i>Hours</i>
   81    * <i>Sign:</i> one of
   82    *         <code>+ -</code>
   83    * <i>Hours:</i>
   84    *         <i>Digit</i>
   85    *         <i>Digit</i> <i>Digit</i>
   86    * <i>Minutes:</i>
   87    *         <i>Digit</i> <i>Digit</i>
   88    * <i>Digit:</i> one of
   89    *         <code>0 1 2 3 4 5 6 7 8 9</code>
   90    * </pre></blockquote>
   91    *
   92    * <i>Hours</i> must be between 0 to 23 and <i>Minutes</i> must be
   93    * between 00 to 59.  For example, "GMT+10" and "GMT+0010" mean ten
   94    * hours and ten minutes ahead of GMT, respectively.
   95    * <p>
   96    * The format is locale independent and digits must be taken from the
   97    * Basic Latin block of the Unicode standard. No daylight saving time
   98    * transition schedule can be specified with a custom time zone ID. If
   99    * the specified string doesn't match the syntax, <code>"GMT"</code>
  100    * is used.
  101    * <p>
  102    * When creating a <code>TimeZone</code>, the specified custom time
  103    * zone ID is normalized in the following syntax:
  104    * <blockquote><pre>
  105    * <a name="NormalizedCustomID"><i>NormalizedCustomID:</i></a>
  106    *         <code>GMT</code> <i>Sign</i> <i>TwoDigitHours</i> <code>:</code> <i>Minutes</i>
  107    * <i>Sign:</i> one of
  108    *         <code>+ -</code>
  109    * <i>TwoDigitHours:</i>
  110    *         <i>Digit</i> <i>Digit</i>
  111    * <i>Minutes:</i>
  112    *         <i>Digit</i> <i>Digit</i>
  113    * <i>Digit:</i> one of
  114    *         <code>0 1 2 3 4 5 6 7 8 9</code>
  115    * </pre></blockquote>
  116    * For example, TimeZone.getTimeZone("GMT-8").getID() returns "GMT-08:00".
  117    *
  118    * <h4>Three-letter time zone IDs</h4>
  119    *
  120    * For compatibility with JDK 1.1.x, some other three-letter time zone IDs
  121    * (such as "PST", "CTT", "AST") are also supported. However, <strong>their
  122    * use is deprecated</strong> because the same abbreviation is often used
  123    * for multiple time zones (for example, "CST" could be U.S. "Central Standard
  124    * Time" and "China Standard Time"), and the Java platform can then only
  125    * recognize one of them.
  126    *
  127    *
  128    * @see          Calendar
  129    * @see          GregorianCalendar
  130    * @see          SimpleTimeZone
  131    * @author       Mark Davis, David Goldsmith, Chen-Lieh Huang, Alan Liu
  132    * @since        JDK1.1
  133    */
  134   abstract public class TimeZone implements Serializable, Cloneable {
  135       /**
  136        * Sole constructor.  (For invocation by subclass constructors, typically
  137        * implicit.)
  138        */
  139       public TimeZone() {
  140       }
  141   
  142       /**
  143        * A style specifier for <code>getDisplayName()</code> indicating
  144        * a short name, such as "PST."
  145        * @see #LONG
  146        * @since 1.2
  147        */
  148       public static final int SHORT = 0;
  149   
  150       /**
  151        * A style specifier for <code>getDisplayName()</code> indicating
  152        * a long name, such as "Pacific Standard Time."
  153        * @see #SHORT
  154        * @since 1.2
  155        */
  156       public static final int LONG  = 1;
  157   
  158       // Constants used internally; unit is milliseconds
  159       private static final int ONE_MINUTE = 60*1000;
  160       private static final int ONE_HOUR   = 60*ONE_MINUTE;
  161       private static final int ONE_DAY    = 24*ONE_HOUR;
  162   
  163       // Proclaim serialization compatibility with JDK 1.1
  164       static final long serialVersionUID = 3581463369166924961L;
  165   
  166       /**
  167        * Gets the time zone offset, for current date, modified in case of
  168        * daylight savings. This is the offset to add to UTC to get local time.
  169        * <p>
  170        * This method returns a historically correct offset if an
  171        * underlying <code>TimeZone</code> implementation subclass
  172        * supports historical Daylight Saving Time schedule and GMT
  173        * offset changes.
  174        *
  175        * @param era the era of the given date.
  176        * @param year the year in the given date.
  177        * @param month the month in the given date.
  178        * Month is 0-based. e.g., 0 for January.
  179        * @param day the day-in-month of the given date.
  180        * @param dayOfWeek the day-of-week of the given date.
  181        * @param milliseconds the milliseconds in day in <em>standard</em>
  182        * local time.
  183        *
  184        * @return the offset in milliseconds to add to GMT to get local time.
  185        *
  186        * @see Calendar#ZONE_OFFSET
  187        * @see Calendar#DST_OFFSET
  188        */
  189       public abstract int getOffset(int era, int year, int month, int day,
  190                                     int dayOfWeek, int milliseconds);
  191   
  192       /**
  193        * Returns the offset of this time zone from UTC at the specified
  194        * date. If Daylight Saving Time is in effect at the specified
  195        * date, the offset value is adjusted with the amount of daylight
  196        * saving.
  197        * <p>
  198        * This method returns a historically correct offset value if an
  199        * underlying TimeZone implementation subclass supports historical
  200        * Daylight Saving Time schedule and GMT offset changes.
  201        *
  202        * @param date the date represented in milliseconds since January 1, 1970 00:00:00 GMT
  203        * @return the amount of time in milliseconds to add to UTC to get local time.
  204        *
  205        * @see Calendar#ZONE_OFFSET
  206        * @see Calendar#DST_OFFSET
  207        * @since 1.4
  208        */
  209       public int getOffset(long date) {
  210           if (inDaylightTime(new Date(date))) {
  211               return getRawOffset() + getDSTSavings();
  212           }
  213           return getRawOffset();
  214       }
  215   
  216       /**
  217        * Gets the raw GMT offset and the amount of daylight saving of this
  218        * time zone at the given time.
  219        * @param date the milliseconds (since January 1, 1970,
  220        * 00:00:00.000 GMT) at which the time zone offset and daylight
  221        * saving amount are found
  222        * @param offset an array of int where the raw GMT offset
  223        * (offset[0]) and daylight saving amount (offset[1]) are stored,
  224        * or null if those values are not needed. The method assumes that
  225        * the length of the given array is two or larger.
  226        * @return the total amount of the raw GMT offset and daylight
  227        * saving at the specified date.
  228        *
  229        * @see Calendar#ZONE_OFFSET
  230        * @see Calendar#DST_OFFSET
  231        */
  232       int getOffsets(long date, int[] offsets) {
  233           int rawoffset = getRawOffset();
  234           int dstoffset = 0;
  235           if (inDaylightTime(new Date(date))) {
  236               dstoffset = getDSTSavings();
  237           }
  238           if (offsets != null) {
  239               offsets[0] = rawoffset;
  240               offsets[1] = dstoffset;
  241           }
  242           return rawoffset + dstoffset;
  243       }
  244   
  245       /**
  246        * Sets the base time zone offset to GMT.
  247        * This is the offset to add to UTC to get local time.
  248        * <p>
  249        * If an underlying <code>TimeZone</code> implementation subclass
  250        * supports historical GMT offset changes, the specified GMT
  251        * offset is set as the latest GMT offset and the difference from
  252        * the known latest GMT offset value is used to adjust all
  253        * historical GMT offset values.
  254        *
  255        * @param offsetMillis the given base time zone offset to GMT.
  256        */
  257       abstract public void setRawOffset(int offsetMillis);
  258   
  259       /**
  260        * Returns the amount of time in milliseconds to add to UTC to get
  261        * standard time in this time zone. Because this value is not
  262        * affected by daylight saving time, it is called <I>raw
  263        * offset</I>.
  264        * <p>
  265        * If an underlying <code>TimeZone</code> implementation subclass
  266        * supports historical GMT offset changes, the method returns the
  267        * raw offset value of the current date. In Honolulu, for example,
  268        * its raw offset changed from GMT-10:30 to GMT-10:00 in 1947, and
  269        * this method always returns -36000000 milliseconds (i.e., -10
  270        * hours).
  271        *
  272        * @return the amount of raw offset time in milliseconds to add to UTC.
  273        * @see Calendar#ZONE_OFFSET
  274        */
  275       public abstract int getRawOffset();
  276   
  277       /**
  278        * Gets the ID of this time zone.
  279        * @return the ID of this time zone.
  280        */
  281       public String getID()
  282       {
  283           return ID;
  284       }
  285   
  286       /**
  287        * Sets the time zone ID. This does not change any other data in
  288        * the time zone object.
  289        * @param ID the new time zone ID.
  290        */
  291       public void setID(String ID)
  292       {
  293           if (ID == null) {
  294               throw new NullPointerException();
  295           }
  296           this.ID = ID;
  297       }
  298   
  299       /**
  300        * Returns a long standard time name of this {@code TimeZone} suitable for
  301        * presentation to the user in the default locale.
  302        *
  303        * <p>This method is equivalent to:
  304        * <pre><blockquote>
  305        * getDisplayName(false, {@link #LONG},
  306        *                Locale.getDefault({@link Locale.Category#DISPLAY}))
  307        * </blockquote></pre>
  308        *
  309        * @return the human-readable name of this time zone in the default locale.
  310        * @since 1.2
  311        * @see #getDisplayName(boolean, int, Locale)
  312        * @see Locale#getDefault(Locale.Category)
  313        * @see Locale.Category
  314        */
  315       public final String getDisplayName() {
  316           return getDisplayName(false, LONG,
  317                                 Locale.getDefault(Locale.Category.DISPLAY));
  318       }
  319   
  320       /**
  321        * Returns a long standard time name of this {@code TimeZone} suitable for
  322        * presentation to the user in the specified {@code locale}.
  323        *
  324        * <p>This method is equivalent to:
  325        * <pre><blockquote>
  326        * getDisplayName(false, {@link #LONG}, locale)
  327        * </blockquote></pre>
  328        *
  329        * @param locale the locale in which to supply the display name.
  330        * @return the human-readable name of this time zone in the given locale.
  331        * @exception NullPointerException if {@code locale} is {@code null}.
  332        * @since 1.2
  333        * @see #getDisplayName(boolean, int, Locale)
  334        */
  335       public final String getDisplayName(Locale locale) {
  336           return getDisplayName(false, LONG, locale);
  337       }
  338   
  339       /**
  340        * Returns a name in the specified {@code style} of this {@code TimeZone}
  341        * suitable for presentation to the user in the default locale. If the
  342        * specified {@code daylight} is {@code true}, a Daylight Saving Time name
  343        * is returned (even if this {@code TimeZone} doesn't observe Daylight Saving
  344        * Time). Otherwise, a Standard Time name is returned.
  345        *
  346        * <p>This method is equivalent to:
  347        * <pre><blockquote>
  348        * getDisplayName(daylight, style,
  349        *                Locale.getDefault({@link Locale.Category#DISPLAY}))
  350        * </blockquote></pre>
  351        *
  352        * @param daylight {@code true} specifying a Daylight Saving Time name, or
  353        *                 {@code false} specifying a Standard Time name
  354        * @param style either {@link #LONG} or {@link #SHORT}
  355        * @return the human-readable name of this time zone in the default locale.
  356        * @exception IllegalArgumentException if {@code style} is invalid.
  357        * @since 1.2
  358        * @see #getDisplayName(boolean, int, Locale)
  359        * @see Locale#getDefault(Locale.Category)
  360        * @see Locale.Category
  361        * @see java.text.DateFormatSymbols#getZoneStrings()
  362        */
  363       public final String getDisplayName(boolean daylight, int style) {
  364           return getDisplayName(daylight, style,
  365                                 Locale.getDefault(Locale.Category.DISPLAY));
  366       }
  367   
  368       /**
  369        * Returns a name in the specified {@code style} of this {@code TimeZone}
  370        * suitable for presentation to the user in the specified {@code
  371        * locale}. If the specified {@code daylight} is {@code true}, a Daylight
  372        * Saving Time name is returned (even if this {@code TimeZone} doesn't
  373        * observe Daylight Saving Time). Otherwise, a Standard Time name is
  374        * returned.
  375        *
  376        * <p>When looking up a time zone name, the {@linkplain
  377        * ResourceBundle.Control#getCandidateLocales(String,Locale) default
  378        * <code>Locale</code> search path of <code>ResourceBundle</code>} derived
  379        * from the specified {@code locale} is used. (No {@linkplain
  380        * ResourceBundle.Control#getFallbackLocale(String,Locale) fallback
  381        * <code>Locale</code>} search is performed.) If a time zone name in any
  382        * {@code Locale} of the search path, including {@link Locale#ROOT}, is
  383        * found, the name is returned. Otherwise, a string in the
  384        * <a href="#NormalizedCustomID">normalized custom ID format</a> is returned.
  385        *
  386        * @param daylight {@code true} specifying a Daylight Saving Time name, or
  387        *                 {@code false} specifying a Standard Time name
  388        * @param style either {@link #LONG} or {@link #SHORT}
  389        * @param locale   the locale in which to supply the display name.
  390        * @return the human-readable name of this time zone in the given locale.
  391        * @exception IllegalArgumentException if {@code style} is invalid.
  392        * @exception NullPointerException if {@code locale} is {@code null}.
  393        * @since 1.2
  394        * @see java.text.DateFormatSymbols#getZoneStrings()
  395        */
  396       public String getDisplayName(boolean daylight, int style, Locale locale) {
  397           if (style != SHORT && style != LONG) {
  398               throw new IllegalArgumentException("Illegal style: " + style);
  399           }
  400   
  401           String id = getID();
  402           String[] names = getDisplayNames(id, locale);
  403           if (names == null) {
  404               if (id.startsWith("GMT")) {
  405                   char sign = id.charAt(3);
  406                   if (sign == '+' || sign == '-') {
  407                       return id;
  408                   }
  409               }
  410               int offset = getRawOffset();
  411               if (daylight) {
  412                   offset += getDSTSavings();
  413               }
  414               return ZoneInfoFile.toCustomID(offset);
  415           }
  416   
  417           int index = daylight ? 3 : 1;
  418           if (style == SHORT) {
  419               index++;
  420           }
  421           return names[index];
  422       }
  423   
  424       private static class DisplayNames {
  425           // Cache for managing display names per timezone per locale
  426           // The structure is:
  427           //   Map(key=id, value=SoftReference(Map(key=locale, value=displaynames)))
  428           private static final Map<String, SoftReference<Map<Locale, String[]>>> CACHE =
  429               new ConcurrentHashMap<String, SoftReference<Map<Locale, String[]>>>();
  430       }
  431   
  432       private static final String[] getDisplayNames(String id, Locale locale) {
  433           Map<String, SoftReference<Map<Locale, String[]>>> displayNames = DisplayNames.CACHE;
  434   
  435           SoftReference<Map<Locale, String[]>> ref = displayNames.get(id);
  436           if (ref != null) {
  437               Map<Locale, String[]> perLocale = ref.get();
  438               if (perLocale != null) {
  439                   String[] names = perLocale.get(locale);
  440                   if (names != null) {
  441                       return names;
  442                   }
  443                   names = TimeZoneNameUtility.retrieveDisplayNames(id, locale);
  444                   if (names != null) {
  445                       perLocale.put(locale, names);
  446                   }
  447                   return names;
  448               }
  449           }
  450   
  451           String[] names = TimeZoneNameUtility.retrieveDisplayNames(id, locale);
  452           if (names != null) {
  453               Map<Locale, String[]> perLocale = new ConcurrentHashMap<Locale, String[]>();
  454               perLocale.put(locale, names);
  455               ref = new SoftReference<Map<Locale, String[]>>(perLocale);
  456               displayNames.put(id, ref);
  457           }
  458           return names;
  459       }
  460   
  461       /**
  462        * Returns the amount of time to be added to local standard time
  463        * to get local wall clock time.
  464        *
  465        * <p>The default implementation returns 3600000 milliseconds
  466        * (i.e., one hour) if a call to {@link #useDaylightTime()}
  467        * returns {@code true}. Otherwise, 0 (zero) is returned.
  468        *
  469        * <p>If an underlying {@code TimeZone} implementation subclass
  470        * supports historical and future Daylight Saving Time schedule
  471        * changes, this method returns the amount of saving time of the
  472        * last known Daylight Saving Time rule that can be a future
  473        * prediction.
  474        *
  475        * <p>If the amount of saving time at any given time stamp is
  476        * required, construct a {@link Calendar} with this {@code
  477        * TimeZone} and the time stamp, and call {@link Calendar#get(int)
  478        * Calendar.get}{@code (}{@link Calendar#DST_OFFSET}{@code )}.
  479        *
  480        * @return the amount of saving time in milliseconds
  481        * @since 1.4
  482        * @see #inDaylightTime(Date)
  483        * @see #getOffset(long)
  484        * @see #getOffset(int,int,int,int,int,int)
  485        * @see Calendar#ZONE_OFFSET
  486        */
  487       public int getDSTSavings() {
  488           if (useDaylightTime()) {
  489               return 3600000;
  490           }
  491           return 0;
  492       }
  493   
  494       /**
  495        * Queries if this {@code TimeZone} uses Daylight Saving Time.
  496        *
  497        * <p>If an underlying {@code TimeZone} implementation subclass
  498        * supports historical and future Daylight Saving Time schedule
  499        * changes, this method refers to the last known Daylight Saving Time
  500        * rule that can be a future prediction and may not be the same as
  501        * the current rule. Consider calling {@link #observesDaylightTime()}
  502        * if the current rule should also be taken into account.
  503        *
  504        * @return {@code true} if this {@code TimeZone} uses Daylight Saving Time,
  505        *         {@code false}, otherwise.
  506        * @see #inDaylightTime(Date)
  507        * @see Calendar#DST_OFFSET
  508        */
  509       public abstract boolean useDaylightTime();
  510   
  511       /**
  512        * Returns {@code true} if this {@code TimeZone} is currently in
  513        * Daylight Saving Time, or if a transition from Standard Time to
  514        * Daylight Saving Time occurs at any future time.
  515        *
  516        * <p>The default implementation returns {@code true} if
  517        * {@code useDaylightTime()} or {@code inDaylightTime(new Date())}
  518        * returns {@code true}.
  519        *
  520        * @return {@code true} if this {@code TimeZone} is currently in
  521        * Daylight Saving Time, or if a transition from Standard Time to
  522        * Daylight Saving Time occurs at any future time; {@code false}
  523        * otherwise.
  524        * @since 1.7
  525        * @see #useDaylightTime()
  526        * @see #inDaylightTime(Date)
  527        * @see Calendar#DST_OFFSET
  528        */
  529       public boolean observesDaylightTime() {
  530           return useDaylightTime() || inDaylightTime(new Date());
  531       }
  532   
  533       /**
  534        * Queries if the given {@code date} is in Daylight Saving Time in
  535        * this time zone.
  536        *
  537        * @param date the given Date.
  538        * @return {@code true} if the given date is in Daylight Saving Time,
  539        *         {@code false}, otherwise.
  540        */
  541       abstract public boolean inDaylightTime(Date date);
  542   
  543       /**
  544        * Gets the <code>TimeZone</code> for the given ID.
  545        *
  546        * @param ID the ID for a <code>TimeZone</code>, either an abbreviation
  547        * such as "PST", a full name such as "America/Los_Angeles", or a custom
  548        * ID such as "GMT-8:00". Note that the support of abbreviations is
  549        * for JDK 1.1.x compatibility only and full names should be used.
  550        *
  551        * @return the specified <code>TimeZone</code>, or the GMT zone if the given ID
  552        * cannot be understood.
  553        */
  554       public static synchronized TimeZone getTimeZone(String ID) {
  555           return getTimeZone(ID, true);
  556       }
  557   
  558       private static TimeZone getTimeZone(String ID, boolean fallback) {
  559           TimeZone tz = ZoneInfo.getTimeZone(ID);
  560           if (tz == null) {
  561               tz = parseCustomTimeZone(ID);
  562               if (tz == null && fallback) {
  563                   tz = new ZoneInfo(GMT_ID, 0);
  564               }
  565           }
  566           return tz;
  567       }
  568   
  569       /**
  570        * Gets the available IDs according to the given time zone offset in milliseconds.
  571        *
  572        * @param rawOffset the given time zone GMT offset in milliseconds.
  573        * @return an array of IDs, where the time zone for that ID has
  574        * the specified GMT offset. For example, "America/Phoenix" and "America/Denver"
  575        * both have GMT-07:00, but differ in daylight saving behavior.
  576        * @see #getRawOffset()
  577        */
  578       public static synchronized String[] getAvailableIDs(int rawOffset) {
  579           return ZoneInfo.getAvailableIDs(rawOffset);
  580       }
  581   
  582       /**
  583        * Gets all the available IDs supported.
  584        * @return an array of IDs.
  585        */
  586       public static synchronized String[] getAvailableIDs() {
  587           return ZoneInfo.getAvailableIDs();
  588       }
  589   
  590       /**
  591        * Gets the platform defined TimeZone ID.
  592        **/
  593       private static native String getSystemTimeZoneID(String javaHome,
  594                                                        String country);
  595   
  596       /**
  597        * Gets the custom time zone ID based on the GMT offset of the
  598        * platform. (e.g., "GMT+08:00")
  599        */
  600       private static native String getSystemGMTOffsetID();
  601   
  602       /**
  603        * Gets the default <code>TimeZone</code> for this host.
  604        * The source of the default <code>TimeZone</code>
  605        * may vary with implementation.
  606        * @return a default <code>TimeZone</code>.
  607        * @see #setDefault
  608        */
  609       public static TimeZone getDefault() {
  610           return (TimeZone) getDefaultRef().clone();
  611       }
  612   
  613       /**
  614        * Returns the reference to the default TimeZone object. This
  615        * method doesn't create a clone.
  616        */
  617       static TimeZone getDefaultRef() {
  618           TimeZone defaultZone = defaultZoneTL.get();
  619           if (defaultZone == null) {
  620               defaultZone = defaultTimeZone;
  621               if (defaultZone == null) {
  622                   // Need to initialize the default time zone.
  623                   defaultZone = setDefaultZone();
  624                   assert defaultZone != null;
  625               }
  626           }
  627           // Don't clone here.
  628           return defaultZone;
  629       }
  630   
  631       private static synchronized TimeZone setDefaultZone() {
  632           TimeZone tz = null;
  633           // get the time zone ID from the system properties
  634           String zoneID = AccessController.doPrivileged(
  635                   new GetPropertyAction("user.timezone"));
  636   
  637           // if the time zone ID is not set (yet), perform the
  638           // platform to Java time zone ID mapping.
  639           if (zoneID == null || zoneID.equals("")) {
  640               String country = AccessController.doPrivileged(
  641                       new GetPropertyAction("user.country"));
  642               String javaHome = AccessController.doPrivileged(
  643                       new GetPropertyAction("java.home"));
  644               try {
  645                   zoneID = getSystemTimeZoneID(javaHome, country);
  646                   if (zoneID == null) {
  647                       zoneID = GMT_ID;
  648                   }
  649               } catch (NullPointerException e) {
  650                   zoneID = GMT_ID;
  651               }
  652           }
  653   
  654           // Get the time zone for zoneID. But not fall back to
  655           // "GMT" here.
  656           tz = getTimeZone(zoneID, false);
  657   
  658           if (tz == null) {
  659               // If the given zone ID is unknown in Java, try to
  660               // get the GMT-offset-based time zone ID,
  661               // a.k.a. custom time zone ID (e.g., "GMT-08:00").
  662               String gmtOffsetID = getSystemGMTOffsetID();
  663               if (gmtOffsetID != null) {
  664                   zoneID = gmtOffsetID;
  665               }
  666               tz = getTimeZone(zoneID, true);
  667           }
  668           assert tz != null;
  669   
  670           final String id = zoneID;
  671           AccessController.doPrivileged(new PrivilegedAction<Object>() {
  672                   public Object run() {
  673                       System.setProperty("user.timezone", id);
  674                       return null;
  675                   }
  676               });
  677   
  678           defaultTimeZone = tz;
  679           return tz;
  680       }
  681   
  682       private static boolean hasPermission() {
  683           boolean hasPermission = true;
  684           SecurityManager sm = System.getSecurityManager();
  685           if (sm != null) {
  686               try {
  687                   sm.checkPermission(new PropertyPermission
  688                                      ("user.timezone", "write"));
  689               } catch (SecurityException e) {
  690                   hasPermission = false;
  691               }
  692           }
  693           return hasPermission;
  694       }
  695   
  696       /**
  697        * Sets the <code>TimeZone</code> that is
  698        * returned by the <code>getDefault</code> method.  If <code>zone</code>
  699        * is null, reset the default to the value it had originally when the
  700        * VM first started.
  701        * @param zone the new default time zone
  702        * @see #getDefault
  703        */
  704       public static void setDefault(TimeZone zone)
  705       {
  706           if (hasPermission()) {
  707               synchronized (TimeZone.class) {
  708                   defaultTimeZone = zone;
  709                   defaultZoneTL.set(null);
  710               }
  711           } else {
  712               defaultZoneTL.set(zone);
  713           }
  714       }
  715   
  716       /**
  717        * Returns true if this zone has the same rule and offset as another zone.
  718        * That is, if this zone differs only in ID, if at all.  Returns false
  719        * if the other zone is null.
  720        * @param other the <code>TimeZone</code> object to be compared with
  721        * @return true if the other zone is not null and is the same as this one,
  722        * with the possible exception of the ID
  723        * @since 1.2
  724        */
  725       public boolean hasSameRules(TimeZone other) {
  726           return other != null && getRawOffset() == other.getRawOffset() &&
  727               useDaylightTime() == other.useDaylightTime();
  728       }
  729   
  730       /**
  731        * Creates a copy of this <code>TimeZone</code>.
  732        *
  733        * @return a clone of this <code>TimeZone</code>
  734        */
  735       public Object clone()
  736       {
  737           try {
  738               TimeZone other = (TimeZone) super.clone();
  739               other.ID = ID;
  740               return other;
  741           } catch (CloneNotSupportedException e) {
  742               throw new InternalError();
  743           }
  744       }
  745   
  746       /**
  747        * The null constant as a TimeZone.
  748        */
  749       static final TimeZone NO_TIMEZONE = null;
  750   
  751       // =======================privates===============================
  752   
  753       /**
  754        * The string identifier of this <code>TimeZone</code>.  This is a
  755        * programmatic identifier used internally to look up <code>TimeZone</code>
  756        * objects from the system table and also to map them to their localized
  757        * display names.  <code>ID</code> values are unique in the system
  758        * table but may not be for dynamically created zones.
  759        * @serial
  760        */
  761       private String           ID;
  762       private static volatile TimeZone defaultTimeZone;
  763       private static final InheritableThreadLocal<TimeZone> defaultZoneTL
  764                                           = new InheritableThreadLocal<TimeZone>();
  765   
  766       static final String         GMT_ID        = "GMT";
  767       private static final int    GMT_ID_LENGTH = 3;
  768   
  769       /**
  770        * Parses a custom time zone identifier and returns a corresponding zone.
  771        * This method doesn't support the RFC 822 time zone format. (e.g., +hhmm)
  772        *
  773        * @param id a string of the <a href="#CustomID">custom ID form</a>.
  774        * @return a newly created TimeZone with the given offset and
  775        * no daylight saving time, or null if the id cannot be parsed.
  776        */
  777       private static final TimeZone parseCustomTimeZone(String id) {
  778           int length;
  779   
  780           // Error if the length of id isn't long enough or id doesn't
  781           // start with "GMT".
  782           if ((length = id.length()) < (GMT_ID_LENGTH + 2) ||
  783               id.indexOf(GMT_ID) != 0) {
  784               return null;
  785           }
  786   
  787           ZoneInfo zi;
  788   
  789           // First, we try to find it in the cache with the given
  790           // id. Even the id is not normalized, the returned ZoneInfo
  791           // should have its normalized id.
  792           zi = ZoneInfoFile.getZoneInfo(id);
  793           if (zi != null) {
  794               return zi;
  795           }
  796   
  797           int index = GMT_ID_LENGTH;
  798           boolean negative = false;
  799           char c = id.charAt(index++);
  800           if (c == '-') {
  801               negative = true;
  802           } else if (c != '+') {
  803               return null;
  804           }
  805   
  806           int hours = 0;
  807           int num = 0;
  808           int countDelim = 0;
  809           int len = 0;
  810           while (index < length) {
  811               c = id.charAt(index++);
  812               if (c == ':') {
  813                   if (countDelim > 0) {
  814                       return null;
  815                   }
  816                   if (len > 2) {
  817                       return null;
  818                   }
  819                   hours = num;
  820                   countDelim++;
  821                   num = 0;
  822                   len = 0;
  823                   continue;
  824               }
  825               if (c < '0' || c > '9') {
  826                   return null;
  827               }
  828               num = num * 10 + (c - '0');
  829               len++;
  830           }
  831           if (index != length) {
  832               return null;
  833           }
  834           if (countDelim == 0) {
  835               if (len <= 2) {
  836                   hours = num;
  837                   num = 0;
  838               } else {
  839                   hours = num / 100;
  840                   num %= 100;
  841               }
  842           } else {
  843               if (len != 2) {
  844                   return null;
  845               }
  846           }
  847           if (hours > 23 || num > 59) {
  848               return null;
  849           }
  850           int gmtOffset =  (hours * 60 + num) * 60 * 1000;
  851   
  852           if (gmtOffset == 0) {
  853               zi = ZoneInfoFile.getZoneInfo(GMT_ID);
  854               if (negative) {
  855                   zi.setID("GMT-00:00");
  856               } else {
  857                   zi.setID("GMT+00:00");
  858               }
  859           } else {
  860               zi = ZoneInfoFile.getCustomTimeZone(id, negative ? -gmtOffset : gmtOffset);
  861           }
  862           return zi;
  863       }
  864   }

Home » openjdk-7 » java » util » [javadoc | source]