Save This Page
Home » openjdk-7 » java » util » [javadoc | source]
    1   /*
    2    * Copyright 1996-2005 Sun Microsystems, Inc.  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.  Sun designates this
    8    * particular file as subject to the "Classpath" exception as provided
    9    * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
   22    * CA 95054 USA or visit www.sun.com if you need additional information or
   23    * have any 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       /**
  164        * Cache to hold the SimpleDateFormat objects for a Locale.
  165        */
  166       private static Hashtable cachedLocaleData = new Hashtable(3);
  167   
  168       // Proclaim serialization compatibility with JDK 1.1
  169       static final long serialVersionUID = 3581463369166924961L;
  170   
  171       /**
  172        * Gets the time zone offset, for current date, modified in case of
  173        * daylight savings. This is the offset to add to UTC to get local time.
  174        * <p>
  175        * This method returns a historically correct offset if an
  176        * underlying <code>TimeZone</code> implementation subclass
  177        * supports historical Daylight Saving Time schedule and GMT
  178        * offset changes.
  179        *
  180        * @param era the era of the given date.
  181        * @param year the year in the given date.
  182        * @param month the month in the given date.
  183        * Month is 0-based. e.g., 0 for January.
  184        * @param day the day-in-month of the given date.
  185        * @param dayOfWeek the day-of-week of the given date.
  186        * @param milliseconds the milliseconds in day in <em>standard</em>
  187        * local time.
  188        *
  189        * @return the offset in milliseconds to add to GMT to get local time.
  190        *
  191        * @see Calendar#ZONE_OFFSET
  192        * @see Calendar#DST_OFFSET
  193        */
  194       public abstract int getOffset(int era, int year, int month, int day,
  195                                     int dayOfWeek, int milliseconds);
  196   
  197       /**
  198        * Returns the offset of this time zone from UTC at the specified
  199        * date. If Daylight Saving Time is in effect at the specified
  200        * date, the offset value is adjusted with the amount of daylight
  201        * saving.
  202        * <p>
  203        * This method returns a historically correct offset value if an
  204        * underlying TimeZone implementation subclass supports historical
  205        * Daylight Saving Time schedule and GMT offset changes.
  206        *
  207        * @param date the date represented in milliseconds since January 1, 1970 00:00:00 GMT
  208        * @return the amount of time in milliseconds to add to UTC to get local time.
  209        *
  210        * @see Calendar#ZONE_OFFSET
  211        * @see Calendar#DST_OFFSET
  212        * @since 1.4
  213        */
  214       public int getOffset(long date) {
  215           if (inDaylightTime(new Date(date))) {
  216               return getRawOffset() + getDSTSavings();
  217           }
  218           return getRawOffset();
  219       }
  220   
  221       /**
  222        * Gets the raw GMT offset and the amount of daylight saving of this
  223        * time zone at the given time.
  224        * @param date the milliseconds (since January 1, 1970,
  225        * 00:00:00.000 GMT) at which the time zone offset and daylight
  226        * saving amount are found
  227        * @param offset an array of int where the raw GMT offset
  228        * (offset[0]) and daylight saving amount (offset[1]) are stored,
  229        * or null if those values are not needed. The method assumes that
  230        * the length of the given array is two or larger.
  231        * @return the total amount of the raw GMT offset and daylight
  232        * saving at the specified date.
  233        *
  234        * @see Calendar#ZONE_OFFSET
  235        * @see Calendar#DST_OFFSET
  236        */
  237       int getOffsets(long date, int[] offsets) {
  238           int rawoffset = getRawOffset();
  239           int dstoffset = 0;
  240           if (inDaylightTime(new Date(date))) {
  241               dstoffset = getDSTSavings();
  242           }
  243           if (offsets != null) {
  244               offsets[0] = rawoffset;
  245               offsets[1] = dstoffset;
  246           }
  247           return rawoffset + dstoffset;
  248       }
  249   
  250       /**
  251        * Sets the base time zone offset to GMT.
  252        * This is the offset to add to UTC to get local time.
  253        * <p>
  254        * If an underlying <code>TimeZone</code> implementation subclass
  255        * supports historical GMT offset changes, the specified GMT
  256        * offset is set as the latest GMT offset and the difference from
  257        * the known latest GMT offset value is used to adjust all
  258        * historical GMT offset values.
  259        *
  260        * @param offsetMillis the given base time zone offset to GMT.
  261        */
  262       abstract public void setRawOffset(int offsetMillis);
  263   
  264       /**
  265        * Returns the amount of time in milliseconds to add to UTC to get
  266        * standard time in this time zone. Because this value is not
  267        * affected by daylight saving time, it is called <I>raw
  268        * offset</I>.
  269        * <p>
  270        * If an underlying <code>TimeZone</code> implementation subclass
  271        * supports historical GMT offset changes, the method returns the
  272        * raw offset value of the current date. In Honolulu, for example,
  273        * its raw offset changed from GMT-10:30 to GMT-10:00 in 1947, and
  274        * this method always returns -36000000 milliseconds (i.e., -10
  275        * hours).
  276        *
  277        * @return the amount of raw offset time in milliseconds to add to UTC.
  278        * @see Calendar#ZONE_OFFSET
  279        */
  280       public abstract int getRawOffset();
  281   
  282       /**
  283        * Gets the ID of this time zone.
  284        * @return the ID of this time zone.
  285        */
  286       public String getID()
  287       {
  288           return ID;
  289       }
  290   
  291       /**
  292        * Sets the time zone ID. This does not change any other data in
  293        * the time zone object.
  294        * @param ID the new time zone ID.
  295        */
  296       public void setID(String ID)
  297       {
  298           if (ID == null) {
  299               throw new NullPointerException();
  300           }
  301           this.ID = ID;
  302       }
  303   
  304       /**
  305        * Returns a name of this time zone suitable for presentation to the user
  306        * in the default locale.
  307        * This method returns the long name, not including daylight savings.
  308        * If the display name is not available for the locale,
  309        * then this method returns a string in the
  310        * <a href="#NormalizedCustomID">normalized custom ID format</a>.
  311        * @return the human-readable name of this time zone in the default locale.
  312        * @since 1.2
  313        */
  314       public final String getDisplayName() {
  315           return getDisplayName(false, LONG, Locale.getDefault());
  316       }
  317   
  318       /**
  319        * Returns a name of this time zone suitable for presentation to the user
  320        * in the specified locale.
  321        * This method returns the long name, not including daylight savings.
  322        * If the display name is not available for the locale,
  323        * then this method returns a string in the
  324        * <a href="#NormalizedCustomID">normalized custom ID format</a>.
  325        * @param locale the locale in which to supply the display name.
  326        * @return the human-readable name of this time zone in the given locale.
  327        * @since 1.2
  328        */
  329       public final String getDisplayName(Locale locale) {
  330           return getDisplayName(false, LONG, locale);
  331       }
  332   
  333       /**
  334        * Returns a name of this time zone suitable for presentation to the user
  335        * in the default locale.
  336        * If the display name is not available for the locale, then this
  337        * method returns a string in the
  338        * <a href="#NormalizedCustomID">normalized custom ID format</a>.
  339        * @param daylight if true, return the daylight savings name.
  340        * @param style either <code>LONG</code> or <code>SHORT</code>
  341        * @return the human-readable name of this time zone in the default locale.
  342        * @since 1.2
  343        */
  344       public final String getDisplayName(boolean daylight, int style) {
  345           return getDisplayName(daylight, style, Locale.getDefault());
  346       }
  347   
  348       /**
  349        * Returns a name of this time zone suitable for presentation to the user
  350        * in the specified locale.
  351        * If the display name is not available for the locale,
  352        * then this method returns a string in the
  353        * <a href="#NormalizedCustomID">normalized custom ID format</a>.
  354        * @param daylight if true, return the daylight savings name.
  355        * @param style either <code>LONG</code> or <code>SHORT</code>
  356        * @param locale the locale in which to supply the display name.
  357        * @return the human-readable name of this time zone in the given locale.
  358        * @exception IllegalArgumentException style is invalid.
  359        * @since 1.2
  360        */
  361       public String getDisplayName(boolean daylight, int style, Locale locale) {
  362           if (style != SHORT && style != LONG) {
  363               throw new IllegalArgumentException("Illegal style: " + style);
  364           }
  365   
  366           String id = getID();
  367           String[] names = getDisplayNames(id, locale);
  368           if (names == null) {
  369               if (id.startsWith("GMT")) {
  370                   char sign = id.charAt(3);
  371                   if (sign == '+' || sign == '-') {
  372                       return id;
  373                   }
  374               }
  375               int offset = getRawOffset();
  376               if (daylight) {
  377                   offset += getDSTSavings();
  378               }
  379               return ZoneInfoFile.toCustomID(offset);
  380           }
  381   
  382           int index = daylight ? 3 : 1;
  383           if (style == SHORT) {
  384               index++;
  385           }
  386           return names[index];
  387       }
  388   
  389       private static class DisplayNames {
  390           // Cache for managing display names per timezone per locale
  391           // The structure is:
  392           //   Map(key=id, value=SoftReference(Map(key=locale, value=displaynames)))
  393           private static final Map<String, SoftReference<Map<Locale, String[]>>> CACHE =
  394               new ConcurrentHashMap<String, SoftReference<Map<Locale, String[]>>>();
  395       }
  396   
  397       private static final String[] getDisplayNames(String id, Locale locale) {
  398           Map<String, SoftReference<Map<Locale, String[]>>> displayNames = DisplayNames.CACHE;
  399   
  400           SoftReference<Map<Locale, String[]>> ref = displayNames.get(id);
  401           if (ref != null) {
  402               Map<Locale, String[]> perLocale = ref.get();
  403               if (perLocale != null) {
  404                   String[] names = perLocale.get(locale);
  405                   if (names != null) {
  406                       return names;
  407                   }
  408                   names = TimeZoneNameUtility.retrieveDisplayNames(id, locale);
  409                   if (names != null) {
  410                       perLocale.put(locale, names);
  411                   }
  412                   return names;
  413               }
  414           }
  415   
  416           String[] names = TimeZoneNameUtility.retrieveDisplayNames(id, locale);
  417           if (names != null) {
  418               Map<Locale, String[]> perLocale = new ConcurrentHashMap<Locale, String[]>();
  419               perLocale.put(locale, names);
  420               ref = new SoftReference<Map<Locale, String[]>>(perLocale);
  421               displayNames.put(id, ref);
  422           }
  423           return names;
  424       }
  425   
  426       /**
  427        * Returns the amount of time to be added to local standard time
  428        * to get local wall clock time.
  429        * <p>
  430        * The default implementation always returns 3600000 milliseconds
  431        * (i.e., one hour) if this time zone observes Daylight Saving
  432        * Time. Otherwise, 0 (zero) is returned.
  433        * <p>
  434        * If an underlying TimeZone implementation subclass supports
  435        * historical Daylight Saving Time changes, this method returns
  436        * the known latest daylight saving value.
  437        *
  438        * @return the amount of saving time in milliseconds
  439        * @since 1.4
  440        */
  441       public int getDSTSavings() {
  442           if (useDaylightTime()) {
  443               return 3600000;
  444           }
  445           return 0;
  446       }
  447   
  448       /**
  449        * Queries if this time zone uses daylight savings time.
  450        * <p>
  451        * If an underlying <code>TimeZone</code> implementation subclass
  452        * supports historical Daylight Saving Time schedule changes, the
  453        * method refers to the latest Daylight Saving Time schedule
  454        * information.
  455        *
  456        * @return true if this time zone uses daylight savings time,
  457        * false, otherwise.
  458        */
  459       public abstract boolean useDaylightTime();
  460   
  461       /**
  462        * Queries if the given date is in daylight savings time in
  463        * this time zone.
  464        * @param date the given Date.
  465        * @return true if the given date is in daylight savings time,
  466        * false, otherwise.
  467        */
  468       abstract public boolean inDaylightTime(Date date);
  469   
  470       /**
  471        * Gets the <code>TimeZone</code> for the given ID.
  472        *
  473        * @param ID the ID for a <code>TimeZone</code>, either an abbreviation
  474        * such as "PST", a full name such as "America/Los_Angeles", or a custom
  475        * ID such as "GMT-8:00". Note that the support of abbreviations is
  476        * for JDK 1.1.x compatibility only and full names should be used.
  477        *
  478        * @return the specified <code>TimeZone</code>, or the GMT zone if the given ID
  479        * cannot be understood.
  480        */
  481       public static synchronized TimeZone getTimeZone(String ID) {
  482           return getTimeZone(ID, true);
  483       }
  484   
  485       private static TimeZone getTimeZone(String ID, boolean fallback) {
  486           TimeZone tz = ZoneInfo.getTimeZone(ID);
  487           if (tz == null) {
  488               tz = parseCustomTimeZone(ID);
  489               if (tz == null && fallback) {
  490                   tz = new ZoneInfo(GMT_ID, 0);
  491               }
  492           }
  493           return tz;
  494       }
  495   
  496       /**
  497        * Gets the available IDs according to the given time zone offset in milliseconds.
  498        *
  499        * @param rawOffset the given time zone GMT offset in milliseconds.
  500        * @return an array of IDs, where the time zone for that ID has
  501        * the specified GMT offset. For example, "America/Phoenix" and "America/Denver"
  502        * both have GMT-07:00, but differ in daylight savings behavior.
  503        * @see #getRawOffset()
  504        */
  505       public static synchronized String[] getAvailableIDs(int rawOffset) {
  506           return ZoneInfo.getAvailableIDs(rawOffset);
  507       }
  508   
  509       /**
  510        * Gets all the available IDs supported.
  511        * @return an array of IDs.
  512        */
  513       public static synchronized String[] getAvailableIDs() {
  514           return ZoneInfo.getAvailableIDs();
  515       }
  516   
  517       /**
  518        * Gets the platform defined TimeZone ID.
  519        **/
  520       private static native String getSystemTimeZoneID(String javaHome,
  521                                                        String country);
  522   
  523       /**
  524        * Gets the custom time zone ID based on the GMT offset of the
  525        * platform. (e.g., "GMT+08:00")
  526        */
  527       private static native String getSystemGMTOffsetID();
  528   
  529       /**
  530        * Gets the default <code>TimeZone</code> for this host.
  531        * The source of the default <code>TimeZone</code>
  532        * may vary with implementation.
  533        * @return a default <code>TimeZone</code>.
  534        * @see #setDefault
  535        */
  536       public static TimeZone getDefault() {
  537           return (TimeZone) getDefaultRef().clone();
  538       }
  539   
  540       /**
  541        * Returns the reference to the default TimeZone object. This
  542        * method doesn't create a clone.
  543        */
  544       static TimeZone getDefaultRef() {
  545           TimeZone defaultZone = defaultZoneTL.get();
  546           if (defaultZone == null) {
  547               defaultZone = defaultTimeZone;
  548               if (defaultZone == null) {
  549                   // Need to initialize the default time zone.
  550                   defaultZone = setDefaultZone();
  551                   assert defaultZone != null;
  552               }
  553           }
  554           // Don't clone here.
  555           return defaultZone;
  556       }
  557   
  558       private static synchronized TimeZone setDefaultZone() {
  559           TimeZone tz = null;
  560           // get the time zone ID from the system properties
  561           String zoneID = AccessController.doPrivileged(
  562                   new GetPropertyAction("user.timezone"));
  563   
  564           // if the time zone ID is not set (yet), perform the
  565           // platform to Java time zone ID mapping.
  566           if (zoneID == null || zoneID.equals("")) {
  567               String country = AccessController.doPrivileged(
  568                       new GetPropertyAction("user.country"));
  569               String javaHome = AccessController.doPrivileged(
  570                       new GetPropertyAction("java.home"));
  571               try {
  572                   zoneID = getSystemTimeZoneID(javaHome, country);
  573                   if (zoneID == null) {
  574                       zoneID = GMT_ID;
  575                   }
  576               } catch (NullPointerException e) {
  577                   zoneID = GMT_ID;
  578               }
  579           }
  580   
  581           // Get the time zone for zoneID. But not fall back to
  582           // "GMT" here.
  583           tz = getTimeZone(zoneID, false);
  584   
  585           if (tz == null) {
  586               // If the given zone ID is unknown in Java, try to
  587               // get the GMT-offset-based time zone ID,
  588               // a.k.a. custom time zone ID (e.g., "GMT-08:00").
  589               String gmtOffsetID = getSystemGMTOffsetID();
  590               if (gmtOffsetID != null) {
  591                   zoneID = gmtOffsetID;
  592               }
  593               tz = getTimeZone(zoneID, true);
  594           }
  595           assert tz != null;
  596   
  597           final String id = zoneID;
  598           AccessController.doPrivileged(new PrivilegedAction<Object>() {
  599                   public Object run() {
  600                       System.setProperty("user.timezone", id);
  601                       return null;
  602                   }
  603               });
  604   
  605           defaultTimeZone = tz;
  606           return tz;
  607       }
  608   
  609       private static boolean hasPermission() {
  610           boolean hasPermission = true;
  611           SecurityManager sm = System.getSecurityManager();
  612           if (sm != null) {
  613               try {
  614                   sm.checkPermission(new PropertyPermission
  615                                      ("user.timezone", "write"));
  616               } catch (SecurityException e) {
  617                   hasPermission = false;
  618               }
  619           }
  620           return hasPermission;
  621       }
  622   
  623       /**
  624        * Sets the <code>TimeZone</code> that is
  625        * returned by the <code>getDefault</code> method.  If <code>zone</code>
  626        * is null, reset the default to the value it had originally when the
  627        * VM first started.
  628        * @param zone the new default time zone
  629        * @see #getDefault
  630        */
  631       public static void setDefault(TimeZone zone)
  632       {
  633           if (hasPermission()) {
  634               synchronized (TimeZone.class) {
  635                   defaultTimeZone = zone;
  636                   defaultZoneTL.set(null);
  637               }
  638           } else {
  639               defaultZoneTL.set(zone);
  640           }
  641       }
  642   
  643       /**
  644        * Returns true if this zone has the same rule and offset as another zone.
  645        * That is, if this zone differs only in ID, if at all.  Returns false
  646        * if the other zone is null.
  647        * @param other the <code>TimeZone</code> object to be compared with
  648        * @return true if the other zone is not null and is the same as this one,
  649        * with the possible exception of the ID
  650        * @since 1.2
  651        */
  652       public boolean hasSameRules(TimeZone other) {
  653           return other != null && getRawOffset() == other.getRawOffset() &&
  654               useDaylightTime() == other.useDaylightTime();
  655       }
  656   
  657       /**
  658        * Creates a copy of this <code>TimeZone</code>.
  659        *
  660        * @return a clone of this <code>TimeZone</code>
  661        */
  662       public Object clone()
  663       {
  664           try {
  665               TimeZone other = (TimeZone) super.clone();
  666               other.ID = ID;
  667               return other;
  668           } catch (CloneNotSupportedException e) {
  669               throw new InternalError();
  670           }
  671       }
  672   
  673       /**
  674        * The null constant as a TimeZone.
  675        */
  676       static final TimeZone NO_TIMEZONE = null;
  677   
  678       // =======================privates===============================
  679   
  680       /**
  681        * The string identifier of this <code>TimeZone</code>.  This is a
  682        * programmatic identifier used internally to look up <code>TimeZone</code>
  683        * objects from the system table and also to map them to their localized
  684        * display names.  <code>ID</code> values are unique in the system
  685        * table but may not be for dynamically created zones.
  686        * @serial
  687        */
  688       private String           ID;
  689       private static volatile TimeZone defaultTimeZone;
  690       private static final InheritableThreadLocal<TimeZone> defaultZoneTL
  691                                           = new InheritableThreadLocal<TimeZone>();
  692   
  693       static final String         GMT_ID        = "GMT";
  694       private static final int    GMT_ID_LENGTH = 3;
  695   
  696       /**
  697        * Parses a custom time zone identifier and returns a corresponding zone.
  698        * This method doesn't support the RFC 822 time zone format. (e.g., +hhmm)
  699        *
  700        * @param id a string of the <a href="#CustomID">custom ID form</a>.
  701        * @return a newly created TimeZone with the given offset and
  702        * no daylight saving time, or null if the id cannot be parsed.
  703        */
  704       private static final TimeZone parseCustomTimeZone(String id) {
  705           int length;
  706   
  707           // Error if the length of id isn't long enough or id doesn't
  708           // start with "GMT".
  709           if ((length = id.length()) < (GMT_ID_LENGTH + 2) ||
  710               id.indexOf(GMT_ID) != 0) {
  711               return null;
  712           }
  713   
  714           ZoneInfo zi;
  715   
  716           // First, we try to find it in the cache with the given
  717           // id. Even the id is not normalized, the returned ZoneInfo
  718           // should have its normalized id.
  719           zi = ZoneInfoFile.getZoneInfo(id);
  720           if (zi != null) {
  721               return zi;
  722           }
  723   
  724           int index = GMT_ID_LENGTH;
  725           boolean negative = false;
  726           char c = id.charAt(index++);
  727           if (c == '-') {
  728               negative = true;
  729           } else if (c != '+') {
  730               return null;
  731           }
  732   
  733           int hours = 0;
  734           int num = 0;
  735           int countDelim = 0;
  736           int len = 0;
  737           while (index < length) {
  738               c = id.charAt(index++);
  739               if (c == ':') {
  740                   if (countDelim > 0) {
  741                       return null;
  742                   }
  743                   if (len > 2) {
  744                       return null;
  745                   }
  746                   hours = num;
  747                   countDelim++;
  748                   num = 0;
  749                   len = 0;
  750                   continue;
  751               }
  752               if (c < '0' || c > '9') {
  753                   return null;
  754               }
  755               num = num * 10 + (c - '0');
  756               len++;
  757           }
  758           if (index != length) {
  759               return null;
  760           }
  761           if (countDelim == 0) {
  762               if (len <= 2) {
  763                   hours = num;
  764                   num = 0;
  765               } else {
  766                   hours = num / 100;
  767                   num %= 100;
  768               }
  769           } else {
  770               if (len != 2) {
  771                   return null;
  772               }
  773           }
  774           if (hours > 23 || num > 59) {
  775               return null;
  776           }
  777           int gmtOffset =  (hours * 60 + num) * 60 * 1000;
  778   
  779           if (gmtOffset == 0) {
  780               zi = ZoneInfoFile.getZoneInfo(GMT_ID);
  781               if (negative) {
  782                   zi.setID("GMT-00:00");
  783               } else {
  784                   zi.setID("GMT+00:00");
  785               }
  786           } else {
  787               zi = ZoneInfoFile.getCustomTimeZone(id, negative ? -gmtOffset : gmtOffset);
  788           }
  789           return zi;
  790       }
  791   }

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