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