12ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller/* GENERATED SOURCE. DO NOT MODIFY. */
22ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /*
32ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller  *******************************************************************************
42ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller  * Copyright (C) 2005-2014, International Business Machines Corporation and    *
52ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller  * others. All Rights Reserved.                                                *
62ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller  *******************************************************************************
72ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller  */
82ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerpackage android.icu.impl;
92ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport java.io.IOException;
112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport java.io.ObjectInputStream;
122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport java.util.Arrays;
132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport java.util.Date;
142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport java.util.MissingResourceException;
152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport android.icu.util.AnnualTimeZoneRule;
172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport android.icu.util.BasicTimeZone;
182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport android.icu.util.Calendar;
192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport android.icu.util.DateTimeRule;
202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport android.icu.util.GregorianCalendar;
212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport android.icu.util.InitialTimeZoneRule;
222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport android.icu.util.SimpleTimeZone;
232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport android.icu.util.TimeArrayTimeZoneRule;
242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport android.icu.util.TimeZone;
252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport android.icu.util.TimeZoneRule;
262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport android.icu.util.TimeZoneTransition;
272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport android.icu.util.UResourceBundle;
282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller/**
302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * A time zone based on the Olson tz database.  Olson time zones change
312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * behavior over time.  The raw offset, rules, presence or absence of
322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * daylight savings time, and even the daylight savings amount can all
332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * vary.
342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * This class uses a resource bundle named "zoneinfo".  Zoneinfo is a
362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * table containing different kinds of resources.  In several places,
372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * zones are referred to using integers.  A zone's integer is a number
382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * from 0..n-1, where n is the number of zones, with the zones sorted
392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * in lexicographic order.
402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * 1. Zones.  These have keys corresponding to the Olson IDs, e.g.,
422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * "Asia/Shanghai".  Each resource describes the behavior of the given
432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * zone.  Zones come in two different formats.
442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *   a. Zone (table).  A zone is a table resource contains several
462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *   type of resources below:
472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *   - typeOffsets:intvector (Required)
492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *   Sets of UTC raw/dst offset pairs in seconds.  Entries at
512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *   2n represents raw offset and 2n+1 represents dst offset
522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *   paired with the raw offset at 2n.  The very first pair represents
532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *   the initial zone offset (before the first transition) always.
542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *   - trans:intvector (Optional)
562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *   List of transition times represented by 32bit seconds from the
582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *   epoch (1970-01-01T00:00Z) in ascending order.
592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *   - transPre32/transPost32:intvector (Optional)
612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *   List of transition times before/after 32bit minimum seconds.
632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *   Each time is represented by a pair of 32bit integer.
642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *   - typeMap:bin (Optional)
662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *   Array of bytes representing the mapping between each transition
682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *   time (transPre32/trans/transPost32) and its corresponding offset
692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *   data (typeOffsets).
702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *   - finalRule:string (Optional)
722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *   If a recurrent transition rule is applicable to a zone forever
742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *   after the final transition time, finalRule represents the rule
752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *   in Rules data.
762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *   - finalRaw:int (Optional)
782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *   When finalRule is available, finalRaw is required and specifies
802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *   the raw (base) offset of the rule.
812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *   - finalYear:int (Optional)
832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *   When finalRule is available, finalYear is required and specifies
852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *   the start year of the rule.
862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *   - links:intvector (Optional)
882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *   When this zone data is shared with other zones, links specifies
902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *   all zones including the zone itself.  Each zone is referenced by
912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *   integer index.
922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *  b. Link (int, length 1).  A link zone is an int resource.  The
942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *  integer is the zone number of the target zone.  The key of this
952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *  resource is an alternate name for the target zone.  This data
962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *  is corresponding to Link data in the tz database.
972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * 2. Rules.  These have keys corresponding to the Olson rule IDs,
1002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * with an underscore prepended, e.g., "_EU".  Each resource describes
1012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * the behavior of the given rule using an intvector, containing the
1022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * onset list, the cessation list, and the DST savings.  The onset and
1032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * cessation lists consist of the month, dowim, dow, time, and time
1042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * mode.  The end result is that the 11 integers describing the rule
1052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * can be passed directly into the SimpleTimeZone 13-argument
1062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * constructor (the other two arguments will be the raw offset, taken
1072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * from the complex zone element 5, and the ID string, which is not
1082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * used), with the times and the DST savings multiplied by 1000 to
1092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * scale from seconds to milliseconds.
1102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
1112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * 3. Regions.  An array specifies mapping between zones and regions.
1122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Each item is either a 2-letter ISO country code or "001"
1132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * (UN M.49 - World).  This data is generated from "zone.tab"
1142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * in the tz database.
115836e6b40a94ec3fb7545a76cb072960442b7eee9Neil Fuller * @hide Only a subset of ICU is exposed in Android
1162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */
1172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerpublic class OlsonTimeZone extends BasicTimeZone {
1182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
1192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    // Generated by serialver from JDK 1.4.1_01
1202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    static final long serialVersionUID = -6281977362477515376L;
1212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
1222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /* (non-Javadoc)
1231fba789ac68efdd9120a7373f49daef42833e674Neil Fuller     * @see android.icu.util.TimeZone#getOffset(int, int, int, int, int, int)
1242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
1252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    @Override
1262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public int getOffset(int era, int year, int month, int day, int dayOfWeek, int milliseconds) {
1272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (month < Calendar.JANUARY || month > Calendar.DECEMBER) {
1282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            throw new IllegalArgumentException("Month is not in the legal range: " +month);
1292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        } else {
1302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return getOffset(era, year, month, day, dayOfWeek, milliseconds, Grego.monthLength(year, month));
1312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
1322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
1332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
1342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
1352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * TimeZone API.
1362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
1372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public int getOffset(int era, int year, int month,int dom, int dow, int millis, int monthLength){
1382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
1392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if ((era != GregorianCalendar.AD && era != GregorianCalendar.BC)
1402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            || month < Calendar.JANUARY
1412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            || month > Calendar.DECEMBER
1422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            || dom < 1
1432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            || dom > monthLength
1442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            || dow < Calendar.SUNDAY
1452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            || dow > Calendar.SATURDAY
1462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            || millis < 0
1472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            || millis >= Grego.MILLIS_PER_DAY
1482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            || monthLength < 28
1492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            || monthLength > 31) {
1502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            throw new IllegalArgumentException();
1512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
1522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
1532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (era == GregorianCalendar.BC) {
1542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            year = -year;
1552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
1562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
1572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (finalZone != null && year >= finalStartYear) {
1582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return finalZone.getOffset(era, year, month, dom, dow, millis);
1592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
1602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
1612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // Compute local epoch millis from input fields
1622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        long time = Grego.fieldsToDay(year, month, dom) * Grego.MILLIS_PER_DAY + millis;
1632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
1642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int[] offsets = new int[2];
1652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        getHistoricalOffset(time, true, LOCAL_DST, LOCAL_STD, offsets);
1662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return offsets[0] + offsets[1];
1672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
1682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
1692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /* (non-Javadoc)
1701fba789ac68efdd9120a7373f49daef42833e674Neil Fuller     * @see android.icu.util.TimeZone#setRawOffset(int)
1712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
1722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    @Override
1732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public void setRawOffset(int offsetMillis) {
1742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (isFrozen()) {
1752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            throw new UnsupportedOperationException("Attempt to modify a frozen OlsonTimeZone instance.");
1762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
1772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
1782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (getRawOffset() == offsetMillis) {
1792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return;
1802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
1812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        long current = System.currentTimeMillis();
1822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
1832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (current < finalStartMillis) {
1842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            SimpleTimeZone stz = new SimpleTimeZone(offsetMillis, getID());
1852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
1862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            boolean bDst = useDaylightTime();
1872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (bDst) {
1882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                TimeZoneRule[] currentRules = getSimpleTimeZoneRulesNear(current);
1892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (currentRules.length != 3) {
1902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    // DST was observed at the beginning of this year, so useDaylightTime
1912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    // returned true.  getSimpleTimeZoneRulesNear requires at least one
1922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    // future transition for making a pair of rules.  This implementation
1932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    // rolls back the time before the latest offset transition.
1942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    TimeZoneTransition tzt = getPreviousTransition(current, false);
1952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    if (tzt != null) {
1962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        currentRules = getSimpleTimeZoneRulesNear(tzt.getTime() - 1);
1972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    }
1982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
1992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (currentRules.length == 3
2002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        && (currentRules[1] instanceof AnnualTimeZoneRule)
2012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        && (currentRules[2] instanceof AnnualTimeZoneRule)) {
2022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    // A pair of AnnualTimeZoneRule
2032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    AnnualTimeZoneRule r1 = (AnnualTimeZoneRule)currentRules[1];
2042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    AnnualTimeZoneRule r2 = (AnnualTimeZoneRule)currentRules[2];
2052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    DateTimeRule start, end;
2062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    int offset1 = r1.getRawOffset() + r1.getDSTSavings();
2072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    int offset2 = r2.getRawOffset() + r2.getDSTSavings();
2082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    int sav;
2092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    if (offset1 > offset2) {
2102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        start = r1.getRule();
2112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        end = r2.getRule();
2122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        sav = offset1 - offset2;
2132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    } else {
2142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        start = r2.getRule();
2152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        end = r1.getRule();
2162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        sav = offset2 - offset1;
2172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    }
2182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    // getSimpleTimeZoneRulesNear always return rules using DOW / WALL_TIME
2192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    stz.setStartRule(start.getRuleMonth(), start.getRuleWeekInMonth(), start.getRuleDayOfWeek(),
2202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                            start.getRuleMillisInDay());
2212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    stz.setEndRule(end.getRuleMonth(), end.getRuleWeekInMonth(), end.getRuleDayOfWeek(),
2222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                            end.getRuleMillisInDay());
2232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    // set DST saving amount and start year
2242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    stz.setDSTSavings(sav);
2252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                } else {
2262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    // This could only happen if last rule is DST
2272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    // and the rule used forever.  For example, Asia/Dhaka
2282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    // in tzdata2009i stays in DST forever.
2292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
2302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    // Hack - set DST starting at midnight on Jan 1st,
2312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    // ending 23:59:59.999 on Dec 31st
2322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    stz.setStartRule(0, 1, 0);
2332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    stz.setEndRule(11, 31, Grego.MILLIS_PER_DAY - 1);
2342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
2352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
2362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
2372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            int[] fields = Grego.timeToFields(current, null);
2382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
2392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            finalStartYear = fields[0];
2402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            finalStartMillis = Grego.fieldsToDay(fields[0], 0, 1);
2412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
2422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (bDst) {
2432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // we probably do not need to set start year of final rule
2442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // to finalzone itself, but we always do this for now.
2452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                stz.setStartYear(finalStartYear);
2462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
2472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
2482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            finalZone = stz;
2492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
2502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        } else {
2512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            finalZone.setRawOffset(offsetMillis);
2522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
2532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
2542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        transitionRulesInitialized = false;
2552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
2562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
2572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    @Override
2582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public Object clone() {
2592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (isFrozen()) {
2602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return this;
2612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
2622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return cloneAsThawed();
2632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
2642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
2652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
2662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * TimeZone API.
2672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
2682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    @Override
2692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public void getOffset(long date, boolean local, int[] offsets)  {
2702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (finalZone != null && date >= finalStartMillis) {
2712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            finalZone.getOffset(date, local, offsets);
2722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        } else {
2732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            getHistoricalOffset(date, local,
2742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    LOCAL_FORMER, LOCAL_LATTER, offsets);
2752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
2762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
2772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
2782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
2792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * {@inheritDoc}
2802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
2812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    @Override
2822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public void getOffsetFromLocal(long date,
2832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            int nonExistingTimeOpt, int duplicatedTimeOpt, int[] offsets) {
2842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (finalZone != null && date >= finalStartMillis) {
2852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            finalZone.getOffsetFromLocal(date, nonExistingTimeOpt, duplicatedTimeOpt, offsets);
2862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        } else {
2872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            getHistoricalOffset(date, true, nonExistingTimeOpt, duplicatedTimeOpt, offsets);
2882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
2892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
2902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
2912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /* (non-Javadoc)
2921fba789ac68efdd9120a7373f49daef42833e674Neil Fuller     * @see android.icu.util.TimeZone#getRawOffset()
2932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
2942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    @Override
2952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public int getRawOffset() {
2962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int[] ret = new int[2];
2972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        getOffset(System.currentTimeMillis(), false, ret);
2982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return ret[0];
2992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
3002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
3012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /* (non-Javadoc)
3021fba789ac68efdd9120a7373f49daef42833e674Neil Fuller     * @see android.icu.util.TimeZone#useDaylightTime()
3032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
3042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    @Override
3052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public boolean useDaylightTime() {
3062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // If DST was observed in 1942 (for example) but has never been
3072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // observed from 1943 to the present, most clients will expect
3082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // this method to return FALSE.  This method determines whether
3092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // DST is in use in the current year (at any point in the year)
3102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // and returns TRUE if so.
3112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        long current = System.currentTimeMillis();
3122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
3132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (finalZone != null && current >= finalStartMillis) {
3142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return (finalZone != null && finalZone.useDaylightTime());
3152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
3162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
3172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int[] fields = Grego.timeToFields(current, null);
3182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
3192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // Find start of this year, and start of next year
3202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        long start = Grego.fieldsToDay(fields[0], 0, 1) * SECONDS_PER_DAY;
3212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        long limit = Grego.fieldsToDay(fields[0] + 1, 0, 1) * SECONDS_PER_DAY;
3222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
3232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // Return TRUE if DST is observed at any time during the current
3242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // year.
3252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        for (int i = 0; i < transitionCount; ++i) {
3262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (transitionTimes64[i] >= limit) {
3272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                break;
3282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
3292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if ((transitionTimes64[i] >= start && dstOffsetAt(i) != 0)
3302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    || (transitionTimes64[i] > start && i > 0 && dstOffsetAt(i - 1) != 0)) {
3312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                return true;
3322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
3332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
3342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return false;
3352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
3362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
3372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /* (non-Javadoc)
3381fba789ac68efdd9120a7373f49daef42833e674Neil Fuller     * @see android.icu.util.TimeZone#observesDaylightTime()
3392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
3402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    @Override
3412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public boolean observesDaylightTime() {
3422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        long current = System.currentTimeMillis();
3432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
3442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (finalZone != null) {
3452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (finalZone.useDaylightTime()) {
3462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                return true;
3472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            } else if (current >= finalStartMillis) {
3482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                return false;
3492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
3502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
3512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
3522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // Return TRUE if DST is observed at any future time
3532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        long currentSec = Grego.floorDivide(current, Grego.MILLIS_PER_SECOND);
3542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int trsIdx = transitionCount - 1;
3552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (dstOffsetAt(trsIdx) != 0) {
3562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return true;
3572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
3582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        while (trsIdx >= 0) {
3592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (transitionTimes64[trsIdx] <= currentSec) {
3602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                break;
3612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
3622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (dstOffsetAt(trsIdx - 1) != 0) {
3632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                return true;
3642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
3652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            trsIdx--;
3662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
3672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return false;
3682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
3692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
3702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * TimeZone API
3712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Returns the amount of time to be added to local standard time
3722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * to get local wall clock time.
3732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
3742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    @Override
3752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public int getDSTSavings() {
3762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (finalZone != null){
3772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return finalZone.getDSTSavings();
3782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
3792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return super.getDSTSavings();
3802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
3812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
3822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /* (non-Javadoc)
3831fba789ac68efdd9120a7373f49daef42833e674Neil Fuller     * @see android.icu.util.TimeZone#inDaylightTime(java.util.Date)
3842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
3852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    @Override
3862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public boolean inDaylightTime(Date date) {
3872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int[] temp = new int[2];
3882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        getOffset(date.getTime(), false, temp);
3892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return temp[1] != 0;
3902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
3912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
3922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /* (non-Javadoc)
3931fba789ac68efdd9120a7373f49daef42833e674Neil Fuller     * @see android.icu.util.TimeZone#hasSameRules(android.icu.util.TimeZone)
3942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
3952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    @Override
3962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public boolean hasSameRules(TimeZone other) {
3972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (this == other) {
3982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return true;
3992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
4002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // The super class implementation only check raw offset and
4012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // use of daylight saving time.
4022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (!super.hasSameRules(other)) {
4032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return false;
4042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
4052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
4062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (!(other instanceof OlsonTimeZone)) {
4072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // We cannot reasonably compare rules in different types
4082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return false;
4092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
4102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
4112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // Check final zone
4122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        OlsonTimeZone o = (OlsonTimeZone)other;
4132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (finalZone == null) {
4142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (o.finalZone != null) {
4152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                return false;
4162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
4172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        } else {
4182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (o.finalZone == null
4192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    || finalStartYear != o.finalStartYear
4202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    || !(finalZone.hasSameRules(o.finalZone))) {
4212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                return false;
4222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
4232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
4242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // Check transitions
4252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // Note: The code below actually fails to compare two equivalent rules in
4262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // different representation properly.
4272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (transitionCount != o.transitionCount ||
4282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                !Arrays.equals(transitionTimes64, o.transitionTimes64) ||
4292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                typeCount != o.typeCount ||
4302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                !Arrays.equals(typeMapData, o.typeMapData) ||
4312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                !Arrays.equals(typeOffsets, o.typeOffsets)){
4322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return false;
4332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
4342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return true;
4352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
4362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
4372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
4382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Returns the canonical ID of this system time zone
4392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
4402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public String getCanonicalID() {
4412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (canonicalID == null) {
4422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            synchronized(this) {
4432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (canonicalID == null) {
4442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    canonicalID = getCanonicalID(getID());
4452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
4462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    assert(canonicalID != null);
4472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    if (canonicalID == null) {
4482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        // This should never happen...
4492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        canonicalID = getID();
4502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    }
4512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
4522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
4532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
4542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return canonicalID;
4552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
4562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
4572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
4582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Construct a GMT+0 zone with no transitions.  This is done when a
4592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * constructor fails so the resultant object is well-behaved.
4602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
4612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private void constructEmpty(){
4622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        transitionCount = 0;
4632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        transitionTimes64 = null;
4642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        typeMapData =  null;
4652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
4662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        typeCount = 1;
4672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        typeOffsets = new int[]{0,0};
4682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        finalZone = null;
4692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        finalStartYear = Integer.MAX_VALUE;
4702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        finalStartMillis = Double.MAX_VALUE;
4712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
4722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        transitionRulesInitialized = false;
4732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
4742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
4752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
4762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Construct from a resource bundle
4772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param top the top-level zoneinfo resource bundle.  This is used
4782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * to lookup the rule that `res' may refer to, if there is one.
4792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param res the resource bundle of the zone to be constructed
4802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param id time zone ID
4812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
4822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public OlsonTimeZone(UResourceBundle top, UResourceBundle res, String id){
4832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        super(id);
4842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        construct(top, res);
4852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
4862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
4872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private void construct(UResourceBundle top, UResourceBundle res){
4882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
4892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if ((top == null || res == null)) {
4902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            throw new IllegalArgumentException();
4912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
4922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if(DEBUG) System.out.println("OlsonTimeZone(" + res.getKey() +")");
4932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
4942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        UResourceBundle r;
4952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int[] transPre32, trans32, transPost32;
4962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        transPre32 = trans32 = transPost32 = null;
4972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
4982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        transitionCount = 0;
4992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
5002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // Pre-32bit second transitions
5012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        try {
5022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            r = res.get("transPre32");
5032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            transPre32 = r.getIntVector();
5042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (transPre32.length % 2 != 0) {
5052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // elements in the pre-32bit must be an even number
5062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                throw new IllegalArgumentException("Invalid Format");
5072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
5082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            transitionCount += transPre32.length / 2;
5092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        } catch (MissingResourceException e) {
5102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // Pre-32bit transition data is optional
5112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
5122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
5132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // 32bit second transitions
5142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        try {
5152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            r = res.get("trans");
5162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            trans32 = r.getIntVector();
5172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            transitionCount += trans32.length;
5182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        } catch (MissingResourceException e) {
5192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // 32bit transition data is optional
5202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
5212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
5222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // Post-32bit second transitions
5232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        try {
5242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            r = res.get("transPost32");
5252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            transPost32 = r.getIntVector();
5262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (transPost32.length % 2 != 0) {
5272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // elements in the post-32bit must be an even number
5282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                throw new IllegalArgumentException("Invalid Format");
5292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
5302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            transitionCount += transPost32.length / 2;
5312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        } catch (MissingResourceException e) {
5322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // Post-32bit transition data is optional
5332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
5342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
5352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (transitionCount > 0) {
5362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            transitionTimes64 = new long[transitionCount];
5372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            int idx = 0;
5382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (transPre32 != null) {
5392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                for (int i = 0; i < transPre32.length / 2; i++, idx++) {
5402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    transitionTimes64[idx] =
5412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        (((long)transPre32[i * 2]) & 0x00000000FFFFFFFFL) << 32
5422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        | (((long)transPre32[i * 2 + 1]) & 0x00000000FFFFFFFFL);
5432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
5442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
5452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (trans32 != null) {
5462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                for (int i = 0; i < trans32.length; i++, idx++) {
5472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    transitionTimes64[idx] = (long)trans32[i];
5482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
5492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
5502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (transPost32 != null) {
5512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                for (int i = 0; i < transPost32.length / 2; i++, idx++) {
5522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    transitionTimes64[idx] =
5532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        (((long)transPost32[i * 2]) & 0x00000000FFFFFFFFL) << 32
5542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        | (((long)transPost32[i * 2 + 1]) & 0x00000000FFFFFFFFL);
5552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
5562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
5572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        } else {
5582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            transitionTimes64 = null;
5592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
5602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
5612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // Type offsets list must be of even size, with size >= 2
5622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        r = res.get("typeOffsets");
5632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        typeOffsets = r.getIntVector();
5642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if ((typeOffsets.length < 2 || typeOffsets.length > 0x7FFE || typeOffsets.length % 2 != 0)) {
5652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            throw new IllegalArgumentException("Invalid Format");
5662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
5672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        typeCount = typeOffsets.length / 2;
5682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
5692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // Type map data must be of the same size as the transition count
5702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (transitionCount > 0) {
5712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            r = res.get("typeMap");
5722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            typeMapData = r.getBinary(null);
5732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (typeMapData.length != transitionCount) {
5742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                throw new IllegalArgumentException("Invalid Format");
5752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
5762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        } else {
5772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            typeMapData = null;
5782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
5792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
5802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // Process final rule and data, if any
5812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        finalZone = null;
5822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        finalStartYear = Integer.MAX_VALUE;
5832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        finalStartMillis = Double.MAX_VALUE;
5842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
5852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        String ruleID = null;
5862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        try {
5872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            ruleID = res.getString("finalRule");
5882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
5892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            r = res.get("finalRaw");
5902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            int ruleRaw = r.getInt() * Grego.MILLIS_PER_SECOND;
5912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            r = loadRule(top, ruleID);
5922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            int[] ruleData = r.getIntVector();
5932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
5942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (ruleData == null || ruleData.length != 11) {
5952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                throw new IllegalArgumentException("Invalid Format");
5962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
5972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            finalZone = new SimpleTimeZone(ruleRaw, "",
5982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    ruleData[0], ruleData[1], ruleData[2],
5992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    ruleData[3] * Grego.MILLIS_PER_SECOND,
6002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    ruleData[4],
6012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    ruleData[5], ruleData[6], ruleData[7],
6022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    ruleData[8] * Grego.MILLIS_PER_SECOND,
6032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    ruleData[9],
6042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    ruleData[10] * Grego.MILLIS_PER_SECOND);
6052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
6062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            r = res.get("finalYear");
6072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            finalStartYear = r.getInt();
6082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
6092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // Note: Setting finalStartYear to the finalZone is problematic.  When a date is around
6102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // year boundary, SimpleTimeZone may return false result when DST is observed at the
6112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // beginning of year.  We could apply safe margin (day or two), but when one of recurrent
6122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // rules falls around year boundary, it could return false result.  Without setting the
6132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // start year, finalZone works fine around the year boundary of the start year.
6142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
6152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // finalZone.setStartYear(finalStartYear);
6162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
6172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // Compute the millis for Jan 1, 0:00 GMT of the finalYear
6182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
6192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // Note: finalStartMillis is used for detecting either if
6202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // historic transition data or finalZone to be used.  In an
6212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // extreme edge case - for example, two transitions fall into
6222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // small windows of time around the year boundary, this may
6232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // result incorrect offset computation.  But I think it will
6242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // never happen practically.  Yoshito - Feb 20, 2010
6252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            finalStartMillis = Grego.fieldsToDay(finalStartYear, 0, 1) * Grego.MILLIS_PER_DAY;
6262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        } catch (MissingResourceException e) {
6272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (ruleID != null) {
6282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // ruleID is found, but missing other data required for
6292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // creating finalZone
6302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                throw new IllegalArgumentException("Invalid Format");
6312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
6322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
6332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
6342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
6352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    // This constructor is used for testing purpose only
6362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public OlsonTimeZone(String id){
6372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        super(id);
6382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        UResourceBundle top = UResourceBundle.getBundleInstance(ICUResourceBundle.ICU_BASE_NAME,
6392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                ZONEINFORES, ICUResourceBundle.ICU_DATA_CLASS_LOADER);
6402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        UResourceBundle res = ZoneMeta.openOlsonResource(top, id);
6412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        construct(top, res);
6422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (finalZone != null){
6432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            finalZone.setID(id);
6442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
6452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
6462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
6472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /* (non-Javadoc)
6481fba789ac68efdd9120a7373f49daef42833e674Neil Fuller     * @see android.icu.util.TimeZone#setID(java.lang.String)
6492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
6502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    @Override
6512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public void setID(String id){
6522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (isFrozen()) {
6532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            throw new UnsupportedOperationException("Attempt to modify a frozen OlsonTimeZone instance.");
6542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
6552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
6562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // Before updating the ID, preserve the original ID's canonical ID.
6572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (canonicalID == null) {
6582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            canonicalID = getCanonicalID(getID());
6592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            assert(canonicalID != null);
6602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (canonicalID == null) {
6612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // This should never happen...
6622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                canonicalID = getID();
6632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
6642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
6652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
6662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (finalZone != null){
6672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            finalZone.setID(id);
6682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
6692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        super.setID(id);
6702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        transitionRulesInitialized = false;
6712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
6722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
6732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    // Maximum absolute offset in seconds = 1 day.
6742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    // getHistoricalOffset uses this constant as safety margin of
6752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    // quick zone transition checking.
6762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static final int MAX_OFFSET_SECONDS = 86400; // 60 * 60 * 24;
6772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
6782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private void getHistoricalOffset(long date, boolean local,
6792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            int NonExistingTimeOpt, int DuplicatedTimeOpt, int[] offsets) {
6802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (transitionCount != 0) {
6812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            long sec = Grego.floorDivide(date, Grego.MILLIS_PER_SECOND);
6822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (!local && sec < transitionTimes64[0]) {
6832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // Before the first transition time
6842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                offsets[0] = initialRawOffset() * Grego.MILLIS_PER_SECOND;
6852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                offsets[1] = initialDstOffset() * Grego.MILLIS_PER_SECOND;
6862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            } else {
6872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // Linear search from the end is the fastest approach, since
6882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // most lookups will happen at/near the end.
6892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                int transIdx;
6902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                for (transIdx = transitionCount - 1; transIdx >= 0; transIdx--) {
6912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    long transition = transitionTimes64[transIdx];
6922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    if (local && (sec >= (transition - MAX_OFFSET_SECONDS))) {
6932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        int offsetBefore = zoneOffsetAt(transIdx - 1);
6942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        boolean dstBefore = dstOffsetAt(transIdx - 1) != 0;
6952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
6962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        int offsetAfter = zoneOffsetAt(transIdx);
6972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        boolean dstAfter = dstOffsetAt(transIdx) != 0;
6982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
6992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        boolean dstToStd = dstBefore && !dstAfter;
7002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        boolean stdToDst = !dstBefore && dstAfter;
7012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
7022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        if (offsetAfter - offsetBefore >= 0) {
7032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                            // Positive transition, which makes a non-existing local time range
7042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                            if (((NonExistingTimeOpt & STD_DST_MASK) == LOCAL_STD && dstToStd)
7052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                    || ((NonExistingTimeOpt & STD_DST_MASK) == LOCAL_DST && stdToDst)) {
7062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                transition += offsetBefore;
7072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                            } else if (((NonExistingTimeOpt & STD_DST_MASK) == LOCAL_STD && stdToDst)
7082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                    || ((NonExistingTimeOpt & STD_DST_MASK) == LOCAL_DST && dstToStd)) {
7092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                transition += offsetAfter;
7102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                            } else if ((NonExistingTimeOpt & FORMER_LATTER_MASK) == LOCAL_LATTER) {
7112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                transition += offsetBefore;
7122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                            } else {
7132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                // Interprets the time with rule before the transition,
7142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                // default for non-existing time range
7152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                transition += offsetAfter;
7162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                            }
7172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        } else {
7182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                            // Negative transition, which makes a duplicated local time range
7192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                            if (((DuplicatedTimeOpt & STD_DST_MASK) == LOCAL_STD && dstToStd)
7202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                    || ((DuplicatedTimeOpt & STD_DST_MASK) == LOCAL_DST && stdToDst)) {
7212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                transition += offsetAfter;
7222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                            } else if (((DuplicatedTimeOpt & STD_DST_MASK) == LOCAL_STD && stdToDst)
7232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                    || ((DuplicatedTimeOpt & STD_DST_MASK) == LOCAL_DST && dstToStd)) {
7242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                transition += offsetBefore;
7252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                            } else if ((DuplicatedTimeOpt & FORMER_LATTER_MASK) == LOCAL_FORMER) {
7262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                transition += offsetBefore;
7272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                            } else {
7282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                // Interprets the time with rule after the transition,
7292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                // default for duplicated local time range
7302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                transition += offsetAfter;
7312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                            }
7322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        }
7332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    }
7342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    if (sec >= transition) {
7352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        break;
7362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    }
7372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
7382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // transIdx could be -1 when local=true
7392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                offsets[0] = rawOffsetAt(transIdx) * Grego.MILLIS_PER_SECOND;
7402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                offsets[1] = dstOffsetAt(transIdx) * Grego.MILLIS_PER_SECOND;
7412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
7422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        } else {
7432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // No transitions, single pair of offsets only
7442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            offsets[0] = initialRawOffset() * Grego.MILLIS_PER_SECOND;
7452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            offsets[1] = initialDstOffset() * Grego.MILLIS_PER_SECOND;
7462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
7472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
7482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
7492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private int getInt(byte val){
7502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return val & 0xFF;
7512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
7522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
7532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*
7542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Following 3 methods return an offset at the given transition time index.
7552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * When the index is negative, return the initial offset.
7562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
7572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private int zoneOffsetAt(int transIdx) {
7582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int typeIdx = transIdx >= 0 ? getInt(typeMapData[transIdx]) * 2 : 0;
7592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return typeOffsets[typeIdx] + typeOffsets[typeIdx + 1];
7602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
7612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
7622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private int rawOffsetAt(int transIdx) {
7632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int typeIdx = transIdx >= 0 ? getInt(typeMapData[transIdx]) * 2 : 0;
7642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return typeOffsets[typeIdx];
7652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
7662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
7672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private int dstOffsetAt(int transIdx) {
7682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int typeIdx = transIdx >= 0 ? getInt(typeMapData[transIdx]) * 2 : 0;
7692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return typeOffsets[typeIdx + 1];
7702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
7712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
7722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private int initialRawOffset() {
7732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return typeOffsets[0];
7742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
7752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
7762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private int initialDstOffset() {
7772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return typeOffsets[1];
7782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
7792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
7802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    // temp
7812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    @Override
7822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public String toString() {
7832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        StringBuilder buf = new StringBuilder();
7842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        buf.append(super.toString());
7852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        buf.append('[');
7862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        buf.append("transitionCount=" + transitionCount);
7872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        buf.append(",typeCount=" + typeCount);
7882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        buf.append(",transitionTimes=");
7892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (transitionTimes64 != null) {
7902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            buf.append('[');
7912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            for (int i = 0; i < transitionTimes64.length; ++i) {
7922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (i > 0) {
7932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    buf.append(',');
7942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
7952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                buf.append(Long.toString(transitionTimes64[i]));
7962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
7972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            buf.append(']');
7982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        } else {
7992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            buf.append("null");
8002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
8012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        buf.append(",typeOffsets=");
8022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (typeOffsets != null) {
8032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            buf.append('[');
8042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            for (int i = 0; i < typeOffsets.length; ++i) {
8052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (i > 0) {
8062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    buf.append(',');
8072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
8082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                buf.append(Integer.toString(typeOffsets[i]));
8092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
8102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            buf.append(']');
8112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        } else {
8122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            buf.append("null");
8132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
8142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        buf.append(",typeMapData=");
8152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (typeMapData != null) {
8162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            buf.append('[');
8172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            for (int i = 0; i < typeMapData.length; ++i) {
8182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (i > 0) {
8192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    buf.append(',');
8202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
8212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                buf.append(Byte.toString(typeMapData[i]));
8222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
8232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        } else {
8242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            buf.append("null");
8252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
8262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        buf.append(",finalStartYear=" + finalStartYear);
8272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        buf.append(",finalStartMillis=" + finalStartMillis);
8282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        buf.append(",finalZone=" + finalZone);
8292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        buf.append(']');
8302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
8312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return buf.toString();
8322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
8332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
8342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
8352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Number of transitions, 0..~370
8362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
8372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private int transitionCount;
8382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
8392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
8402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Number of types, 1..255
8412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
8422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private int typeCount;
8432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
8442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
8452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Time of each transition in seconds from 1970 epoch.
8462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
8472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private long[] transitionTimes64;
8482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
8492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
8502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Offset from GMT in seconds for each type.
8512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Length is equal to typeCount
8522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
8532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private int[] typeOffsets;
8542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
8552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
8562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Type description data, consisting of transitionCount uint8_t
8572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * type indices (from 0..typeCount-1).
8582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Length is equal to transitionCount
8592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
8602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private byte[] typeMapData;
8612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
8622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
8632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * For year >= finalStartYear, the finalZone will be used.
8642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
8652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private int finalStartYear = Integer.MAX_VALUE;
8662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
8672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
8682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * For date >= finalStartMillis, the finalZone will be used.
8692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
8702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private double finalStartMillis = Double.MAX_VALUE;
8712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
8722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
8732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * A SimpleTimeZone that governs the behavior for years >= finalYear.
8742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * If and only if finalYear == INT32_MAX then finalZone == 0.
8752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
8762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private SimpleTimeZone finalZone = null; // owned, may be NULL
8772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
8782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
8792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * The canonical ID of this zone. Initialized when {@link #getCanonicalID()}
8802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * is invoked first time, or {@link #setID(String)} is called.
8812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
8822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private volatile String canonicalID = null;
8832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
8842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static final String ZONEINFORES = "zoneinfo64";
8852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
8862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static final boolean DEBUG = ICUDebug.enabled("olson");
8872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static final int SECONDS_PER_DAY = 24*60*60;
8882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
8892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static UResourceBundle loadRule(UResourceBundle top, String ruleid) {
8902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        UResourceBundle r = top.get("Rules");
8912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        r = r.get(ruleid);
8922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return r;
8932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
8942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
8952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    @Override
8962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public boolean equals(Object obj){
8972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (!super.equals(obj)) return false; // super does class check
8982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
8992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        OlsonTimeZone z = (OlsonTimeZone) obj;
9002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
9012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return (Utility.arrayEquals(typeMapData, z.typeMapData) ||
9022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                 // If the pointers are not equal, the zones may still
9032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                 // be equal if their rules and transitions are equal
9042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                 (finalStartYear == z.finalStartYear &&
9052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                  // Don't compare finalMillis; if finalYear is ==, so is finalMillis
9062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                  ((finalZone == null && z.finalZone == null) ||
9072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                   (finalZone != null && z.finalZone != null &&
9082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    finalZone.equals(z.finalZone)) &&
9092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                  transitionCount == z.transitionCount &&
9102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                  typeCount == z.typeCount &&
9112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                  Utility.arrayEquals(transitionTimes64, z.transitionTimes64) &&
9122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                  Utility.arrayEquals(typeOffsets, z.typeOffsets) &&
9132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                  Utility.arrayEquals(typeMapData, z.typeMapData)
9142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                  )));
9152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
9162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
9172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
9182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    @Override
9192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public int hashCode(){
9202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int ret =   (int)  (finalStartYear ^ (finalStartYear>>>4) +
9212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                   transitionCount ^ (transitionCount>>>6) +
9222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                   typeCount ^ (typeCount>>>8) +
9232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                   Double.doubleToLongBits(finalStartMillis)+
9242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                   (finalZone == null ? 0 : finalZone.hashCode()) +
9252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                   super.hashCode());
9262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (transitionTimes64 != null) {
9272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            for(int i=0; i<transitionTimes64.length; i++){
9282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                ret+=transitionTimes64[i]^(transitionTimes64[i]>>>8);
9292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
9302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
9312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        for(int i=0; i<typeOffsets.length; i++){
9322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            ret+=typeOffsets[i]^(typeOffsets[i]>>>8);
9332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
9342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (typeMapData != null) {
9352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            for(int i=0; i<typeMapData.length; i++){
9362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                ret+=typeMapData[i] & 0xFF;
9372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
9382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
9392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return ret;
9402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
9412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
9422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    //
9432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    // BasicTimeZone methods
9442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    //
9452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
9462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /* (non-Javadoc)
9471fba789ac68efdd9120a7373f49daef42833e674Neil Fuller     * @see android.icu.util.BasicTimeZone#getNextTransition(long, boolean)
9482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
9492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    @Override
9502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public TimeZoneTransition getNextTransition(long base, boolean inclusive) {
9512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        initTransitionRules();
9522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
9532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (finalZone != null) {
9542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (inclusive && base == firstFinalTZTransition.getTime()) {
9552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                return firstFinalTZTransition;
9562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            } else if (base >= firstFinalTZTransition.getTime()) {
9572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (finalZone.useDaylightTime()) {
9582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    //return finalZone.getNextTransition(base, inclusive);
9592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    return finalZoneWithStartYear.getNextTransition(base, inclusive);
9602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                } else {
9612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    // No more transitions
9622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    return null;
9632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
9642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
9652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
9662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (historicRules != null) {
9672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // Find a historical transition
9682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            int ttidx = transitionCount - 1;
9692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            for (; ttidx >= firstTZTransitionIdx; ttidx--) {
9702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                long t = transitionTimes64[ttidx] * Grego.MILLIS_PER_SECOND;
9712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (base > t || (!inclusive && base == t)) {
9722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    break;
9732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
9742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
9752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (ttidx == transitionCount - 1)  {
9762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                return firstFinalTZTransition;
9772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            } else if (ttidx < firstTZTransitionIdx) {
9782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                return firstTZTransition;
9792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            } else {
9802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // Create a TimeZoneTransition
9812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                TimeZoneRule to = historicRules[getInt(typeMapData[ttidx + 1])];
9822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                TimeZoneRule from = historicRules[getInt(typeMapData[ttidx])];
9832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                long startTime = transitionTimes64[ttidx+1] * Grego.MILLIS_PER_SECOND;
9842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
9852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // The transitions loaded from zoneinfo.res may contain non-transition data
9862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (from.getName().equals(to.getName()) && from.getRawOffset() == to.getRawOffset()
9872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        && from.getDSTSavings() == to.getDSTSavings()) {
9882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    return getNextTransition(startTime, false);
9892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
9902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
9912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                return new TimeZoneTransition(startTime, from, to);
9922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
9932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
9942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return null;
9952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
9962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
9972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /* (non-Javadoc)
9981fba789ac68efdd9120a7373f49daef42833e674Neil Fuller     * @see android.icu.util.BasicTimeZone#getPreviousTransition(long, boolean)
9992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
10002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    @Override
10012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public TimeZoneTransition getPreviousTransition(long base, boolean inclusive) {
10022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        initTransitionRules();
10032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
10042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (finalZone != null) {
10052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (inclusive && base == firstFinalTZTransition.getTime()) {
10062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                return firstFinalTZTransition;
10072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            } else if (base > firstFinalTZTransition.getTime()) {
10082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (finalZone.useDaylightTime()) {
10092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    //return finalZone.getPreviousTransition(base, inclusive);
10102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    return finalZoneWithStartYear.getPreviousTransition(base, inclusive);
10112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                } else {
10122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    return firstFinalTZTransition;
10132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
10142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
10152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
10162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
10172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (historicRules != null) {
10182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // Find a historical transition
10192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            int ttidx = transitionCount - 1;
10202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            for (; ttidx >= firstTZTransitionIdx; ttidx--) {
10212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                long t = transitionTimes64[ttidx] * Grego.MILLIS_PER_SECOND;
10222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (base > t || (inclusive && base == t)) {
10232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    break;
10242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
10252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
10262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (ttidx < firstTZTransitionIdx) {
10272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // No more transitions
10282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                return null;
10292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            } else if (ttidx == firstTZTransitionIdx) {
10302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                return firstTZTransition;
10312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            } else {
10322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // Create a TimeZoneTransition
10332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                TimeZoneRule to = historicRules[getInt(typeMapData[ttidx])];
10342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                TimeZoneRule from = historicRules[getInt(typeMapData[ttidx-1])];
10352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                long startTime = transitionTimes64[ttidx] * Grego.MILLIS_PER_SECOND;
10362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
10372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // The transitions loaded from zoneinfo.res may contain non-transition data
10382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (from.getName().equals(to.getName()) && from.getRawOffset() == to.getRawOffset()
10392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        && from.getDSTSavings() == to.getDSTSavings()) {
10402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    return getPreviousTransition(startTime, false);
10412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
10422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
10432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                return new TimeZoneTransition(startTime, from, to);
10442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
10452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
10462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return null;
10472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
10482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
10492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /* (non-Javadoc)
10501fba789ac68efdd9120a7373f49daef42833e674Neil Fuller     * @see android.icu.util.BasicTimeZone#getTimeZoneRules()
10512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
10522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    @Override
10532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public TimeZoneRule[] getTimeZoneRules() {
10542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        initTransitionRules();
10552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int size = 1;
10562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (historicRules != null) {
10572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // historicRules may contain null entries when original zoneinfo data
10582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // includes non transition data.
10592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            for (int i = 0; i < historicRules.length; i++) {
10602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (historicRules[i] != null) {
10612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    size++;
10622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
10632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
10642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
10652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (finalZone != null) {
10662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (finalZone.useDaylightTime()) {
10672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                size += 2;
10682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            } else {
10692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                size++;
10702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
10712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
10722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
10732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        TimeZoneRule[] rules = new TimeZoneRule[size];
10742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int idx = 0;
10752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        rules[idx++] = initialRule;
10762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
10772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (historicRules != null) {
10782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            for (int i = 0; i < historicRules.length; i++) {
10792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (historicRules[i] != null) {
10802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    rules[idx++] = historicRules[i];
10812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
10822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
10832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         }
10842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
10852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (finalZone != null) {
10862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (finalZone.useDaylightTime()) {
10872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                TimeZoneRule[] stzr = finalZoneWithStartYear.getTimeZoneRules();
10882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // Adding only transition rules
10892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                rules[idx++] = stzr[1];
10902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                rules[idx++] = stzr[2];
10912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            } else {
10922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // Create a TimeArrayTimeZoneRule at finalMillis
10932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                rules[idx++] = new TimeArrayTimeZoneRule(getID() + "(STD)", finalZone.getRawOffset(), 0,
10942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        new long[] {(long)finalStartMillis}, DateTimeRule.UTC_TIME);
10952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
10962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
10972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return rules;
10982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
10992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
11002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private transient InitialTimeZoneRule initialRule;
11012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private transient TimeZoneTransition firstTZTransition;
11022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private transient int firstTZTransitionIdx;
11032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private transient TimeZoneTransition firstFinalTZTransition;
11042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private transient TimeArrayTimeZoneRule[] historicRules;
11052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private transient SimpleTimeZone finalZoneWithStartYear; // hack
11062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
11072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private transient boolean transitionRulesInitialized;
11082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
11092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private synchronized void initTransitionRules() {
11102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (transitionRulesInitialized) {
11112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return;
11122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
11132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
11142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        initialRule = null;
11152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        firstTZTransition = null;
11162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        firstFinalTZTransition = null;
11172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        historicRules = null;
11182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        firstTZTransitionIdx = 0;
11192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        finalZoneWithStartYear = null;
11202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
11212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        String stdName = getID() + "(STD)";
11222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        String dstName = getID() + "(DST)";
11232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
11242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int raw, dst;
11252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
11262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // Create initial rule
11272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        raw = initialRawOffset() * Grego.MILLIS_PER_SECOND;
11282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        dst = initialDstOffset() * Grego.MILLIS_PER_SECOND;
11292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        initialRule = new InitialTimeZoneRule((dst == 0 ? stdName : dstName), raw, dst);
11302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
11312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (transitionCount > 0) {
11322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            int transitionIdx, typeIdx;
11332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
11342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // We probably no longer need to check the first "real" transition
11352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // here, because the new tzcode remove such transitions already.
11362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // For now, keeping this code for just in case. Feb 19, 2010 Yoshito
11372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            for (transitionIdx = 0; transitionIdx < transitionCount; transitionIdx++) {
11382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (getInt(typeMapData[transitionIdx]) != 0) { // type 0 is the initial type
11392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    break;
11402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
11412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                firstTZTransitionIdx++;
11422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
11432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (transitionIdx == transitionCount) {
11442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // Actually no transitions...
11452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            } else {
11462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // Build historic rule array
11472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                long[] times = new long[transitionCount];
11482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                for (typeIdx = 0; typeIdx < typeCount; typeIdx++) {
11492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    // Gather all start times for each pair of offsets
11502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    int nTimes = 0;
11512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    for (transitionIdx = firstTZTransitionIdx; transitionIdx < transitionCount; transitionIdx++) {
11522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        if (typeIdx == getInt(typeMapData[transitionIdx])) {
11532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                            long tt = transitionTimes64[transitionIdx] * Grego.MILLIS_PER_SECOND;
11542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                            if (tt < finalStartMillis) {
11552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                // Exclude transitions after finalMillis
11562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                times[nTimes++] = tt;
11572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                            }
11582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        }
11592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    }
11602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    if (nTimes > 0) {
11612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        long[] startTimes = new long[nTimes];
11622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        System.arraycopy(times, 0, startTimes, 0, nTimes);
11632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        // Create a TimeArrayTimeZoneRule
11642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        raw = typeOffsets[typeIdx*2]*Grego.MILLIS_PER_SECOND;
11652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        dst = typeOffsets[typeIdx*2 + 1]*Grego.MILLIS_PER_SECOND;
11662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        if (historicRules == null) {
11672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                            historicRules = new TimeArrayTimeZoneRule[typeCount];
11682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        }
11692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        historicRules[typeIdx] = new TimeArrayTimeZoneRule((dst == 0 ? stdName : dstName),
11702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                raw, dst, startTimes, DateTimeRule.UTC_TIME);
11712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    }
11722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
11732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
11742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // Create initial transition
11752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                typeIdx = getInt(typeMapData[firstTZTransitionIdx]);
11762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                firstTZTransition = new TimeZoneTransition(transitionTimes64[firstTZTransitionIdx] * Grego.MILLIS_PER_SECOND,
11772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        initialRule, historicRules[typeIdx]);
11782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
11792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
11802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
11812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
11822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (finalZone != null) {
11832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // Get the first occurrence of final rule starts
11842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            long startTime = (long)finalStartMillis;
11852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            TimeZoneRule firstFinalRule;
11862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (finalZone.useDaylightTime()) {
11872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                /*
11882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                 * Note: When an OlsonTimeZone is constructed, we should set the final year
11892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                 * as the start year of finalZone.  However, the boundary condition used for
11902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                 * getting offset from finalZone has some problems.  So setting the start year
11912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                 * in the finalZone will cause a problem.  For now, we do not set the valid
11922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                 * start year when the construction time and create a clone and set the
11932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                 * start year when extracting rules.
11942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                 */
11952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                finalZoneWithStartYear = (SimpleTimeZone)finalZone.clone();
11962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                finalZoneWithStartYear.setStartYear(finalStartYear);
11972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
11982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                TimeZoneTransition tzt = finalZoneWithStartYear.getNextTransition(startTime, false);
11992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                firstFinalRule  = tzt.getTo();
12002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                startTime = tzt.getTime();
12012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            } else {
12022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                finalZoneWithStartYear = finalZone;
12032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                firstFinalRule = new TimeArrayTimeZoneRule(finalZone.getID(),
12042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        finalZone.getRawOffset(), 0, new long[] {startTime}, DateTimeRule.UTC_TIME);
12052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
12062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            TimeZoneRule prevRule = null;
12072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (transitionCount > 0) {
12082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                prevRule = historicRules[getInt(typeMapData[transitionCount - 1])];
12092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
12102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (prevRule == null) {
12112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // No historic transitions, but only finalZone available
12122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                prevRule = initialRule;
12132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
12142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            firstFinalTZTransition = new TimeZoneTransition(startTime, prevRule, firstFinalRule);
12152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
12162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
12172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        transitionRulesInitialized = true;
12182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
12192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
12202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    // Note: This class does not support back level serialization compatibility
12212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    // very well.  ICU 4.4 introduced the 64bit transition data.  It is probably
12222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    // possible to implement this class to make old version of ICU to deserialize
12232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    // object stream serialized by ICU 4.4+.  However, such implementation will
12242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    // introduce unnecessary complexity other than serialization support.
12252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    // I decided to provide minimum level of backward compatibility, which
12262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    // only support ICU 4.4+ to create an instance of OlsonTimeZone by reloading
12272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    // the zone rules from bundles.  ICU 4.2 or older version of ICU cannot
12282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    // deserialize object stream created by ICU 4.4+.  Yoshito -Feb 22, 2010
12292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
12302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static final int currentSerialVersion = 1;
12312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private int serialVersionOnStream = currentSerialVersion;
12322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
12332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException {
12342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        stream.defaultReadObject();
12352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
12362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (serialVersionOnStream < 1) {
12372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // No version - 4.2 or older
12382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // Just reloading the rule from bundle
12392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            boolean initialized = false;
12402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            String tzid = getID();
12412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (tzid != null) {
12422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                try {
12432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    UResourceBundle top = UResourceBundle.getBundleInstance(ICUResourceBundle.ICU_BASE_NAME,
12442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                            ZONEINFORES, ICUResourceBundle.ICU_DATA_CLASS_LOADER);
12452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    UResourceBundle res = ZoneMeta.openOlsonResource(top, tzid);
12462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    construct(top, res);
12472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    if (finalZone != null){
12482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        finalZone.setID(tzid);
12492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    }
12502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    initialized = true;
12512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                } catch (Exception e) {
12522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    // throw away
12532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
12542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
12552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (!initialized) {
12562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // final resort
12572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                constructEmpty();
12582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
12592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
12602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
12612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // need to rebuild transition rules when requested
12622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        transitionRulesInitialized = false;
12632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
12642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
12652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    // Freezable stuffs
12662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private transient volatile boolean isFrozen = false;
12672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
12682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /* (non-Javadoc)
12691fba789ac68efdd9120a7373f49daef42833e674Neil Fuller     * @see android.icu.util.TimeZone#isFrozen()
12702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
12712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public boolean isFrozen() {
12722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return isFrozen;
12732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
12742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
12752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /* (non-Javadoc)
12761fba789ac68efdd9120a7373f49daef42833e674Neil Fuller     * @see android.icu.util.TimeZone#freeze()
12772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
12782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public TimeZone freeze() {
12792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        isFrozen = true;
12802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return this;
12812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
12822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
12832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /* (non-Javadoc)
12841fba789ac68efdd9120a7373f49daef42833e674Neil Fuller     * @see android.icu.util.TimeZone#cloneAsThawed()
12852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
12862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public TimeZone cloneAsThawed() {
12872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        OlsonTimeZone tz = (OlsonTimeZone)super.cloneAsThawed();
12882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (finalZone != null) {
12892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // TODO Do we really need this?
12902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            finalZone.setID(getID());
12912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            tz.finalZone = (SimpleTimeZone) finalZone.clone();
12922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
12932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
12942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // Following data are read-only and never changed.
12952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // Therefore, shallow copies should be sufficient.
12962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        //
12972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // transitionTimes64
12982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // typeMapData
12992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // typeOffsets
13002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
13012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        tz.isFrozen = false;
13022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return tz;
13032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
13042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller}
1305