jtulach@1334: /*
jtulach@1334: * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved.
jtulach@1334: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
jtulach@1334: *
jtulach@1334: * This code is free software; you can redistribute it and/or modify it
jtulach@1334: * under the terms of the GNU General Public License version 2 only, as
jtulach@1334: * published by the Free Software Foundation. Oracle designates this
jtulach@1334: * particular file as subject to the "Classpath" exception as provided
jtulach@1334: * by Oracle in the LICENSE file that accompanied this code.
jtulach@1334: *
jtulach@1334: * This code is distributed in the hope that it will be useful, but WITHOUT
jtulach@1334: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
jtulach@1334: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
jtulach@1334: * version 2 for more details (a copy is included in the LICENSE file that
jtulach@1334: * accompanied this code).
jtulach@1334: *
jtulach@1334: * You should have received a copy of the GNU General Public License version
jtulach@1334: * 2 along with this work; if not, write to the Free Software Foundation,
jtulach@1334: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
jtulach@1334: *
jtulach@1334: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
jtulach@1334: * or visit www.oracle.com if you need additional information or have any
jtulach@1334: * questions.
jtulach@1334: */
jtulach@1334:
jtulach@1334: /*
jtulach@1334: * (C) Copyright Taligent, Inc. 1996 - All Rights Reserved
jtulach@1334: * (C) Copyright IBM Corp. 1996 - All Rights Reserved
jtulach@1334: *
jtulach@1334: * The original version of this source code and documentation is copyrighted
jtulach@1334: * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
jtulach@1334: * materials are provided under terms of a License Agreement between Taligent
jtulach@1334: * and Sun. This technology is protected by multiple US and International
jtulach@1334: * patents. This notice and attribution to Taligent may not be removed.
jtulach@1334: * Taligent is a registered trademark of Taligent, Inc.
jtulach@1334: *
jtulach@1334: */
jtulach@1334:
jtulach@1334: package java.util;
jtulach@1334:
jtulach@1334: import java.io.Serializable;
jtulach@1334: import java.lang.ref.SoftReference;
jtulach@1334: import java.security.AccessController;
jtulach@1334: import java.security.PrivilegedAction;
jtulach@1334: import java.util.concurrent.ConcurrentHashMap;
jtulach@1334:
jtulach@1334: /**
jtulach@1334: * TimeZone
represents a time zone offset, and also figures out daylight
jtulach@1334: * savings.
jtulach@1334: *
jtulach@1334: *
jtulach@1334: * Typically, you get a TimeZone
using getDefault
jtulach@1334: * which creates a TimeZone
based on the time zone where the program
jtulach@1334: * is running. For example, for a program running in Japan, getDefault
jtulach@1334: * creates a TimeZone
object based on Japanese Standard Time.
jtulach@1334: *
jtulach@1334: *
jtulach@1334: * You can also get a TimeZone
using getTimeZone
jtulach@1334: * along with a time zone ID. For instance, the time zone ID for the
jtulach@1334: * U.S. Pacific Time zone is "America/Los_Angeles". So, you can get a
jtulach@1334: * U.S. Pacific Time TimeZone
object with:
jtulach@1334: *
jtulach@1334: * You can use thejtulach@1334: * TimeZone tz = TimeZone.getTimeZone("America/Los_Angeles"); jtulach@1334: *
getAvailableIDs
method to iterate through
jtulach@1334: * all the supported time zone IDs. You can then choose a
jtulach@1334: * supported ID to get a TimeZone
.
jtulach@1334: * If the time zone you want is not represented by one of the
jtulach@1334: * supported IDs, then a custom time zone ID can be specified to
jtulach@1334: * produce a TimeZone. The syntax of a custom time zone ID is:
jtulach@1334: *
jtulach@1334: * jtulach@1334: * jtulach@1334: * Hours must be between 0 to 23 and Minutes must be jtulach@1334: * between 00 to 59. For example, "GMT+10" and "GMT+0010" mean ten jtulach@1334: * hours and ten minutes ahead of GMT, respectively. jtulach@1334: *jtulach@1334: * CustomID: jtulach@1334: *GMT
Sign Hours:
Minutes jtulach@1334: *GMT
Sign Hours Minutes jtulach@1334: *GMT
Sign Hours jtulach@1334: * Sign: one of jtulach@1334: *+ -
jtulach@1334: * Hours: jtulach@1334: * Digit jtulach@1334: * Digit Digit jtulach@1334: * Minutes: jtulach@1334: * Digit Digit jtulach@1334: * Digit: one of jtulach@1334: *0 1 2 3 4 5 6 7 8 9
jtulach@1334: *
jtulach@1334: * The format is locale independent and digits must be taken from the
jtulach@1334: * Basic Latin block of the Unicode standard. No daylight saving time
jtulach@1334: * transition schedule can be specified with a custom time zone ID. If
jtulach@1334: * the specified string doesn't match the syntax, "GMT"
jtulach@1334: * is used.
jtulach@1334: *
jtulach@1334: * When creating a TimeZone
, the specified custom time
jtulach@1334: * zone ID is normalized in the following syntax:
jtulach@1334: *
jtulach@1334: * For example, TimeZone.getTimeZone("GMT-8").getID() returns "GMT-08:00". jtulach@1334: * jtulach@1334: *jtulach@1334: * NormalizedCustomID: jtulach@1334: *GMT
Sign TwoDigitHours:
Minutes jtulach@1334: * Sign: one of jtulach@1334: *+ -
jtulach@1334: * TwoDigitHours: jtulach@1334: * Digit Digit jtulach@1334: * Minutes: jtulach@1334: * Digit Digit jtulach@1334: * Digit: one of jtulach@1334: *0 1 2 3 4 5 6 7 8 9
jtulach@1334: *
getDisplayName()
indicating
jtulach@1334: * a short name, such as "PST."
jtulach@1334: * @see #LONG
jtulach@1334: * @since 1.2
jtulach@1334: */
jtulach@1334: public static final int SHORT = 0;
jtulach@1334:
jtulach@1334: /**
jtulach@1334: * A style specifier for getDisplayName()
indicating
jtulach@1334: * a long name, such as "Pacific Standard Time."
jtulach@1334: * @see #SHORT
jtulach@1334: * @since 1.2
jtulach@1334: */
jtulach@1334: public static final int LONG = 1;
jtulach@1334:
jtulach@1334: // Constants used internally; unit is milliseconds
jtulach@1334: private static final int ONE_MINUTE = 60*1000;
jtulach@1334: private static final int ONE_HOUR = 60*ONE_MINUTE;
jtulach@1334: private static final int ONE_DAY = 24*ONE_HOUR;
jtulach@1334:
jtulach@1334: // Proclaim serialization compatibility with JDK 1.1
jtulach@1334: static final long serialVersionUID = 3581463369166924961L;
jtulach@1334:
jtulach@1334: /**
jtulach@1334: * Gets the time zone offset, for current date, modified in case of
jtulach@1334: * daylight savings. This is the offset to add to UTC to get local time.
jtulach@1334: *
jtulach@1334: * This method returns a historically correct offset if an
jtulach@1334: * underlying TimeZone
implementation subclass
jtulach@1334: * supports historical Daylight Saving Time schedule and GMT
jtulach@1334: * offset changes.
jtulach@1334: *
jtulach@1334: * @param era the era of the given date.
jtulach@1334: * @param year the year in the given date.
jtulach@1334: * @param month the month in the given date.
jtulach@1334: * Month is 0-based. e.g., 0 for January.
jtulach@1334: * @param day the day-in-month of the given date.
jtulach@1334: * @param dayOfWeek the day-of-week of the given date.
jtulach@1334: * @param milliseconds the milliseconds in day in standard
jtulach@1334: * local time.
jtulach@1334: *
jtulach@1334: * @return the offset in milliseconds to add to GMT to get local time.
jtulach@1334: *
jtulach@1334: * @see Calendar#ZONE_OFFSET
jtulach@1334: * @see Calendar#DST_OFFSET
jtulach@1334: */
jtulach@1334: public abstract int getOffset(int era, int year, int month, int day,
jtulach@1334: int dayOfWeek, int milliseconds);
jtulach@1334:
jtulach@1334: /**
jtulach@1334: * Returns the offset of this time zone from UTC at the specified
jtulach@1334: * date. If Daylight Saving Time is in effect at the specified
jtulach@1334: * date, the offset value is adjusted with the amount of daylight
jtulach@1334: * saving.
jtulach@1334: *
jtulach@1334: * This method returns a historically correct offset value if an jtulach@1334: * underlying TimeZone implementation subclass supports historical jtulach@1334: * Daylight Saving Time schedule and GMT offset changes. jtulach@1334: * jtulach@1334: * @param date the date represented in milliseconds since January 1, 1970 00:00:00 GMT jtulach@1334: * @return the amount of time in milliseconds to add to UTC to get local time. jtulach@1334: * jtulach@1334: * @see Calendar#ZONE_OFFSET jtulach@1334: * @see Calendar#DST_OFFSET jtulach@1334: * @since 1.4 jtulach@1334: */ jtulach@1334: public int getOffset(long date) { jtulach@1334: if (inDaylightTime(new Date(date))) { jtulach@1334: return getRawOffset() + getDSTSavings(); jtulach@1334: } jtulach@1334: return getRawOffset(); jtulach@1334: } jtulach@1334: jtulach@1334: /** jtulach@1334: * Gets the raw GMT offset and the amount of daylight saving of this jtulach@1334: * time zone at the given time. jtulach@1334: * @param date the milliseconds (since January 1, 1970, jtulach@1334: * 00:00:00.000 GMT) at which the time zone offset and daylight jtulach@1334: * saving amount are found jtulach@1334: * @param offset an array of int where the raw GMT offset jtulach@1334: * (offset[0]) and daylight saving amount (offset[1]) are stored, jtulach@1334: * or null if those values are not needed. The method assumes that jtulach@1334: * the length of the given array is two or larger. jtulach@1334: * @return the total amount of the raw GMT offset and daylight jtulach@1334: * saving at the specified date. jtulach@1334: * jtulach@1334: * @see Calendar#ZONE_OFFSET jtulach@1334: * @see Calendar#DST_OFFSET jtulach@1334: */ jtulach@1334: int getOffsets(long date, int[] offsets) { jtulach@1334: int rawoffset = getRawOffset(); jtulach@1334: int dstoffset = 0; jtulach@1334: if (inDaylightTime(new Date(date))) { jtulach@1334: dstoffset = getDSTSavings(); jtulach@1334: } jtulach@1334: if (offsets != null) { jtulach@1334: offsets[0] = rawoffset; jtulach@1334: offsets[1] = dstoffset; jtulach@1334: } jtulach@1334: return rawoffset + dstoffset; jtulach@1334: } jtulach@1334: jtulach@1334: /** jtulach@1334: * Sets the base time zone offset to GMT. jtulach@1334: * This is the offset to add to UTC to get local time. jtulach@1334: *
jtulach@1334: * If an underlying TimeZone
implementation subclass
jtulach@1334: * supports historical GMT offset changes, the specified GMT
jtulach@1334: * offset is set as the latest GMT offset and the difference from
jtulach@1334: * the known latest GMT offset value is used to adjust all
jtulach@1334: * historical GMT offset values.
jtulach@1334: *
jtulach@1334: * @param offsetMillis the given base time zone offset to GMT.
jtulach@1334: */
jtulach@1334: abstract public void setRawOffset(int offsetMillis);
jtulach@1334:
jtulach@1334: /**
jtulach@1334: * Returns the amount of time in milliseconds to add to UTC to get
jtulach@1334: * standard time in this time zone. Because this value is not
jtulach@1334: * affected by daylight saving time, it is called raw
jtulach@1334: * offset.
jtulach@1334: *
jtulach@1334: * If an underlying TimeZone
implementation subclass
jtulach@1334: * supports historical GMT offset changes, the method returns the
jtulach@1334: * raw offset value of the current date. In Honolulu, for example,
jtulach@1334: * its raw offset changed from GMT-10:30 to GMT-10:00 in 1947, and
jtulach@1334: * this method always returns -36000000 milliseconds (i.e., -10
jtulach@1334: * hours).
jtulach@1334: *
jtulach@1334: * @return the amount of raw offset time in milliseconds to add to UTC.
jtulach@1334: * @see Calendar#ZONE_OFFSET
jtulach@1334: */
jtulach@1334: public abstract int getRawOffset();
jtulach@1334:
jtulach@1334: /**
jtulach@1334: * Gets the ID of this time zone.
jtulach@1334: * @return the ID of this time zone.
jtulach@1334: */
jtulach@1334: public String getID()
jtulach@1334: {
jtulach@1334: return ID;
jtulach@1334: }
jtulach@1334:
jtulach@1334: /**
jtulach@1334: * Sets the time zone ID. This does not change any other data in
jtulach@1334: * the time zone object.
jtulach@1334: * @param ID the new time zone ID.
jtulach@1334: */
jtulach@1334: public void setID(String ID)
jtulach@1334: {
jtulach@1334: if (ID == null) {
jtulach@1334: throw new NullPointerException();
jtulach@1334: }
jtulach@1334: this.ID = ID;
jtulach@1334: }
jtulach@1334:
jtulach@1334: /**
jtulach@1334: * Returns a long standard time name of this {@code TimeZone} suitable for
jtulach@1334: * presentation to the user in the default locale.
jtulach@1334: *
jtulach@1334: *
This method is equivalent to: jtulach@1334: *
jtulach@1334: * jtulach@1334: * @return the human-readable name of this time zone in the default locale. jtulach@1334: * @since 1.2 jtulach@1334: * @see #getDisplayName(boolean, int, Locale) jtulach@1334: * @see Locale#getDefault(Locale.Category) jtulach@1334: * @see Locale.Category jtulach@1334: */ jtulach@1334: public final String getDisplayName() { jtulach@1334: return getDisplayName(false, LONG, jtulach@1334: Locale.getDefault(Locale.Category.DISPLAY)); jtulach@1334: } jtulach@1334: jtulach@1334: /** jtulach@1334: * Returns a long standard time name of this {@code TimeZone} suitable for jtulach@1334: * presentation to the user in the specified {@code locale}. jtulach@1334: * jtulach@1334: *jtulach@1334: * getDisplayName(false, {@link #LONG}, jtulach@1334: * Locale.getDefault({@link Locale.Category#DISPLAY})) jtulach@1334: *
This method is equivalent to: jtulach@1334: *
jtulach@1334: * jtulach@1334: * @param locale the locale in which to supply the display name. jtulach@1334: * @return the human-readable name of this time zone in the given locale. jtulach@1334: * @exception NullPointerException if {@code locale} is {@code null}. jtulach@1334: * @since 1.2 jtulach@1334: * @see #getDisplayName(boolean, int, Locale) jtulach@1334: */ jtulach@1334: public final String getDisplayName(Locale locale) { jtulach@1334: return getDisplayName(false, LONG, locale); jtulach@1334: } jtulach@1334: jtulach@1334: /** jtulach@1334: * Returns a name in the specified {@code style} of this {@code TimeZone} jtulach@1334: * suitable for presentation to the user in the default locale. If the jtulach@1334: * specified {@code daylight} is {@code true}, a Daylight Saving Time name jtulach@1334: * is returned (even if this {@code TimeZone} doesn't observe Daylight Saving jtulach@1334: * Time). Otherwise, a Standard Time name is returned. jtulach@1334: * jtulach@1334: *jtulach@1334: * getDisplayName(false, {@link #LONG}, locale) jtulach@1334: *
This method is equivalent to: jtulach@1334: *
jtulach@1334: * jtulach@1334: * @param daylight {@code true} specifying a Daylight Saving Time name, or jtulach@1334: * {@code false} specifying a Standard Time name jtulach@1334: * @param style either {@link #LONG} or {@link #SHORT} jtulach@1334: * @return the human-readable name of this time zone in the default locale. jtulach@1334: * @exception IllegalArgumentException if {@code style} is invalid. jtulach@1334: * @since 1.2 jtulach@1334: * @see #getDisplayName(boolean, int, Locale) jtulach@1334: * @see Locale#getDefault(Locale.Category) jtulach@1334: * @see Locale.Category jtulach@1334: * @see java.text.DateFormatSymbols#getZoneStrings() jtulach@1334: */ jtulach@1334: public final String getDisplayName(boolean daylight, int style) { jtulach@1334: return getDisplayName(daylight, style, jtulach@1334: Locale.getDefault(Locale.Category.DISPLAY)); jtulach@1334: } jtulach@1334: jtulach@1334: /** jtulach@1334: * Returns a name in the specified {@code style} of this {@code TimeZone} jtulach@1334: * suitable for presentation to the user in the specified {@code jtulach@1334: * locale}. If the specified {@code daylight} is {@code true}, a Daylight jtulach@1334: * Saving Time name is returned (even if this {@code TimeZone} doesn't jtulach@1334: * observe Daylight Saving Time). Otherwise, a Standard Time name is jtulach@1334: * returned. jtulach@1334: * jtulach@1334: *jtulach@1334: * getDisplayName(daylight, style, jtulach@1334: * Locale.getDefault({@link Locale.Category#DISPLAY})) jtulach@1334: *
When looking up a time zone name, the {@linkplain
jtulach@1334: * ResourceBundle.Control#getCandidateLocales(String,Locale) default
jtulach@1334: * Locale
search path of ResourceBundle
} derived
jtulach@1334: * from the specified {@code locale} is used. (No {@linkplain
jtulach@1334: * ResourceBundle.Control#getFallbackLocale(String,Locale) fallback
jtulach@1334: * Locale
} search is performed.) If a time zone name in any
jtulach@1334: * {@code Locale} of the search path, including {@link Locale#ROOT}, is
jtulach@1334: * found, the name is returned. Otherwise, a string in the
jtulach@1334: * normalized custom ID format is returned.
jtulach@1334: *
jtulach@1334: * @param daylight {@code true} specifying a Daylight Saving Time name, or
jtulach@1334: * {@code false} specifying a Standard Time name
jtulach@1334: * @param style either {@link #LONG} or {@link #SHORT}
jtulach@1334: * @param locale the locale in which to supply the display name.
jtulach@1334: * @return the human-readable name of this time zone in the given locale.
jtulach@1334: * @exception IllegalArgumentException if {@code style} is invalid.
jtulach@1334: * @exception NullPointerException if {@code locale} is {@code null}.
jtulach@1334: * @since 1.2
jtulach@1334: * @see java.text.DateFormatSymbols#getZoneStrings()
jtulach@1334: */
jtulach@1334: public String getDisplayName(boolean daylight, int style, Locale locale) {
jtulach@1334: if (style != SHORT && style != LONG) {
jtulach@1334: throw new IllegalArgumentException("Illegal style: " + style);
jtulach@1334: }
jtulach@1334:
jtulach@1334: String id = getID();
jtulach@1334: String[] names = getDisplayNames(id, locale);
jtulach@1334: if (names == null) {
jtulach@1334: if (id.startsWith("GMT")) {
jtulach@1334: char sign = id.charAt(3);
jtulach@1334: if (sign == '+' || sign == '-') {
jtulach@1334: return id;
jtulach@1334: }
jtulach@1334: }
jtulach@1334: int offset = getRawOffset();
jtulach@1334: if (daylight) {
jtulach@1334: offset += getDSTSavings();
jtulach@1334: }
jaroslav@1340: // return ZoneInfoFile.toCustomID(offset);
jtulach@1334: }
jtulach@1334:
jtulach@1334: int index = daylight ? 3 : 1;
jtulach@1334: if (style == SHORT) {
jtulach@1334: index++;
jtulach@1334: }
jtulach@1334: return names[index];
jtulach@1334: }
jtulach@1334:
jtulach@1334: private static class DisplayNames {
jtulach@1334: // Cache for managing display names per timezone per locale
jtulach@1334: // The structure is:
jtulach@1334: // Map(key=id, value=SoftReference(Map(key=locale, value=displaynames)))
jtulach@1334: private static final Map