KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > joda > time > DateTimeZone


1 /*
2  * Copyright 2001-2006 Stephen Colebourne
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16 package org.joda.time;
17
18 import java.io.IOException JavaDoc;
19 import java.io.ObjectInputStream JavaDoc;
20 import java.io.ObjectOutputStream JavaDoc;
21 import java.io.ObjectStreamException JavaDoc;
22 import java.io.Serializable JavaDoc;
23 import java.lang.ref.Reference JavaDoc;
24 import java.lang.ref.SoftReference JavaDoc;
25 import java.util.HashMap JavaDoc;
26 import java.util.Locale JavaDoc;
27 import java.util.Map JavaDoc;
28 import java.util.Set JavaDoc;
29 import java.util.TimeZone JavaDoc;
30
31 import org.joda.time.chrono.BaseChronology;
32 import org.joda.time.chrono.ISOChronology;
33 import org.joda.time.field.FieldUtils;
34 import org.joda.time.format.DateTimeFormatter;
35 import org.joda.time.format.DateTimeFormatterBuilder;
36 import org.joda.time.format.FormatUtils;
37 import org.joda.time.tz.DefaultNameProvider;
38 import org.joda.time.tz.FixedDateTimeZone;
39 import org.joda.time.tz.NameProvider;
40 import org.joda.time.tz.Provider;
41 import org.joda.time.tz.UTCProvider;
42 import org.joda.time.tz.ZoneInfoProvider;
43
44 /**
45  * DateTimeZone represents a time zone.
46  * <p>
47  * A time zone is a system of rules to convert time from one geographic
48  * location to another. For example, Paris, France is one hour ahead of
49  * London, England. Thus when it is 10:00 in London, it is 11:00 in Paris.
50  * <p>
51  * All time zone rules are expressed, for historical reasons, relative to
52  * Greenwich, London. Local time in Greenwich is referred to as Greenwich Mean
53  * Time (GMT). This is similar, but not precisely identical, to Universal
54  * Coordinated Time, or UTC. This library only uses the term UTC.
55  * <p>
56  * Using this system, America/Los_Angeles is expressed as UTC-08:00, or UTC-07:00
57  * in the summer. The offset -08:00 indicates that America/Los_Angeles time is
58  * obtained from UTC by adding -08:00, that is, by subtracting 8 hours.
59  * <p>
60  * The offset differs in the summer because of daylight saving time, or DST.
61  * The folowing definitions of time are generally used:
62  * <ul>
63  * <li>UTC - The reference time.
64  * <li>Standard Time - The local time without a daylight saving time offset.
65  * For example, in Paris, standard time is UTC+01:00.
66  * <li>Daylight Saving Time - The local time with a daylight saving time
67  * offset. This offset is typically one hour, but not always. It is typically
68  * used in most countries away from the equator. In Paris, daylight saving
69  * time is UTC+02:00.
70  * <li>Wall Time - This is what a local clock on the wall reads. This will be
71  * either Standard Time or Daylight Saving Time depending on the time of year
72  * and whether the location uses Daylight Saving Time.
73  * </ul>
74  * <p>
75  * Unlike the Java TimeZone class, DateTimeZone is immutable. It also only
76  * supports long format time zone ids. Thus EST and ECT are not accepted.
77  * However, the factory that accepts a TimeZone will attempt to convert from
78  * the old short id to a suitable long id.
79  * <p>
80  * DateTimeZone is thread-safe and immutable, and all subclasses must be as
81  * well.
82  *
83  * @author Brian S O'Neill
84  * @author Stephen Colebourne
85  * @since 1.0
86  */

87 public abstract class DateTimeZone implements Serializable JavaDoc {
88     
89     /** Serialization version. */
90     private static final long serialVersionUID = 5546345482340108586L;
91
92     /** The time zone for Universal Coordinated Time */
93     public static final DateTimeZone UTC = new FixedDateTimeZone("UTC", "UTC", 0, 0);
94
95     /** The instance that is providing time zones. */
96     private static Provider cProvider;
97     /** The instance that is providing time zone names. */
98     private static NameProvider cNameProvider;
99     /** The set of ID strings. */
100     private static Set JavaDoc cAvailableIDs;
101     /** The default time zone. */
102     private static DateTimeZone cDefault;
103     /** A formatter for printing and parsing zones. */
104     private static DateTimeFormatter cOffsetFormatter;
105
106     /** Cache that maps fixed offset strings to softly referenced DateTimeZones */
107     private static Map JavaDoc iFixedOffsetCache;
108
109     /** Cache of old zone IDs to new zone IDs */
110     private static Map JavaDoc cZoneIdConversion;
111
112     static {
113         setProvider0(null);
114         setNameProvider0(null);
115
116         try {
117             try {
118                 cDefault = forID(System.getProperty("user.timezone"));
119             } catch (RuntimeException JavaDoc ex) {
120                 // ignored
121
}
122             if (cDefault == null) {
123                 cDefault = forTimeZone(TimeZone.getDefault());
124             }
125         } catch (IllegalArgumentException JavaDoc ex) {
126             // ignored
127
}
128
129         if (cDefault == null) {
130             cDefault = UTC;
131         }
132     }
133
134     //-----------------------------------------------------------------------
135
/**
136      * Gets the default time zone.
137      *
138      * @return the default datetime zone object
139      */

140     public static DateTimeZone getDefault() {
141         return cDefault;
142     }
143
144     /**
145      * Sets the default time zone.
146      *
147      * @param zone the default datetime zone object, must not be null
148      * @throws IllegalArgumentException if the zone is null
149      * @throws SecurityException if the application has insufficient security rights
150      */

151     public static void setDefault(DateTimeZone zone) throws SecurityException JavaDoc {
152         SecurityManager JavaDoc sm = System.getSecurityManager();
153         if (sm != null) {
154             sm.checkPermission(new JodaTimePermission("DateTimeZone.setDefault"));
155         }
156         if (zone == null) {
157             throw new IllegalArgumentException JavaDoc("The datetime zone must not be null");
158         }
159         cDefault = zone;
160     }
161
162     //-----------------------------------------------------------------------
163
/**
164      * Gets a time zone instance for the specified time zone id.
165      * <p>
166      * The time zone id may be one of those returned by getAvailableIDs.
167      * Short ids, as accepted by {@link java.util.TimeZone}, are not accepted.
168      * All IDs must be specified in the long format.
169      * The exception is UTC, which is an acceptable id.
170      * <p>
171      * Alternatively a locale independent, fixed offset, datetime zone can
172      * be specified. The form <code>[+-]hh:mm</code> can be used.
173      *
174      * @param id the ID of the datetime zone, null means default
175      * @return the DateTimeZone object for the ID
176      * @throws IllegalArgumentException if the ID is not recognised
177      */

178     public static DateTimeZone forID(String JavaDoc id) {
179         if (id == null) {
180             return getDefault();
181         }
182         if (id.equals("UTC")) {
183             return DateTimeZone.UTC;
184         }
185         DateTimeZone zone = cProvider.getZone(id);
186         if (zone != null) {
187             return zone;
188         }
189         if (id.startsWith("+") || id.startsWith("-")) {
190             int offset = parseOffset(id);
191             if (offset == 0L) {
192                 return DateTimeZone.UTC;
193             } else {
194                 id = printOffset(offset);
195                 return fixedOffsetZone(id, offset);
196             }
197         }
198         throw new IllegalArgumentException JavaDoc("The datetime zone id is not recognised: " + id);
199     }
200
201     /**
202      * Gets a time zone instance for the specified offset to UTC in hours.
203      * This method assumes standard length hours.
204      * <p>
205      * This factory is a convenient way of constructing zones with a fixed offset.
206      *
207      * @param hoursOffset the offset in hours from UTC
208      * @return the DateTimeZone object for the offset
209      * @throws IllegalArgumentException if the offset is too large or too small
210      */

211     public static DateTimeZone forOffsetHours(int hoursOffset) throws IllegalArgumentException JavaDoc {
212         return forOffsetHoursMinutes(hoursOffset, 0);
213     }
214
215     /**
216      * Gets a time zone instance for the specified offset to UTC in hours and minutes.
217      * This method assumes 60 minutes in an hour, and standard length minutes.
218      * <p>
219      * This factory is a convenient way of constructing zones with a fixed offset.
220      * The minutes value is always positive and in the range 0 to 59.
221      * If constructed with the values (-2, 30), the resultiong zone is '-02:30'.
222      *
223      * @param hoursOffset the offset in hours from UTC
224      * @param minutesOffset the offset in minutes from UTC, must be between 0 and 59 inclusive
225      * @return the DateTimeZone object for the offset
226      * @throws IllegalArgumentException if the offset or minute is too large or too small
227      */

228     public static DateTimeZone forOffsetHoursMinutes(int hoursOffset, int minutesOffset) throws IllegalArgumentException JavaDoc {
229         if (hoursOffset == 0 && minutesOffset == 0) {
230             return DateTimeZone.UTC;
231         }
232         if (minutesOffset < 0 || minutesOffset > 59) {
233             throw new IllegalArgumentException JavaDoc("Minutes out of range: " + minutesOffset);
234         }
235         int offset = 0;
236         try {
237             int hoursInMinutes = FieldUtils.safeMultiply(hoursOffset, 60);
238             if (hoursInMinutes < 0) {
239                 minutesOffset = FieldUtils.safeAdd(hoursInMinutes, -minutesOffset);
240             } else {
241                 minutesOffset = FieldUtils.safeAdd(hoursInMinutes, minutesOffset);
242             }
243             offset = FieldUtils.safeMultiply(minutesOffset, DateTimeConstants.MILLIS_PER_MINUTE);
244         } catch (ArithmeticException JavaDoc ex) {
245             throw new IllegalArgumentException JavaDoc("Offset is too large");
246         }
247         return forOffsetMillis(offset);
248     }
249
250     /**
251      * Gets a time zone instance for the specified offset to UTC in milliseconds.
252      *
253      * @param millisOffset the offset in millis from UTC
254      * @return the DateTimeZone object for the offset
255      */

256     public static DateTimeZone forOffsetMillis(int millisOffset) {
257         String JavaDoc id = printOffset(millisOffset);
258         return fixedOffsetZone(id, millisOffset);
259     }
260
261     /**
262      * Gets a time zone instance for a JDK TimeZone.
263      * <p>
264      * DateTimeZone only accepts a subset of the IDs from TimeZone. The
265      * excluded IDs are the short three letter form (except UTC). This
266      * method will attempt to convert between time zones created using the
267      * short IDs and the full version.
268      *
269      * @param zone the zone to convert, null means default
270      * @return the DateTimeZone object for the zone
271      * @throws IllegalArgumentException if the zone is not recognised
272      */

273     public static DateTimeZone forTimeZone(TimeZone JavaDoc zone) {
274         if (zone == null) {
275             return getDefault();
276         }
277         final String JavaDoc id = zone.getID();
278         if (id.equals("UTC")) {
279             return DateTimeZone.UTC;
280         }
281
282         // Convert from old alias before consulting provider since they may differ.
283
DateTimeZone dtz = null;
284         String JavaDoc convId = getConvertedId(id);
285         if (convId != null) {
286             dtz = cProvider.getZone(convId);
287         }
288         if (dtz == null) {
289             dtz = cProvider.getZone(id);
290         }
291         if (dtz != null) {
292             return dtz;
293         }
294
295         // Support GMT+/-hh:mm formats
296
if (convId == null) {
297             convId = zone.getDisplayName();
298             if (convId.startsWith("GMT+") || convId.startsWith("GMT-")) {
299                 convId = convId.substring(3);
300                 int offset = parseOffset(convId);
301                 if (offset == 0L) {
302                     return DateTimeZone.UTC;
303                 } else {
304                     convId = printOffset(offset);
305                     return fixedOffsetZone(convId, offset);
306                 }
307             }
308         }
309
310         throw new IllegalArgumentException JavaDoc("The datetime zone id is not recognised: " + id);
311     }
312
313     //-----------------------------------------------------------------------
314
/**
315      * Gets the zone using a fixed offset amount.
316      *
317      * @param id the zone id
318      * @param offset the offset in millis
319      * @return the zone
320      */

321     private static synchronized DateTimeZone fixedOffsetZone(String JavaDoc id, int offset) {
322         if (offset == 0) {
323             return DateTimeZone.UTC;
324         }
325         if (iFixedOffsetCache == null) {
326             iFixedOffsetCache = new HashMap JavaDoc();
327         }
328         DateTimeZone zone;
329         Reference JavaDoc ref = (Reference JavaDoc) iFixedOffsetCache.get(id);
330         if (ref != null) {
331             zone = (DateTimeZone) ref.get();
332             if (zone != null) {
333                 return zone;
334             }
335         }
336         zone = new FixedDateTimeZone(id, null, offset, offset);
337         iFixedOffsetCache.put(id, new SoftReference JavaDoc(zone));
338         return zone;
339     }
340
341     /**
342      * Gets all the available IDs supported.
343      *
344      * @return an unmodifiable Set of String IDs
345      */

346     public static Set JavaDoc getAvailableIDs() {
347         return cAvailableIDs;
348     }
349
350     //-----------------------------------------------------------------------
351
/**
352      * Gets the zone provider factory.
353      * <p>
354      * The zone provider is a pluggable instance factory that supplies the
355      * actual instances of DateTimeZone.
356      *
357      * @return the provider
358      */

359     public static Provider getProvider() {
360         return cProvider;
361     }
362
363     /**
364      * Sets the zone provider factory.
365      * <p>
366      * The zone provider is a pluggable instance factory that supplies the
367      * actual instances of DateTimeZone.
368      *
369      * @param provider provider to use, or null for default
370      * @throws SecurityException if you do not have the permission DateTimeZone.setProvider
371      * @throws IllegalArgumentException if the provider is invalid
372      */

373     public static void setProvider(Provider provider) throws SecurityException JavaDoc {
374         SecurityManager JavaDoc sm = System.getSecurityManager();
375         if (sm != null) {
376             sm.checkPermission(new JodaTimePermission("DateTimeZone.setProvider"));
377         }
378         setProvider0(provider);
379     }
380
381     /**
382      * Sets the zone provider factory without performing the security check.
383      *
384      * @param provider provider to use, or null for default
385      * @throws IllegalArgumentException if the provider is invalid
386      */

387     private static void setProvider0(Provider provider) {
388         if (provider == null) {
389             provider = getDefaultProvider();
390         }
391         Set JavaDoc ids = provider.getAvailableIDs();
392         if (ids == null || ids.size() == 0) {
393             throw new IllegalArgumentException JavaDoc
394                 ("The provider doesn't have any available ids");
395         }
396         if (!ids.contains("UTC")) {
397             throw new IllegalArgumentException JavaDoc("The provider doesn't support UTC");
398         }
399         if (!UTC.equals(provider.getZone("UTC"))) {
400             throw new IllegalArgumentException JavaDoc("Invalid UTC zone provided");
401         }
402         cProvider = provider;
403         cAvailableIDs = ids;
404     }
405
406     /**
407      * Gets the default zone provider.
408      * <p>
409      * Tries the system property <code>org.joda.time.DateTimeZone.Provider</code>.
410      * Then tries a <code>ZoneInfoProvider</code> using the data in <code>org/joda/time/tz/data</code>.
411      * Then uses <code>UTCProvider</code>.
412      *
413      * @return the default name provider
414      */

415     private static Provider getDefaultProvider() {
416         Provider provider = null;
417
418         try {
419             String JavaDoc providerClass =
420                 System.getProperty("org.joda.time.DateTimeZone.Provider");
421             if (providerClass != null) {
422                 try {
423                     provider = (Provider) Class.forName(providerClass).newInstance();
424                 } catch (Exception JavaDoc ex) {
425                     Thread JavaDoc thread = Thread.currentThread();
426                     thread.getThreadGroup().uncaughtException(thread, ex);
427                 }
428             }
429         } catch (SecurityException JavaDoc ex) {
430             // ignored
431
}
432
433         if (provider == null) {
434             try {
435                 provider = new ZoneInfoProvider("org/joda/time/tz/data");
436             } catch (Exception JavaDoc ex) {
437                 Thread JavaDoc thread = Thread.currentThread();
438                 thread.getThreadGroup().uncaughtException(thread, ex);
439             }
440         }
441
442         if (provider == null) {
443             provider = new UTCProvider();
444         }
445
446         return provider;
447     }
448
449     //-----------------------------------------------------------------------
450
/**
451      * Gets the name provider factory.
452      * <p>
453      * The name provider is a pluggable instance factory that supplies the
454      * names of each DateTimeZone.
455      *
456      * @return the provider
457      */

458     public static NameProvider getNameProvider() {
459         return cNameProvider;
460     }
461
462     /**
463      * Sets the name provider factory.
464      * <p>
465      * The name provider is a pluggable instance factory that supplies the
466      * names of each DateTimeZone.
467      *
468      * @param nameProvider provider to use, or null for default
469      * @throws SecurityException if you do not have the permission DateTimeZone.setNameProvider
470      * @throws IllegalArgumentException if the provider is invalid
471      */

472     public static void setNameProvider(NameProvider nameProvider) throws SecurityException JavaDoc {
473         SecurityManager JavaDoc sm = System.getSecurityManager();
474         if (sm != null) {
475             sm.checkPermission(new JodaTimePermission("DateTimeZone.setNameProvider"));
476         }
477         setNameProvider0(nameProvider);
478     }
479
480     /**
481      * Sets the name provider factory without performing the security check.
482      *
483      * @param nameProvider provider to use, or null for default
484      * @throws IllegalArgumentException if the provider is invalid
485      */

486     private static void setNameProvider0(NameProvider nameProvider) {
487         if (nameProvider == null) {
488             nameProvider = getDefaultNameProvider();
489         }
490         cNameProvider = nameProvider;
491     }
492
493     /**
494      * Gets the default name provider.
495      * <p>
496      * Tries the system property <code>org.joda.time.DateTimeZone.NameProvider</code>.
497      * Then uses <code>DefaultNameProvider</code>.
498      *
499      * @return the default name provider
500      */

501     private static NameProvider getDefaultNameProvider() {
502         NameProvider nameProvider = null;
503         try {
504             String JavaDoc providerClass = System.getProperty("org.joda.time.DateTimeZone.NameProvider");
505             if (providerClass != null) {
506                 try {
507                     nameProvider = (NameProvider) Class.forName(providerClass).newInstance();
508                 } catch (Exception JavaDoc ex) {
509                     Thread JavaDoc thread = Thread.currentThread();
510                     thread.getThreadGroup().uncaughtException(thread, ex);
511                 }
512             }
513         } catch (SecurityException JavaDoc ex) {
514             // ignore
515
}
516
517         if (nameProvider == null) {
518             nameProvider = new DefaultNameProvider();
519         }
520
521         return nameProvider;
522     }
523
524     //-----------------------------------------------------------------------
525
/**
526      * Converts an old style id to a new style id.
527      *
528      * @param id the old style id
529      * @return the new style id, null if not found
530      */

531     private static synchronized String JavaDoc getConvertedId(String JavaDoc id) {
532         Map JavaDoc map = cZoneIdConversion;
533         if (map == null) {
534             // Backwards compatibility with TimeZone.
535
map = new HashMap JavaDoc();
536             map.put("GMT", "UTC");
537             map.put("MIT", "Pacific/Apia");
538             map.put("HST", "Pacific/Honolulu");
539             map.put("AST", "America/Anchorage");
540             map.put("PST", "America/Los_Angeles");
541             map.put("MST", "America/Denver");
542             map.put("PNT", "America/Phoenix");
543             map.put("CST", "America/Chicago");
544             map.put("EST", "America/New_York");
545             map.put("IET", "America/Indianapolis");
546             map.put("PRT", "America/Puerto_Rico");
547             map.put("CNT", "America/St_Johns");
548             map.put("AGT", "America/Buenos_Aires");
549             map.put("BET", "America/Sao_Paulo");
550             map.put("WET", "Europe/London");
551             map.put("ECT", "Europe/Paris");
552             map.put("ART", "Africa/Cairo");
553             map.put("CAT", "Africa/Harare");
554             map.put("EET", "Europe/Bucharest");
555             map.put("EAT", "Africa/Addis_Ababa");
556             map.put("MET", "Asia/Tehran");
557             map.put("NET", "Asia/Yerevan");
558             map.put("PLT", "Asia/Karachi");
559             map.put("IST", "Asia/Calcutta");
560             map.put("BST", "Asia/Dhaka");
561             map.put("VST", "Asia/Saigon");
562             map.put("CTT", "Asia/Shanghai");
563             map.put("JST", "Asia/Tokyo");
564             map.put("ACT", "Australia/Darwin");
565             map.put("AET", "Australia/Sydney");
566             map.put("SST", "Pacific/Guadalcanal");
567             map.put("NST", "Pacific/Auckland");
568             cZoneIdConversion = map;
569         }
570         return (String JavaDoc) map.get(id);
571     }
572
573     private static int parseOffset(String JavaDoc str) {
574         Chronology chrono;
575         if (cDefault != null) {
576             chrono = ISOChronology.getInstanceUTC();
577         } else {
578             // Can't use a real chronology if called during class
579
// initialization. Offset parser doesn't need it anyhow.
580
chrono = new BaseChronology() {
581                 public DateTimeZone getZone() {
582                     return null;
583                 }
584                 public Chronology withUTC() {
585                     return this;
586                 }
587                 public Chronology withZone(DateTimeZone zone) {
588                     return this;
589                 }
590                 public String JavaDoc toString() {
591                     return getClass().getName();
592                 }
593             };
594         }
595
596         return -(int) offsetFormatter().withChronology(chrono).parseMillis(str);
597     }
598
599     /**
600      * Formats a timezone offset string.
601      * <p>
602      * This method is kept separate from the formatting classes to speed and
603      * simplify startup and classloading.
604      *
605      * @param offset the offset in milliseconds
606      * @return the time zone string
607      */

608     private static String JavaDoc printOffset(int offset) {
609         StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
610         if (offset >= 0) {
611             buf.append('+');
612         } else {
613             buf.append('-');
614             offset = -offset;
615         }
616
617         int hours = offset / DateTimeConstants.MILLIS_PER_HOUR;
618         FormatUtils.appendPaddedInteger(buf, hours, 2);
619         offset -= hours * (int) DateTimeConstants.MILLIS_PER_HOUR;
620
621         int minutes = offset / DateTimeConstants.MILLIS_PER_MINUTE;
622         buf.append(':');
623         FormatUtils.appendPaddedInteger(buf, minutes, 2);
624         offset -= minutes * DateTimeConstants.MILLIS_PER_MINUTE;
625         if (offset == 0) {
626             return buf.toString();
627         }
628
629         int seconds = offset / DateTimeConstants.MILLIS_PER_SECOND;
630         buf.append(':');
631         FormatUtils.appendPaddedInteger(buf, seconds, 2);
632         offset -= seconds * DateTimeConstants.MILLIS_PER_SECOND;
633         if (offset == 0) {
634             return buf.toString();
635         }
636
637         buf.append('.');
638         FormatUtils.appendPaddedInteger(buf, offset, 3);
639         return buf.toString();
640     }
641
642     /**
643      * Gets a printer/parser for managing the offset id formatting.
644      *
645      * @return the formatter
646      */

647     private static synchronized DateTimeFormatter offsetFormatter() {
648         if (cOffsetFormatter == null) {
649             cOffsetFormatter = new DateTimeFormatterBuilder()
650                 .appendTimeZoneOffset(null, true, 2, 4)
651                 .toFormatter();
652         }
653         return cOffsetFormatter;
654     }
655
656     // Instance fields and methods
657
//--------------------------------------------------------------------
658

659     private final String JavaDoc iID;
660
661     /**
662      * Constructor.
663      *
664      * @param id the id to use
665      * @throws IllegalArgumentException if the id is null
666      */

667     protected DateTimeZone(String JavaDoc id) {
668         if (id == null) {
669             throw new IllegalArgumentException JavaDoc("Id must not be null");
670         }
671         iID = id;
672     }
673
674     // Principal methods
675
//--------------------------------------------------------------------
676

677     /**
678      * Gets the ID of this datetime zone.
679      *
680      * @return the ID of this datetime zone
681      */

682     public final String JavaDoc getID() {
683         return iID;
684     }
685
686     /**
687      * Returns a non-localized name that is unique to this time zone. It can be
688      * combined with id to form a unique key for fetching localized names.
689      *
690      * @param instant milliseconds from 1970-01-01T00:00:00Z to get the name for
691      * @return name key or null if id should be used for names
692      */

693     public abstract String JavaDoc getNameKey(long instant);
694
695     /**
696      * Gets the short name of this datetime zone suitable for display using
697      * the default locale.
698      * <p>
699      * If the name is not available for the locale, then this method returns a
700      * string in the format <code>[+-]hh:mm</code>.
701      *
702      * @param instant milliseconds from 1970-01-01T00:00:00Z to get the name for
703      * @return the human-readable short name in the default locale
704      */

705     public final String JavaDoc getShortName(long instant) {
706         return getShortName(instant, null);
707     }
708
709     /**
710      * Gets the short name of this datetime zone suitable for display using
711      * the specified locale.
712      * <p>
713      * If the name is not available for the locale, then this method returns a
714      * string in the format <code>[+-]hh:mm</code>.
715      *
716      * @param instant milliseconds from 1970-01-01T00:00:00Z to get the name for
717      * @param locale the locale to get the name for
718      * @return the human-readable short name in the specified locale
719      */

720     public String JavaDoc getShortName(long instant, Locale JavaDoc locale) {
721         if (locale == null) {
722             locale = Locale.getDefault();
723         }
724         String JavaDoc nameKey = getNameKey(instant);
725         if (nameKey == null) {
726             return iID;
727         }
728         String JavaDoc name = cNameProvider.getShortName(locale, iID, nameKey);
729         if (name != null) {
730             return name;
731         }
732         return printOffset(getOffset(instant));
733     }
734
735     /**
736      * Gets the long name of this datetime zone suitable for display using
737      * the default locale.
738      * <p>
739      * If the name is not available for the locale, then this method returns a
740      * string in the format <code>[+-]hh:mm</code>.
741      *
742      * @param instant milliseconds from 1970-01-01T00:00:00Z to get the name for
743      * @return the human-readable long name in the default locale
744      */

745     public final String JavaDoc getName(long instant) {
746         return getName(instant, null);
747     }
748
749     /**
750      * Gets the long name of this datetime zone suitable for display using
751      * the specified locale.
752      * <p>
753      * If the name is not available for the locale, then this method returns a
754      * string in the format <code>[+-]hh:mm</code>.
755      *
756      * @param instant milliseconds from 1970-01-01T00:00:00Z to get the name for
757      * @param locale the locale to get the name for
758      * @return the human-readable long name in the specified locale
759      */

760     public String JavaDoc getName(long instant, Locale JavaDoc locale) {
761         if (locale == null) {
762             locale = Locale.getDefault();
763         }
764         String JavaDoc nameKey = getNameKey(instant);
765         if (nameKey == null) {
766             return iID;
767         }
768         String JavaDoc name = cNameProvider.getName(locale, iID, nameKey);
769         if (name != null) {
770             return name;
771         }
772         return printOffset(getOffset(instant));
773     }
774
775     /**
776      * Gets the millisecond offset to add to UTC to get local time.
777      *
778      * @param instant milliseconds from 1970-01-01T00:00:00Z to get the offset for
779      * @return the millisecond offset to add to UTC to get local time
780      */

781     public abstract int getOffset(long instant);
782
783     /**
784      * Gets the millisecond offset to add to UTC to get local time.
785      *
786      * @param instant instant to get the offset for, null means now
787      * @return the millisecond offset to add to UTC to get local time
788      */

789     public final int getOffset(ReadableInstant instant) {
790         if (instant == null) {
791             return getOffset(DateTimeUtils.currentTimeMillis());
792         }
793         return getOffset(instant.getMillis());
794     }
795
796     /**
797      * Gets the standard millisecond offset to add to UTC to get local time,
798      * when standard time is in effect.
799      *
800      * @param instant milliseconds from 1970-01-01T00:00:00Z to get the offset for
801      * @return the millisecond offset to add to UTC to get local time
802      */

803     public abstract int getStandardOffset(long instant);
804
805     /**
806      * Gets the millisecond offset to subtract from local time to get UTC time.
807      * This offset can be used to undo adding the offset obtained by getOffset.
808      *
809      * <pre>
810      * millisLocal == millisUTC + getOffset(millisUTC)
811      * millisUTC == millisLocal - getOffsetFromLocal(millisLocal)
812      * </pre>
813      *
814      * Note: After calculating millisLocal, some error may be introduced. At
815      * offset transitions (due to DST or other historical changes), ranges of
816      * local times may map to different UTC times.
817      *
818      * @param instantLocal the millisecond instant, relative to this time zone, to
819      * get the offset for
820      * @return the millisecond offset to subtract from local time to get UTC time
821      */

822     public int getOffsetFromLocal(long instantLocal) {
823         return getOffset(instantLocal - getOffset(instantLocal));
824     }
825
826     /**
827      * Gets the millisecond instant in another zone keeping the same local time.
828      * <p>
829      * The conversion is performed by converting the specified UTC millis to local
830      * millis in this zone, then converting back to UTC millis in the new zone.
831      *
832      * @param newZone the new zone, null means default
833      * @param oldInstant the UTC millisecond instant to convert
834      * @return the UTC millisecond instant with the same local time in the new zone
835      */

836     public long getMillisKeepLocal(DateTimeZone newZone, long oldInstant) {
837         if (newZone == null) {
838             newZone = DateTimeZone.getDefault();
839         }
840         if (newZone == this) {
841             return oldInstant;
842         }
843         long instantLocal = oldInstant + getOffset(oldInstant);
844         return instantLocal - newZone.getOffsetFromLocal(instantLocal);
845     }
846
847     /**
848      * Returns true if this time zone has no transitions.
849      *
850      * @return true if no transitions
851      */

852     public abstract boolean isFixed();
853
854     /**
855      * Advances the given instant to where the time zone offset or name changes.
856      * If the instant returned is exactly the same as passed in, then
857      * no changes occur after the given instant.
858      *
859      * @param instant milliseconds from 1970-01-01T00:00:00Z
860      * @return milliseconds from 1970-01-01T00:00:00Z
861      */

862     public abstract long nextTransition(long instant);
863
864     /**
865      * Retreats the given instant to where the time zone offset or name changes.
866      * If the instant returned is exactly the same as passed in, then
867      * no changes occur before the given instant.
868      *
869      * @param instant milliseconds from 1970-01-01T00:00:00Z
870      * @return milliseconds from 1970-01-01T00:00:00Z
871      */

872     public abstract long previousTransition(long instant);
873
874     // Basic methods
875
//--------------------------------------------------------------------
876

877     /**
878      * Get the datetime zone as a {@link java.util.TimeZone}.
879      *
880      * @return the equivalent TimeZone object
881      */

882     public java.util.TimeZone JavaDoc toTimeZone() {
883         return java.util.TimeZone.getTimeZone(iID);
884     }
885
886     /**
887      * Compare this datetime zone with another.
888      *
889      * @param object the object to compare with
890      * @return true if equal, based on the ID and all internal rules
891      */

892     public abstract boolean equals(Object JavaDoc object);
893
894     /**
895      * Gets a hash code compatable with equals.
896      *
897      * @return suitable hashcode
898      */

899     public int hashCode() {
900         return 57 + getID().hashCode();
901     }
902
903     /**
904      * Gets the datetime zone as a string, which is simply its ID.
905      * @return the id of the zone
906      */

907     public String JavaDoc toString() {
908         return getID();
909     }
910
911     /**
912      * By default, when DateTimeZones are serialized, only a "stub" object
913      * referring to the id is written out. When the stub is read in, it
914      * replaces itself with a DateTimeZone object.
915      * @return a stub object to go in the stream
916      */

917     protected Object JavaDoc writeReplace() throws ObjectStreamException JavaDoc {
918         return new Stub(iID);
919     }
920
921     /**
922      * Used to serialize DateTimeZones by id.
923      */

924     private static final class Stub implements Serializable JavaDoc {
925         /** Serialization lock. */
926         private static final long serialVersionUID = -6471952376487863581L;
927         /** The ID of the zone. */
928         private transient String JavaDoc iID;
929
930         /**
931          * Constructor.
932          * @param id the id of the zone
933          */

934         Stub(String JavaDoc id) {
935             iID = id;
936         }
937
938         private void writeObject(ObjectOutputStream JavaDoc out) throws IOException JavaDoc {
939             out.writeUTF(iID);
940         }
941
942         private void readObject(ObjectInputStream JavaDoc in) throws IOException JavaDoc {
943             iID = in.readUTF();
944         }
945
946         private Object JavaDoc readResolve() throws ObjectStreamException JavaDoc {
947             return forID(iID);
948         }
949     }
950 }
951
Popular Tags