KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > java > util > TimeZone


1 /*
2  * @(#)TimeZone.java 1.70 06/01/24
3  *
4  * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7
8 /*
9  * (C) Copyright Taligent, Inc. 1996 - All Rights Reserved
10  * (C) Copyright IBM Corp. 1996 - All Rights Reserved
11  *
12  * The original version of this source code and documentation is copyrighted
13  * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
14  * materials are provided under terms of a License Agreement between Taligent
15  * and Sun. This technology is protected by multiple US and International
16  * patents. This notice and attribution to Taligent may not be removed.
17  * Taligent is a registered trademark of Taligent, Inc.
18  *
19  */

20
21 package java.util;
22
23 import java.io.Serializable JavaDoc;
24 import java.lang.ref.SoftReference JavaDoc;
25 import java.security.AccessController JavaDoc;
26 import java.security.PrivilegedAction JavaDoc;
27 import java.text.DateFormatSymbols JavaDoc;
28 import java.util.concurrent.ConcurrentHashMap JavaDoc;
29 import sun.security.action.GetPropertyAction;
30 import sun.util.calendar.ZoneInfo;
31 import sun.util.calendar.ZoneInfoFile;
32
33 /**
34  * <code>TimeZone</code> represents a time zone offset, and also figures out daylight
35  * savings.
36  *
37  * <p>
38  * Typically, you get a <code>TimeZone</code> using <code>getDefault</code>
39  * which creates a <code>TimeZone</code> based on the time zone where the program
40  * is running. For example, for a program running in Japan, <code>getDefault</code>
41  * creates a <code>TimeZone</code> object based on Japanese Standard Time.
42  *
43  * <p>
44  * You can also get a <code>TimeZone</code> using <code>getTimeZone</code>
45  * along with a time zone ID. For instance, the time zone ID for the
46  * U.S. Pacific Time zone is "America/Los_Angeles". So, you can get a
47  * U.S. Pacific Time <code>TimeZone</code> object with:
48  * <blockquote><pre>
49  * TimeZone tz = TimeZone.getTimeZone("America/Los_Angeles");
50  * </pre></blockquote>
51  * You can use the <code>getAvailableIDs</code> method to iterate through
52  * all the supported time zone IDs. You can then choose a
53  * supported ID to get a <code>TimeZone</code>.
54  * If the time zone you want is not represented by one of the
55  * supported IDs, then a custom time zone ID can be specified to
56  * produce a TimeZone. The syntax of a custom time zone ID is:
57  *
58  * <blockquote><pre>
59  * <a name="CustomID"><i>CustomID:</i></a>
60  * <code>GMT</code> <i>Sign</i> <i>Hours</i> <code>:</code> <i>Minutes</i>
61  * <code>GMT</code> <i>Sign</i> <i>Hours</i> <i>Minutes</i>
62  * <code>GMT</code> <i>Sign</i> <i>Hours</i>
63  * <i>Sign:</i> one of
64  * <code>+ -</code>
65  * <i>Hours:</i>
66  * <i>Digit</i>
67  * <i>Digit</i> <i>Digit</i>
68  * <i>Minutes:</i>
69  * <i>Digit</i> <i>Digit</i>
70  * <i>Digit:</i> one of
71  * <code>0 1 2 3 4 5 6 7 8 9</code>
72  * </pre></blockquote>
73  *
74  * <i>Hours</i> must be between 0 to 23 and <i>Minutes</i> must be
75  * between 00 to 59. For example, "GMT+10" and "GMT+0010" mean ten
76  * hours and ten minutes ahead of GMT, respectively.
77  * <p>
78  * The format is locale independent and digits must be taken from the
79  * Basic Latin block of the Unicode standard. No daylight saving time
80  * transition schedule can be specified with a custom time zone ID. If
81  * the specified string doesn't match the syntax, <code>"GMT"</code>
82  * is used.
83  * <p>
84  * When creating a <code>TimeZone</code>, the specified custom time
85  * zone ID is normalized in the following syntax:
86  * <blockquote><pre>
87  * <a name="NormalizedCustomID"><i>NormalizedCustomID:</i></a>
88  * <code>GMT</code> <i>Sign</i> <i>TwoDigitHours</i> <code>:</code> <i>Minutes</i>
89  * <i>Sign:</i> one of
90  * <code>+ -</code>
91  * <i>TwoDigitHours:</i>
92  * <i>Digit</i> <i>Digit</i>
93  * <i>Minutes:</i>
94  * <i>Digit</i> <i>Digit</i>
95  * <i>Digit:</i> one of
96  * <code>0 1 2 3 4 5 6 7 8 9</code>
97  * </pre></blockquote>
98  * For example, TimeZone.getTimeZone("GMT-8").getID() returns "GMT-08:00".
99  *
100  * <h4>Three-letter time zone IDs</h4>
101  *
102  * For compatibility with JDK 1.1.x, some other three-letter time zone IDs
103  * (such as "PST", "CTT", "AST") are also supported. However, <strong>their
104  * use is deprecated</strong> because the same abbreviation is often used
105  * for multiple time zones (for example, "CST" could be U.S. "Central Standard
106  * Time" and "China Standard Time"), and the Java platform can then only
107  * recognize one of them.
108  *
109  *
110  * @see Calendar
111  * @see GregorianCalendar
112  * @see SimpleTimeZone
113  * @version 1.70 01/24/06
114  * @author Mark Davis, David Goldsmith, Chen-Lieh Huang, Alan Liu
115  * @since JDK1.1
116  */

117 abstract public class TimeZone implements Serializable JavaDoc, Cloneable JavaDoc {
118     /**
119      * Sole constructor. (For invocation by subclass constructors, typically
120      * implicit.)
121      */

122     public TimeZone() {
123     }
124
125     /**
126      * A style specifier for <code>getDisplayName()</code> indicating
127      * a short name, such as "PST."
128      * @see #LONG
129      * @since 1.2
130      */

131     public static final int SHORT = 0;
132
133     /**
134      * A style specifier for <code>getDisplayName()</code> indicating
135      * a long name, such as "Pacific Standard Time."
136      * @see #SHORT
137      * @since 1.2
138      */

139     public static final int LONG = 1;
140
141     // Constants used internally; unit is milliseconds
142
private static final int ONE_MINUTE = 60*1000;
143     private static final int ONE_HOUR = 60*ONE_MINUTE;
144     private static final int ONE_DAY = 24*ONE_HOUR;
145
146     /**
147      * Cache to hold the SimpleDateFormat objects for a Locale.
148      */

149     private static Hashtable JavaDoc cachedLocaleData = new Hashtable JavaDoc(3);
150
151     // Proclaim serialization compatibility with JDK 1.1
152
static final long serialVersionUID = 3581463369166924961L;
153
154     /**
155      * Gets the time zone offset, for current date, modified in case of
156      * daylight savings. This is the offset to add to UTC to get local time.
157      * <p>
158      * This method returns a historically correct offset if an
159      * underlying <code>TimeZone</code> implementation subclass
160      * supports historical Daylight Saving Time schedule and GMT
161      * offset changes.
162      *
163      * @param era the era of the given date.
164      * @param year the year in the given date.
165      * @param month the month in the given date.
166      * Month is 0-based. e.g., 0 for January.
167      * @param day the day-in-month of the given date.
168      * @param dayOfWeek the day-of-week of the given date.
169      * @param milliseconds the milliseconds in day in <em>standard</em>
170      * local time.
171      *
172      * @return the offset in milliseconds to add to GMT to get local time.
173      *
174      * @see Calendar#ZONE_OFFSET
175      * @see Calendar#DST_OFFSET
176      */

177     public abstract int getOffset(int era, int year, int month, int day,
178                                   int dayOfWeek, int milliseconds);
179
180     /**
181      * Returns the offset of this time zone from UTC at the specified
182      * date. If Daylight Saving Time is in effect at the specified
183      * date, the offset value is adjusted with the amount of daylight
184      * saving.
185      * <p>
186      * This method returns a historically correct offset value if an
187      * underlying TimeZone implementation subclass supports historical
188      * Daylight Saving Time schedule and GMT offset changes.
189      *
190      * @param date the date represented in milliseconds since January 1, 1970 00:00:00 GMT
191      * @return the amount of time in milliseconds to add to UTC to get local time.
192      *
193      * @see Calendar#ZONE_OFFSET
194      * @see Calendar#DST_OFFSET
195      * @since 1.4
196      */

197     public int getOffset(long date) {
198     if (inDaylightTime(new Date JavaDoc(date))) {
199         return getRawOffset() + getDSTSavings();
200     }
201     return getRawOffset();
202     }
203
204     /**
205      * Gets the raw GMT offset and the amount of daylight saving of this
206      * time zone at the given time.
207      * @param date the milliseconds (since January 1, 1970,
208      * 00:00:00.000 GMT) at which the time zone offset and daylight
209      * saving amount are found
210      * @param offset an array of int where the raw GMT offset
211      * (offset[0]) and daylight saving amount (offset[1]) are stored,
212      * or null if those values are not needed. The method assumes that
213      * the length of the given array is two or larger.
214      * @return the total amount of the raw GMT offset and daylight
215      * saving at the specified date.
216      *
217      * @see Calendar#ZONE_OFFSET
218      * @see Calendar#DST_OFFSET
219      */

220     int getOffsets(long date, int[] offsets) {
221     int rawoffset = getRawOffset();
222     int dstoffset = 0;
223     if (inDaylightTime(new Date JavaDoc(date))) {
224         dstoffset = getDSTSavings();
225     }
226     if (offsets != null) {
227         offsets[0] = rawoffset;
228         offsets[1] = dstoffset;
229     }
230     return rawoffset + dstoffset;
231     }
232
233     /**
234      * Sets the base time zone offset to GMT.
235      * This is the offset to add to UTC to get local time.
236      * <p>
237      * If an underlying <code>TimeZone</code> implementation subclass
238      * supports historical GMT offset changes, the specified GMT
239      * offset is set as the latest GMT offset and the difference from
240      * the known latest GMT offset value is used to adjust all
241      * historical GMT offset values.
242      *
243      * @param offsetMillis the given base time zone offset to GMT.
244      */

245     abstract public void setRawOffset(int offsetMillis);
246
247     /**
248      * Returns the amount of time in milliseconds to add to UTC to get
249      * standard time in this time zone. Because this value is not
250      * affected by daylight saving time, it is called <I>raw
251      * offset</I>.
252      * <p>
253      * If an underlying <code>TimeZone</code> implementation subclass
254      * supports historical GMT offset changes, the method returns the
255      * raw offset value of the current date. In Honolulu, for example,
256      * its raw offset changed from GMT-10:30 to GMT-10:00 in 1947, and
257      * this method always returns -36000000 milliseconds (i.e., -10
258      * hours).
259      *
260      * @return the amount of raw offset time in milliseconds to add to UTC.
261      * @see Calendar#ZONE_OFFSET
262      */

263     public abstract int getRawOffset();
264
265     /**
266      * Gets the ID of this time zone.
267      * @return the ID of this time zone.
268      */

269     public String JavaDoc getID()
270     {
271         return ID;
272     }
273
274     /**
275      * Sets the time zone ID. This does not change any other data in
276      * the time zone object.
277      * @param ID the new time zone ID.
278      */

279     public void setID(String JavaDoc ID)
280     {
281         if (ID == null) {
282             throw new NullPointerException JavaDoc();
283         }
284         this.ID = ID;
285     }
286
287     /**
288      * Returns a name of this time zone suitable for presentation to the user
289      * in the default locale.
290      * This method returns the long name, not including daylight savings.
291      * If the display name is not available for the locale,
292      * then this method returns a string in the
293      * <a HREF="#NormalizedCustomID">normalized custom ID format</a>.
294      * @return the human-readable name of this time zone in the default locale.
295      * @since 1.2
296      */

297     public final String JavaDoc getDisplayName() {
298         return getDisplayName(false, LONG, Locale.getDefault());
299     }
300
301     /**
302      * Returns a name of this time zone suitable for presentation to the user
303      * in the specified locale.
304      * This method returns the long name, not including daylight savings.
305      * If the display name is not available for the locale,
306      * then this method returns a string in the
307      * <a HREF="#NormalizedCustomID">normalized custom ID format</a>.
308      * @param locale the locale in which to supply the display name.
309      * @return the human-readable name of this time zone in the given locale
310      * or in the default locale if the given locale is not recognized.
311      * @since 1.2
312      */

313     public final String JavaDoc getDisplayName(Locale JavaDoc locale) {
314         return getDisplayName(false, LONG, locale);
315     }
316
317     /**
318      * Returns a name of this time zone suitable for presentation to the user
319      * in the default locale.
320      * If the display name is not available for the locale, then this
321      * method returns a string in the
322      * <a HREF="#NormalizedCustomID">normalized custom ID format</a>.
323      * @param daylight if true, return the daylight savings name.
324      * @param style either <code>LONG</code> or <code>SHORT</code>
325      * @return the human-readable name of this time zone in the default locale.
326      * @since 1.2
327      */

328     public final String JavaDoc getDisplayName(boolean daylight, int style) {
329         return getDisplayName(daylight, style, Locale.getDefault());
330     }
331
332     /**
333      * Returns a name of this time zone suitable for presentation to the user
334      * in the specified locale.
335      * If the display name is not available for the locale,
336      * then this method returns a string in the
337      * <a HREF="#NormalizedCustomID">normalized custom ID format</a>.
338      * @param daylight if true, return the daylight savings name.
339      * @param style either <code>LONG</code> or <code>SHORT</code>
340      * @param locale the locale in which to supply the display name.
341      * @return the human-readable name of this time zone in the given locale
342      * or in the default locale if the given locale is not recognized.
343      * @exception IllegalArgumentException style is invalid.
344      * @since 1.2
345      */

346     public String JavaDoc getDisplayName(boolean daylight, int style, Locale JavaDoc locale) {
347         if (style != SHORT && style != LONG) {
348             throw new IllegalArgumentException JavaDoc("Illegal style: " + style);
349         }
350
351     String JavaDoc id = getID();
352     String JavaDoc[] names = getDisplayNames(id, locale);
353     if (names == null) {
354         if (id.startsWith("GMT")) {
355         char sign = id.charAt(3);
356         if (sign == '+' || sign == '-') {
357             return id;
358         }
359         }
360         int offset = getRawOffset();
361         if (daylight) {
362         offset += getDSTSavings();
363         }
364         return ZoneInfoFile.toCustomID(offset);
365     }
366
367     int index = daylight && useDaylightTime() ? 3 : 1;
368     if (style == SHORT) {
369         index++;
370     }
371     return names[index];
372     }
373
374     private static class DisplayNames {
375     // Cache for managing display names per timezone per locale
376
// The structure is:
377
// Map(key=id, value=SoftReference(Map(key=locale, value=displaynames)))
378
private static final Map JavaDoc<String JavaDoc, SoftReference JavaDoc<Map JavaDoc<Locale JavaDoc, String JavaDoc[]>>> CACHE =
379         new ConcurrentHashMap JavaDoc<String JavaDoc, SoftReference JavaDoc<Map JavaDoc<Locale JavaDoc, String JavaDoc[]>>>();
380     }
381
382     private static final String JavaDoc[] getDisplayNames(String JavaDoc id, Locale JavaDoc locale) {
383     Map JavaDoc<String JavaDoc, SoftReference JavaDoc<Map JavaDoc<Locale JavaDoc, String JavaDoc[]>>> displayNames = DisplayNames.CACHE;
384
385     SoftReference JavaDoc<Map JavaDoc<Locale JavaDoc, String JavaDoc[]>> ref = displayNames.get(id);
386     if (ref != null) {
387         Map JavaDoc<Locale JavaDoc, String JavaDoc[]> perLocale = ref.get();
388         if (perLocale != null) {
389         String JavaDoc[] names = perLocale.get(locale);
390         if (names != null) {
391             return names;
392         }
393         names = retrieveDisplayNames(id, locale);
394         if (names != null) {
395             perLocale.put(locale, names);
396         }
397         return names;
398         }
399     }
400
401     String JavaDoc[] names = retrieveDisplayNames(id, locale);
402     if (names != null) {
403         Map JavaDoc<Locale JavaDoc, String JavaDoc[]> perLocale = new ConcurrentHashMap JavaDoc<Locale JavaDoc, String JavaDoc[]>();
404         perLocale.put(locale, names);
405         ref = new SoftReference JavaDoc<Map JavaDoc<Locale JavaDoc, String JavaDoc[]>>(perLocale);
406         displayNames.put(id, ref);
407     }
408     return names;
409     }
410
411     private static final String JavaDoc[] retrieveDisplayNames(String JavaDoc id, Locale JavaDoc locale) {
412     String JavaDoc[][] tznames = new DateFormatSymbols JavaDoc(locale).getZoneStrings();
413     for (int i = 0; i < tznames.length; i++) {
414         String JavaDoc[] names = tznames[i];
415         if (id.equals(names[0])) {
416         return names;
417         }
418     }
419     return null;
420     }
421
422     /**
423      * Returns the amount of time to be added to local standard time
424      * to get local wall clock time.
425      * <p>
426      * The default implementation always returns 3600000 milliseconds
427      * (i.e., one hour) if this time zone observes Daylight Saving
428      * Time. Otherwise, 0 (zero) is returned.
429      * <p>
430      * If an underlying TimeZone implementation subclass supports
431      * historical Daylight Saving Time changes, this method returns
432      * the known latest daylight saving value.
433      *
434      * @return the amount of saving time in milliseconds
435      * @since 1.4
436      */

437     public int getDSTSavings() {
438     if (useDaylightTime()) {
439         return 3600000;
440     }
441     return 0;
442     }
443
444     /**
445      * Queries if this time zone uses daylight savings time.
446      * <p>
447      * If an underlying <code>TimeZone</code> implementation subclass
448      * supports historical Daylight Saving Time schedule changes, the
449      * method refers to the latest Daylight Saving Time schedule
450      * information.
451      *
452      * @return true if this time zone uses daylight savings time,
453      * false, otherwise.
454      */

455     public abstract boolean useDaylightTime();
456
457     /**
458      * Queries if the given date is in daylight savings time in
459      * this time zone.
460      * @param date the given Date.
461      * @return true if the given date is in daylight savings time,
462      * false, otherwise.
463      */

464     abstract public boolean inDaylightTime(Date JavaDoc date);
465
466     /**
467      * Gets the <code>TimeZone</code> for the given ID.
468      *
469      * @param ID the ID for a <code>TimeZone</code>, either an abbreviation
470      * such as "PST", a full name such as "America/Los_Angeles", or a custom
471      * ID such as "GMT-8:00". Note that the support of abbreviations is
472      * for JDK 1.1.x compatibility only and full names should be used.
473      *
474      * @return the specified <code>TimeZone</code>, or the GMT zone if the given ID
475      * cannot be understood.
476      */

477     public static synchronized TimeZone JavaDoc getTimeZone(String JavaDoc ID) {
478     return getTimeZone(ID, true);
479     }
480
481     private static TimeZone JavaDoc getTimeZone(String JavaDoc ID, boolean fallback) {
482     TimeZone JavaDoc tz = ZoneInfo.getTimeZone(ID);
483     if (tz == null) {
484         tz = parseCustomTimeZone(ID);
485         if (tz == null && fallback) {
486         tz = new ZoneInfo(GMT_ID, 0);
487         }
488     }
489     return tz;
490     }
491
492     /**
493      * Gets the available IDs according to the given time zone offset.
494      * @param rawOffset the given time zone GMT offset.
495      * @return an array of IDs, where the time zone for that ID has
496      * the specified GMT offset. For example, "America/Phoenix" and "America/Denver"
497      * both have GMT-07:00, but differ in daylight savings behavior.
498      */

499     public static synchronized String JavaDoc[] getAvailableIDs(int rawOffset) {
500     return ZoneInfo.getAvailableIDs(rawOffset);
501     }
502
503     /**
504      * Gets all the available IDs supported.
505      * @return an array of IDs.
506      */

507     public static synchronized String JavaDoc[] getAvailableIDs() {
508     return ZoneInfo.getAvailableIDs();
509     }
510     
511     /**
512      * Gets the platform defined TimeZone ID.
513      **/

514     private static native String JavaDoc getSystemTimeZoneID(String JavaDoc javaHome,
515                              String JavaDoc country);
516
517     /**
518      * Gets the custom time zone ID based on the GMT offset of the
519      * platform. (e.g., "GMT+08:00")
520      */

521     private static native String JavaDoc getSystemGMTOffsetID();
522
523     /**
524      * Gets the default <code>TimeZone</code> for this host.
525      * The source of the default <code>TimeZone</code>
526      * may vary with implementation.
527      * @return a default <code>TimeZone</code>.
528      * @see #setDefault
529      */

530     public static TimeZone JavaDoc getDefault() {
531         return (TimeZone JavaDoc) getDefaultRef().clone();
532     }
533
534     /**
535      * Returns the reference to the default TimeZone object. This
536      * method doesn't create a clone.
537      */

538     static TimeZone JavaDoc getDefaultRef() {
539     TimeZone JavaDoc defaultZone = defaultZoneTL.get();
540     if (defaultZone == null) {
541         defaultZone = defaultTimeZone;
542         if (defaultZone == null) {
543         // Need to initialize the default time zone.
544
defaultZone = setDefaultZone();
545         assert defaultZone != null;
546         }
547     }
548     // Don't clone here.
549
return defaultZone;
550     }
551
552     private static synchronized TimeZone JavaDoc setDefaultZone() {
553     TimeZone JavaDoc tz = null;
554     // get the time zone ID from the system properties
555
String JavaDoc zoneID = (String JavaDoc) AccessController.doPrivileged(
556         new GetPropertyAction("user.timezone"));
557
558     // if the time zone ID is not set (yet), perform the
559
// platform to Java time zone ID mapping.
560
if (zoneID == null || zoneID.equals("")) {
561         String JavaDoc country = (String JavaDoc) AccessController.doPrivileged(
562             new GetPropertyAction("user.country"));
563         String JavaDoc javaHome = (String JavaDoc) AccessController.doPrivileged(
564             new GetPropertyAction("java.home"));
565         try {
566         zoneID = getSystemTimeZoneID(javaHome, country);
567         if (zoneID == null) {
568             zoneID = GMT_ID;
569         }
570         } catch (NullPointerException JavaDoc e) {
571         zoneID = GMT_ID;
572         }
573     }
574
575     // Get the time zone for zoneID. But not fall back to
576
// "GMT" here.
577
tz = getTimeZone(zoneID, false);
578
579     if (tz == null) {
580         // If the given zone ID is unknown in Java, try to
581
// get the GMT-offset-based time zone ID,
582
// a.k.a. custom time zone ID (e.g., "GMT-08:00").
583
String JavaDoc gmtOffsetID = getSystemGMTOffsetID();
584         if (gmtOffsetID != null) {
585         zoneID = gmtOffsetID;
586         }
587         tz = getTimeZone(zoneID, true);
588     }
589     assert tz != null;
590
591     final String JavaDoc id = zoneID;
592     AccessController.doPrivileged(new PrivilegedAction JavaDoc<Object JavaDoc>() {
593         public Object JavaDoc run() {
594             System.setProperty("user.timezone", id);
595             return null;
596         }
597         });
598
599     if (hasPermission()) {
600         defaultTimeZone = tz;
601     } else {
602         defaultZoneTL.set(tz);
603     }
604     return tz;
605     }
606
607     private static boolean hasPermission() {
608     boolean hasPermission = true;
609     SecurityManager JavaDoc sm = System.getSecurityManager();
610     if (sm != null) {
611         try {
612         sm.checkPermission(new PropertyPermission JavaDoc
613                    ("user.timezone", "write"));
614         } catch (SecurityException JavaDoc e) {
615         hasPermission = false;
616         }
617     }
618     return hasPermission;
619     }
620
621     /**
622      * Sets the <code>TimeZone</code> that is
623      * returned by the <code>getDefault</code> method. If <code>zone</code>
624      * is null, reset the default to the value it had originally when the
625      * VM first started.
626      * @param zone the new default time zone
627      * @see #getDefault
628      */

629     public static void setDefault(TimeZone JavaDoc zone) {
630     if (hasPermission()) {
631         synchronized (TimeZone JavaDoc.class) {
632         defaultTimeZone = zone;
633         }
634     } else {
635         defaultZoneTL.set(zone);
636     }
637     }
638
639     /**
640      * Returns true if this zone has the same rule and offset as another zone.
641      * That is, if this zone differs only in ID, if at all. Returns false
642      * if the other zone is null.
643      * @param other the <code>TimeZone</code> object to be compared with
644      * @return true if the other zone is not null and is the same as this one,
645      * with the possible exception of the ID
646      * @since 1.2
647      */

648     public boolean hasSameRules(TimeZone JavaDoc other) {
649         return other != null && getRawOffset() == other.getRawOffset() &&
650             useDaylightTime() == other.useDaylightTime();
651     }
652
653     /**
654      * Creates a copy of this <code>TimeZone</code>.
655      *
656      * @return a clone of this <code>TimeZone</code>
657      */

658     public Object JavaDoc clone()
659     {
660         try {
661             TimeZone JavaDoc other = (TimeZone JavaDoc) super.clone();
662             other.ID = ID;
663             return other;
664         } catch (CloneNotSupportedException JavaDoc e) {
665             throw new InternalError JavaDoc();
666         }
667     }
668
669     /**
670      * The null constant as a TimeZone.
671      */

672     static final TimeZone JavaDoc NO_TIMEZONE = null;
673
674     // =======================privates===============================
675

676     /**
677      * The string identifier of this <code>TimeZone</code>. This is a
678      * programmatic identifier used internally to look up <code>TimeZone</code>
679      * objects from the system table and also to map them to their localized
680      * display names. <code>ID</code> values are unique in the system
681      * table but may not be for dynamically created zones.
682      * @serial
683      */

684     private String JavaDoc ID;
685     private static volatile TimeZone JavaDoc defaultTimeZone;
686     private static final InheritableThreadLocal JavaDoc<TimeZone JavaDoc> defaultZoneTL
687                     = new InheritableThreadLocal JavaDoc<TimeZone JavaDoc>();
688
689     static final String JavaDoc GMT_ID = "GMT";
690     private static final int GMT_ID_LENGTH = 3;
691
692     /**
693      * Parses a custom time zone identifier and returns a corresponding zone.
694      * This method doesn't support the RFC 822 time zone format. (e.g., +hhmm)
695      *
696      * @param id a string of the <a HREF="#CustomID">custom ID form</a>.
697      * @return a newly created TimeZone with the given offset and
698      * no daylight saving time, or null if the id cannot be parsed.
699      */

700     private static final TimeZone JavaDoc parseCustomTimeZone(String JavaDoc id) {
701     int length;
702
703     // Error if the length of id isn't long enough or id doesn't
704
// start with "GMT".
705
if ((length = id.length()) < (GMT_ID_LENGTH + 2) ||
706         id.indexOf(GMT_ID) != 0) {
707         return null;
708     }
709
710     ZoneInfo zi;
711
712     // First, we try to find it in the cache with the given
713
// id. Even the id is not normalized, the returned ZoneInfo
714
// should have its normalized id.
715
zi = ZoneInfoFile.getZoneInfo(id);
716     if (zi != null) {
717         return zi;
718     }
719
720     int index = GMT_ID_LENGTH;
721     boolean negative = false;
722     char c = id.charAt(index++);
723     if (c == '-') {
724         negative = true;
725     } else if (c != '+') {
726         return null;
727     }
728
729     int hours = 0;
730     int num = 0;
731     int countDelim = 0;
732     int len = 0;
733     while (index < length) {
734         c = id.charAt(index++);
735         if (c == ':') {
736         if (countDelim > 0) {
737             return null;
738         }
739         if (len > 2) {
740             return null;
741         }
742         hours = num;
743         countDelim++;
744         num = 0;
745         len = 0;
746         continue;
747         }
748         if (c < '0' || c > '9') {
749         return null;
750         }
751         num = num * 10 + (c - '0');
752         len++;
753     }
754     if (index != length) {
755         return null;
756     }
757     if (countDelim == 0) {
758         if (len <= 2) {
759         hours = num;
760         num = 0;
761         } else {
762         hours = num / 100;
763         num %= 100;
764         }
765     } else {
766         if (len != 2) {
767         return null;
768         }
769     }
770     if (hours > 23 || num > 59) {
771         return null;
772     }
773     int gmtOffset = (hours * 60 + num) * 60 * 1000;
774
775     if (gmtOffset == 0) {
776         zi = ZoneInfoFile.getZoneInfo(GMT_ID);
777         if (negative) {
778         zi.setID("GMT-00:00");
779         } else {
780         zi.setID("GMT+00:00");
781         }
782     } else {
783         zi = ZoneInfoFile.getCustomTimeZone(id, negative ? -gmtOffset : gmtOffset);
784     }
785     return zi;
786     }
787 }
788
Popular Tags