12d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert// © 2016 and later: Unicode, Inc. and others. 22d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert// License & terms of use: http://www.unicode.org/copyright.html#License 37935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /* 47935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ******************************************************************************* 52d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert * Copyright (C) 2005-2016, International Business Machines Corporation and 62d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert * others. All Rights Reserved. 77935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ******************************************************************************* 87935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 97935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertpackage com.ibm.icu.impl; 107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.io.IOException; 127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.io.ObjectInputStream; 137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.Arrays; 147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.Date; 157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.MissingResourceException; 167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.util.AnnualTimeZoneRule; 187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.util.BasicTimeZone; 197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.util.Calendar; 207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.util.DateTimeRule; 217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.util.GregorianCalendar; 227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.util.InitialTimeZoneRule; 237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.util.SimpleTimeZone; 247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.util.TimeArrayTimeZoneRule; 257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.util.TimeZone; 267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.util.TimeZoneRule; 277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.util.TimeZoneTransition; 287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.util.UResourceBundle; 297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert/** 317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * A time zone based on the Olson tz database. Olson time zones change 327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * behavior over time. The raw offset, rules, presence or absence of 337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * daylight savings time, and even the daylight savings amount can all 347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * vary. 357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * This class uses a resource bundle named "zoneinfo". Zoneinfo is a 377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * table containing different kinds of resources. In several places, 387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * zones are referred to using integers. A zone's integer is a number 397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * from 0..n-1, where n is the number of zones, with the zones sorted 407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * in lexicographic order. 417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 1. Zones. These have keys corresponding to the Olson IDs, e.g., 437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * "Asia/Shanghai". Each resource describes the behavior of the given 447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * zone. Zones come in two different formats. 457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * a. Zone (table). A zone is a table resource contains several 477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * type of resources below: 482d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert * 497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * - typeOffsets:intvector (Required) 502d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert * 517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Sets of UTC raw/dst offset pairs in seconds. Entries at 527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 2n represents raw offset and 2n+1 represents dst offset 537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * paired with the raw offset at 2n. The very first pair represents 547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * the initial zone offset (before the first transition) always. 557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 562d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert * - trans:intvector (Optional) 572d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert * 587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * List of transition times represented by 32bit seconds from the 597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * epoch (1970-01-01T00:00Z) in ascending order. 602d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert * 617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * - transPre32/transPost32:intvector (Optional) 622d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert * 637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * List of transition times before/after 32bit minimum seconds. 647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Each time is represented by a pair of 32bit integer. 652d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert * 667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * - typeMap:bin (Optional) 672d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert * 687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Array of bytes representing the mapping between each transition 697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * time (transPre32/trans/transPost32) and its corresponding offset 707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * data (typeOffsets). 712d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert * 727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * - finalRule:string (Optional) 732d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert * 747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * If a recurrent transition rule is applicable to a zone forever 757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * after the final transition time, finalRule represents the rule 767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * in Rules data. 772d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert * 787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * - finalRaw:int (Optional) 792d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert * 807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * When finalRule is available, finalRaw is required and specifies 817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * the raw (base) offset of the rule. 822d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert * 837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * - finalYear:int (Optional) 842d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert * 857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * When finalRule is available, finalYear is required and specifies 867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * the start year of the rule. 872d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert * 887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * - links:intvector (Optional) 892d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert * 907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * When this zone data is shared with other zones, links specifies 917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * all zones including the zone itself. Each zone is referenced by 927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * integer index. 932d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert * 947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * b. Link (int, length 1). A link zone is an int resource. The 957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * integer is the zone number of the target zone. The key of this 967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * resource is an alternate name for the target zone. This data 977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * is corresponding to Link data in the tz database. 987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 1007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 2. Rules. These have keys corresponding to the Olson rule IDs, 1017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * with an underscore prepended, e.g., "_EU". Each resource describes 1027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * the behavior of the given rule using an intvector, containing the 1037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * onset list, the cessation list, and the DST savings. The onset and 1047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * cessation lists consist of the month, dowim, dow, time, and time 1057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * mode. The end result is that the 11 integers describing the rule 1067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * can be passed directly into the SimpleTimeZone 13-argument 1077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * constructor (the other two arguments will be the raw offset, taken 1087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * from the complex zone element 5, and the ID string, which is not 1097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * used), with the times and the DST savings multiplied by 1000 to 1107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * scale from seconds to milliseconds. 1117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 1127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 3. Regions. An array specifies mapping between zones and regions. 1137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Each item is either a 2-letter ISO country code or "001" 1147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * (UN M.49 - World). This data is generated from "zone.tab" 1157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * in the tz database. 1167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 1177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertpublic class OlsonTimeZone extends BasicTimeZone { 1187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Generated by serialver from JDK 1.4.1_01 1207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert static final long serialVersionUID = -6281977362477515376L; 1217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /* (non-Javadoc) 1237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @see com.ibm.icu.util.TimeZone#getOffset(int, int, int, int, int, int) 1247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 1257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Override 1267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public int getOffset(int era, int year, int month, int day, int dayOfWeek, int milliseconds) { 1277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (month < Calendar.JANUARY || month > Calendar.DECEMBER) { 1287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert throw new IllegalArgumentException("Month is not in the legal range: " +month); 1297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 1307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return getOffset(era, year, month, day, dayOfWeek, milliseconds, Grego.monthLength(year, month)); 1317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 1357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * TimeZone API. 1367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 1377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public int getOffset(int era, int year, int month,int dom, int dow, int millis, int monthLength){ 1387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if ((era != GregorianCalendar.AD && era != GregorianCalendar.BC) 1407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert || month < Calendar.JANUARY 1417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert || month > Calendar.DECEMBER 1427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert || dom < 1 1437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert || dom > monthLength 1447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert || dow < Calendar.SUNDAY 1457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert || dow > Calendar.SATURDAY 1467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert || millis < 0 1477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert || millis >= Grego.MILLIS_PER_DAY 1487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert || monthLength < 28 1497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert || monthLength > 31) { 1507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert throw new IllegalArgumentException(); 1517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (era == GregorianCalendar.BC) { 1547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert year = -year; 1557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (finalZone != null && year >= finalStartYear) { 1587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return finalZone.getOffset(era, year, month, dom, dow, millis); 1597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Compute local epoch millis from input fields 1627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert long time = Grego.fieldsToDay(year, month, dom) * Grego.MILLIS_PER_DAY + millis; 1637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int[] offsets = new int[2]; 1657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert getHistoricalOffset(time, true, LOCAL_DST, LOCAL_STD, offsets); 1667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return offsets[0] + offsets[1]; 1677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /* (non-Javadoc) 1707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @see com.ibm.icu.util.TimeZone#setRawOffset(int) 1717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 1727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Override 1737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public void setRawOffset(int offsetMillis) { 1747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (isFrozen()) { 1757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert throw new UnsupportedOperationException("Attempt to modify a frozen OlsonTimeZone instance."); 1767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (getRawOffset() == offsetMillis) { 1797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return; 1807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert long current = System.currentTimeMillis(); 1827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (current < finalStartMillis) { 1847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert SimpleTimeZone stz = new SimpleTimeZone(offsetMillis, getID()); 1857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert boolean bDst = useDaylightTime(); 1877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (bDst) { 1887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert TimeZoneRule[] currentRules = getSimpleTimeZoneRulesNear(current); 1897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (currentRules.length != 3) { 1907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // DST was observed at the beginning of this year, so useDaylightTime 1917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // returned true. getSimpleTimeZoneRulesNear requires at least one 1927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // future transition for making a pair of rules. This implementation 1937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // rolls back the time before the latest offset transition. 1947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert TimeZoneTransition tzt = getPreviousTransition(current, false); 1957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (tzt != null) { 1967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert currentRules = getSimpleTimeZoneRulesNear(tzt.getTime() - 1); 1977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (currentRules.length == 3 2007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert && (currentRules[1] instanceof AnnualTimeZoneRule) 2017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert && (currentRules[2] instanceof AnnualTimeZoneRule)) { 2027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // A pair of AnnualTimeZoneRule 2037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert AnnualTimeZoneRule r1 = (AnnualTimeZoneRule)currentRules[1]; 2047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert AnnualTimeZoneRule r2 = (AnnualTimeZoneRule)currentRules[2]; 2057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert DateTimeRule start, end; 2067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int offset1 = r1.getRawOffset() + r1.getDSTSavings(); 2077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int offset2 = r2.getRawOffset() + r2.getDSTSavings(); 2087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int sav; 2097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (offset1 > offset2) { 2107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert start = r1.getRule(); 2117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert end = r2.getRule(); 2127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert sav = offset1 - offset2; 2137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 2147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert start = r2.getRule(); 2157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert end = r1.getRule(); 2167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert sav = offset2 - offset1; 2177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // getSimpleTimeZoneRulesNear always return rules using DOW / WALL_TIME 2197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert stz.setStartRule(start.getRuleMonth(), start.getRuleWeekInMonth(), start.getRuleDayOfWeek(), 2207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert start.getRuleMillisInDay()); 2217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert stz.setEndRule(end.getRuleMonth(), end.getRuleWeekInMonth(), end.getRuleDayOfWeek(), 2227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert end.getRuleMillisInDay()); 2237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // set DST saving amount and start year 2247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert stz.setDSTSavings(sav); 2257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 2267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // This could only happen if last rule is DST 2277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // and the rule used forever. For example, Asia/Dhaka 2287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // in tzdata2009i stays in DST forever. 2297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Hack - set DST starting at midnight on Jan 1st, 2317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // ending 23:59:59.999 on Dec 31st 2327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert stz.setStartRule(0, 1, 0); 2337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert stz.setEndRule(11, 31, Grego.MILLIS_PER_DAY - 1); 2347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int[] fields = Grego.timeToFields(current, null); 2387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert finalStartYear = fields[0]; 2407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert finalStartMillis = Grego.fieldsToDay(fields[0], 0, 1); 2417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (bDst) { 2437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // we probably do not need to set start year of final rule 2447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // to finalzone itself, but we always do this for now. 2457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert stz.setStartYear(finalStartYear); 2467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert finalZone = stz; 2497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 2517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert finalZone.setRawOffset(offsetMillis); 2527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert transitionRulesInitialized = false; 2557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Override 2587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public Object clone() { 2597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (isFrozen()) { 2607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return this; 2617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return cloneAsThawed(); 2637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 2667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * TimeZone API. 2677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 2687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Override 2697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public void getOffset(long date, boolean local, int[] offsets) { 2707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (finalZone != null && date >= finalStartMillis) { 2717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert finalZone.getOffset(date, local, offsets); 2727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 2737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert getHistoricalOffset(date, local, 2747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert LOCAL_FORMER, LOCAL_LATTER, offsets); 2757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 2797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * {@inheritDoc} 2807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 2817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Override 2827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public void getOffsetFromLocal(long date, 2837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int nonExistingTimeOpt, int duplicatedTimeOpt, int[] offsets) { 2847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (finalZone != null && date >= finalStartMillis) { 2857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert finalZone.getOffsetFromLocal(date, nonExistingTimeOpt, duplicatedTimeOpt, offsets); 2867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 2877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert getHistoricalOffset(date, true, nonExistingTimeOpt, duplicatedTimeOpt, offsets); 2887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /* (non-Javadoc) 2927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @see com.ibm.icu.util.TimeZone#getRawOffset() 2937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 2947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Override 2957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public int getRawOffset() { 2967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int[] ret = new int[2]; 2977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert getOffset(System.currentTimeMillis(), false, ret); 2987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return ret[0]; 2997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 3017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /* (non-Javadoc) 3027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @see com.ibm.icu.util.TimeZone#useDaylightTime() 3037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 3047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Override 3057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public boolean useDaylightTime() { 3067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // If DST was observed in 1942 (for example) but has never been 3077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // observed from 1943 to the present, most clients will expect 3087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // this method to return FALSE. This method determines whether 3097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // DST is in use in the current year (at any point in the year) 3107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // and returns TRUE if so. 3117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert long current = System.currentTimeMillis(); 3127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 3137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (finalZone != null && current >= finalStartMillis) { 3147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return (finalZone != null && finalZone.useDaylightTime()); 3157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 3177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int[] fields = Grego.timeToFields(current, null); 3187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 3197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Find start of this year, and start of next year 3202d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert long start = Grego.fieldsToDay(fields[0], 0, 1) * SECONDS_PER_DAY; 3212d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert long limit = Grego.fieldsToDay(fields[0] + 1, 0, 1) * SECONDS_PER_DAY; 3227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 3237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Return TRUE if DST is observed at any time during the current 3247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // year. 3257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (int i = 0; i < transitionCount; ++i) { 3267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (transitionTimes64[i] >= limit) { 3277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert break; 3287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if ((transitionTimes64[i] >= start && dstOffsetAt(i) != 0) 3307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert || (transitionTimes64[i] > start && i > 0 && dstOffsetAt(i - 1) != 0)) { 3317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return true; 3327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return false; 3357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 3377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /* (non-Javadoc) 3387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @see com.ibm.icu.util.TimeZone#observesDaylightTime() 3397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 3407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Override 3417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public boolean observesDaylightTime() { 3427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert long current = System.currentTimeMillis(); 3437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 3447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (finalZone != null) { 3457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (finalZone.useDaylightTime()) { 3467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return true; 3477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else if (current >= finalStartMillis) { 3487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return false; 3497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 3527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Return TRUE if DST is observed at any future time 3537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert long currentSec = Grego.floorDivide(current, Grego.MILLIS_PER_SECOND); 3547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int trsIdx = transitionCount - 1; 3557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (dstOffsetAt(trsIdx) != 0) { 3567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return true; 3577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert while (trsIdx >= 0) { 3597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (transitionTimes64[trsIdx] <= currentSec) { 3607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert break; 3617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (dstOffsetAt(trsIdx - 1) != 0) { 3637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return true; 3647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert trsIdx--; 3667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return false; 3687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 3707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * TimeZone API 3717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Returns the amount of time to be added to local standard time 3727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * to get local wall clock time. 3737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 3747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Override 3757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public int getDSTSavings() { 3767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (finalZone != null){ 3777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return finalZone.getDSTSavings(); 3787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return super.getDSTSavings(); 3807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 3827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /* (non-Javadoc) 3837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @see com.ibm.icu.util.TimeZone#inDaylightTime(java.util.Date) 3847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 3857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Override 3867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public boolean inDaylightTime(Date date) { 3877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int[] temp = new int[2]; 3887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert getOffset(date.getTime(), false, temp); 3897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return temp[1] != 0; 3907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 3927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /* (non-Javadoc) 3937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @see com.ibm.icu.util.TimeZone#hasSameRules(com.ibm.icu.util.TimeZone) 3947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 3957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Override 3967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public boolean hasSameRules(TimeZone other) { 3977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (this == other) { 3987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return true; 3997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 4007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // The super class implementation only check raw offset and 4017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // use of daylight saving time. 4027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (!super.hasSameRules(other)) { 4037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return false; 4047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 4057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 4067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (!(other instanceof OlsonTimeZone)) { 4077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // We cannot reasonably compare rules in different types 4087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return false; 4097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 4107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 4117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Check final zone 4127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert OlsonTimeZone o = (OlsonTimeZone)other; 4137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (finalZone == null) { 4147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (o.finalZone != null) { 4157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return false; 4167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 4177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 4187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (o.finalZone == null 4197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert || finalStartYear != o.finalStartYear 4207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert || !(finalZone.hasSameRules(o.finalZone))) { 4217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return false; 4227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 4237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 4247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Check transitions 4257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Note: The code below actually fails to compare two equivalent rules in 4267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // different representation properly. 4277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (transitionCount != o.transitionCount || 4287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert !Arrays.equals(transitionTimes64, o.transitionTimes64) || 4297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert typeCount != o.typeCount || 4307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert !Arrays.equals(typeMapData, o.typeMapData) || 4317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert !Arrays.equals(typeOffsets, o.typeOffsets)){ 4327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return false; 4337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 4347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return true; 4357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 4367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 4377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 4387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Returns the canonical ID of this system time zone 4397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 4407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public String getCanonicalID() { 4417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (canonicalID == null) { 4427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert synchronized(this) { 4437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (canonicalID == null) { 4447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert canonicalID = getCanonicalID(getID()); 4457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 4467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert assert(canonicalID != null); 4477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (canonicalID == null) { 4487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // This should never happen... 4497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert canonicalID = getID(); 4507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 4517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 4527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 4537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 4547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return canonicalID; 4557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 4567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 4577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 4587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Construct a GMT+0 zone with no transitions. This is done when a 4597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * constructor fails so the resultant object is well-behaved. 4607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 4617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private void constructEmpty(){ 4627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert transitionCount = 0; 4637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert transitionTimes64 = null; 4647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert typeMapData = null; 4657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 4667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert typeCount = 1; 4677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert typeOffsets = new int[]{0,0}; 4687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert finalZone = null; 4697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert finalStartYear = Integer.MAX_VALUE; 4707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert finalStartMillis = Double.MAX_VALUE; 4717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 4727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert transitionRulesInitialized = false; 4737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 4747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 4757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 4767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Construct from a resource bundle 4777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param top the top-level zoneinfo resource bundle. This is used 4787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * to lookup the rule that `res' may refer to, if there is one. 4797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param res the resource bundle of the zone to be constructed 4807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param id time zone ID 4817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 4827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public OlsonTimeZone(UResourceBundle top, UResourceBundle res, String id){ 4837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert super(id); 4847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert construct(top, res); 4857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 4867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 4877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private void construct(UResourceBundle top, UResourceBundle res){ 4882d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert 4897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if ((top == null || res == null)) { 4907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert throw new IllegalArgumentException(); 4917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 4927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if(DEBUG) System.out.println("OlsonTimeZone(" + res.getKey() +")"); 4937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 4947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert UResourceBundle r; 4957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int[] transPre32, trans32, transPost32; 4967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert transPre32 = trans32 = transPost32 = null; 4977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 4987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert transitionCount = 0; 4997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 5007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Pre-32bit second transitions 5017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert try { 5027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert r = res.get("transPre32"); 5037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert transPre32 = r.getIntVector(); 5047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (transPre32.length % 2 != 0) { 5057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // elements in the pre-32bit must be an even number 5067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert throw new IllegalArgumentException("Invalid Format"); 5077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 5087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert transitionCount += transPre32.length / 2; 5097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } catch (MissingResourceException e) { 5107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Pre-32bit transition data is optional 5117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 5127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 5137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // 32bit second transitions 5147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert try { 5157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert r = res.get("trans"); 5167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert trans32 = r.getIntVector(); 5177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert transitionCount += trans32.length; 5187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } catch (MissingResourceException e) { 5197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // 32bit transition data is optional 5207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 5217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 5227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Post-32bit second transitions 5237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert try { 5247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert r = res.get("transPost32"); 5257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert transPost32 = r.getIntVector(); 5267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (transPost32.length % 2 != 0) { 5277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // elements in the post-32bit must be an even number 5287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert throw new IllegalArgumentException("Invalid Format"); 5297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 5307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert transitionCount += transPost32.length / 2; 5317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } catch (MissingResourceException e) { 5327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Post-32bit transition data is optional 5337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 5347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 5357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (transitionCount > 0) { 5367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert transitionTimes64 = new long[transitionCount]; 5377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int idx = 0; 5387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (transPre32 != null) { 5397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (int i = 0; i < transPre32.length / 2; i++, idx++) { 5402d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert transitionTimes64[idx] = 5412d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert ((transPre32[i * 2]) & 0x00000000FFFFFFFFL) << 32 5422d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert | ((transPre32[i * 2 + 1]) & 0x00000000FFFFFFFFL); 5437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 5447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 5457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (trans32 != null) { 5467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (int i = 0; i < trans32.length; i++, idx++) { 5472d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert transitionTimes64[idx] = trans32[i]; 5487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 5497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 5507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (transPost32 != null) { 5517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (int i = 0; i < transPost32.length / 2; i++, idx++) { 5522d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert transitionTimes64[idx] = 5532d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert ((transPost32[i * 2]) & 0x00000000FFFFFFFFL) << 32 5542d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert | ((transPost32[i * 2 + 1]) & 0x00000000FFFFFFFFL); 5557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 5567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 5577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 5587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert transitionTimes64 = null; 5597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 5607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 5617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Type offsets list must be of even size, with size >= 2 5627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert r = res.get("typeOffsets"); 5637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert typeOffsets = r.getIntVector(); 5647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if ((typeOffsets.length < 2 || typeOffsets.length > 0x7FFE || typeOffsets.length % 2 != 0)) { 5657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert throw new IllegalArgumentException("Invalid Format"); 5667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 5677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert typeCount = typeOffsets.length / 2; 5687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 5697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Type map data must be of the same size as the transition count 5707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (transitionCount > 0) { 5717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert r = res.get("typeMap"); 5727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert typeMapData = r.getBinary(null); 5732d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert if (typeMapData == null || typeMapData.length != transitionCount) { 5747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert throw new IllegalArgumentException("Invalid Format"); 5757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 5767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 5777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert typeMapData = null; 5787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 5797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 5807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Process final rule and data, if any 5817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert finalZone = null; 5827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert finalStartYear = Integer.MAX_VALUE; 5837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert finalStartMillis = Double.MAX_VALUE; 5847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 5857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String ruleID = null; 5867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert try { 5877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ruleID = res.getString("finalRule"); 5887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 5897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert r = res.get("finalRaw"); 5907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int ruleRaw = r.getInt() * Grego.MILLIS_PER_SECOND; 5917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert r = loadRule(top, ruleID); 5927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int[] ruleData = r.getIntVector(); 5937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 5947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (ruleData == null || ruleData.length != 11) { 5957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert throw new IllegalArgumentException("Invalid Format"); 5967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 5977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert finalZone = new SimpleTimeZone(ruleRaw, "", 5987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ruleData[0], ruleData[1], ruleData[2], 5997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ruleData[3] * Grego.MILLIS_PER_SECOND, 6007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ruleData[4], 6017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ruleData[5], ruleData[6], ruleData[7], 6027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ruleData[8] * Grego.MILLIS_PER_SECOND, 6037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ruleData[9], 6047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ruleData[10] * Grego.MILLIS_PER_SECOND); 6057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 6067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert r = res.get("finalYear"); 6077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert finalStartYear = r.getInt(); 6087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 6097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Note: Setting finalStartYear to the finalZone is problematic. When a date is around 6102d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert // year boundary, SimpleTimeZone may return false result when DST is observed at the 6117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // beginning of year. We could apply safe margin (day or two), but when one of recurrent 6127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // rules falls around year boundary, it could return false result. Without setting the 6137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // start year, finalZone works fine around the year boundary of the start year. 6147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 6157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // finalZone.setStartYear(finalStartYear); 6167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 6177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Compute the millis for Jan 1, 0:00 GMT of the finalYear 6187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 6197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Note: finalStartMillis is used for detecting either if 6207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // historic transition data or finalZone to be used. In an 6217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // extreme edge case - for example, two transitions fall into 6227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // small windows of time around the year boundary, this may 6237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // result incorrect offset computation. But I think it will 6247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // never happen practically. Yoshito - Feb 20, 2010 6257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert finalStartMillis = Grego.fieldsToDay(finalStartYear, 0, 1) * Grego.MILLIS_PER_DAY; 6267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } catch (MissingResourceException e) { 6277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (ruleID != null) { 6287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // ruleID is found, but missing other data required for 6297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // creating finalZone 6307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert throw new IllegalArgumentException("Invalid Format"); 6317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 6327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 6337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 6347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 6357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // This constructor is used for testing purpose only 6367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public OlsonTimeZone(String id){ 6377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert super(id); 6382d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert UResourceBundle top = UResourceBundle.getBundleInstance(ICUData.ICU_BASE_NAME, 6397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ZONEINFORES, ICUResourceBundle.ICU_DATA_CLASS_LOADER); 6407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert UResourceBundle res = ZoneMeta.openOlsonResource(top, id); 6417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert construct(top, res); 6427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (finalZone != null){ 6437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert finalZone.setID(id); 6447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 6457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 6467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 6477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /* (non-Javadoc) 6487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @see com.ibm.icu.util.TimeZone#setID(java.lang.String) 6497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 6507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Override 6517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public void setID(String id){ 6527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (isFrozen()) { 6537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert throw new UnsupportedOperationException("Attempt to modify a frozen OlsonTimeZone instance."); 6547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 6557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 6567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Before updating the ID, preserve the original ID's canonical ID. 6577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (canonicalID == null) { 6587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert canonicalID = getCanonicalID(getID()); 6597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert assert(canonicalID != null); 6607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (canonicalID == null) { 6617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // This should never happen... 6627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert canonicalID = getID(); 6637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 6647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 6657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 6667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (finalZone != null){ 6677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert finalZone.setID(id); 6687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 6697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert super.setID(id); 6707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert transitionRulesInitialized = false; 6717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 6727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 6737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Maximum absolute offset in seconds = 1 day. 6747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // getHistoricalOffset uses this constant as safety margin of 6757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // quick zone transition checking. 6767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static final int MAX_OFFSET_SECONDS = 86400; // 60 * 60 * 24; 6777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 6787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private void getHistoricalOffset(long date, boolean local, 6797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int NonExistingTimeOpt, int DuplicatedTimeOpt, int[] offsets) { 6807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (transitionCount != 0) { 6817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert long sec = Grego.floorDivide(date, Grego.MILLIS_PER_SECOND); 6827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (!local && sec < transitionTimes64[0]) { 6837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Before the first transition time 6847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert offsets[0] = initialRawOffset() * Grego.MILLIS_PER_SECOND; 6857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert offsets[1] = initialDstOffset() * Grego.MILLIS_PER_SECOND; 6867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 6877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Linear search from the end is the fastest approach, since 6887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // most lookups will happen at/near the end. 6897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int transIdx; 6907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (transIdx = transitionCount - 1; transIdx >= 0; transIdx--) { 6917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert long transition = transitionTimes64[transIdx]; 6927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (local && (sec >= (transition - MAX_OFFSET_SECONDS))) { 6937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int offsetBefore = zoneOffsetAt(transIdx - 1); 6947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert boolean dstBefore = dstOffsetAt(transIdx - 1) != 0; 6957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 6967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int offsetAfter = zoneOffsetAt(transIdx); 6977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert boolean dstAfter = dstOffsetAt(transIdx) != 0; 6987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 6997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert boolean dstToStd = dstBefore && !dstAfter; 7007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert boolean stdToDst = !dstBefore && dstAfter; 7017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 7027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (offsetAfter - offsetBefore >= 0) { 7037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Positive transition, which makes a non-existing local time range 7047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (((NonExistingTimeOpt & STD_DST_MASK) == LOCAL_STD && dstToStd) 7057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert || ((NonExistingTimeOpt & STD_DST_MASK) == LOCAL_DST && stdToDst)) { 7067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert transition += offsetBefore; 7077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else if (((NonExistingTimeOpt & STD_DST_MASK) == LOCAL_STD && stdToDst) 7087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert || ((NonExistingTimeOpt & STD_DST_MASK) == LOCAL_DST && dstToStd)) { 7097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert transition += offsetAfter; 7107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else if ((NonExistingTimeOpt & FORMER_LATTER_MASK) == LOCAL_LATTER) { 7117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert transition += offsetBefore; 7127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 7137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Interprets the time with rule before the transition, 7147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // default for non-existing time range 7157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert transition += offsetAfter; 7167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 7177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 7187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Negative transition, which makes a duplicated local time range 7197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (((DuplicatedTimeOpt & STD_DST_MASK) == LOCAL_STD && dstToStd) 7207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert || ((DuplicatedTimeOpt & STD_DST_MASK) == LOCAL_DST && stdToDst)) { 7217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert transition += offsetAfter; 7227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else if (((DuplicatedTimeOpt & STD_DST_MASK) == LOCAL_STD && stdToDst) 7237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert || ((DuplicatedTimeOpt & STD_DST_MASK) == LOCAL_DST && dstToStd)) { 7247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert transition += offsetBefore; 7257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else if ((DuplicatedTimeOpt & FORMER_LATTER_MASK) == LOCAL_FORMER) { 7267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert transition += offsetBefore; 7277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 7287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Interprets the time with rule after the transition, 7297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // default for duplicated local time range 7307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert transition += offsetAfter; 7317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 7327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 7337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 7347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (sec >= transition) { 7357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert break; 7367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 7377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 7387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // transIdx could be -1 when local=true 7397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert offsets[0] = rawOffsetAt(transIdx) * Grego.MILLIS_PER_SECOND; 7407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert offsets[1] = dstOffsetAt(transIdx) * Grego.MILLIS_PER_SECOND; 7417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 7427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 7437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // No transitions, single pair of offsets only 7447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert offsets[0] = initialRawOffset() * Grego.MILLIS_PER_SECOND; 7457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert offsets[1] = initialDstOffset() * Grego.MILLIS_PER_SECOND; 7467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 7477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 7487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 7497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private int getInt(byte val){ 7502d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert return val & 0xFF; 7517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 7527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 7537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /* 7547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Following 3 methods return an offset at the given transition time index. 7557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * When the index is negative, return the initial offset. 7567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 7577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private int zoneOffsetAt(int transIdx) { 7587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int typeIdx = transIdx >= 0 ? getInt(typeMapData[transIdx]) * 2 : 0; 7597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return typeOffsets[typeIdx] + typeOffsets[typeIdx + 1]; 7607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 7617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 7627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private int rawOffsetAt(int transIdx) { 7637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int typeIdx = transIdx >= 0 ? getInt(typeMapData[transIdx]) * 2 : 0; 7647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return typeOffsets[typeIdx]; 7657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 7667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 7677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private int dstOffsetAt(int transIdx) { 7687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int typeIdx = transIdx >= 0 ? getInt(typeMapData[transIdx]) * 2 : 0; 7697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return typeOffsets[typeIdx + 1]; 7707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 7717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 7727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private int initialRawOffset() { 7737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return typeOffsets[0]; 7747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 7757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 7767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private int initialDstOffset() { 7777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return typeOffsets[1]; 7787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 7797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 7807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // temp 7817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Override 7827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public String toString() { 7837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert StringBuilder buf = new StringBuilder(); 7847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert buf.append(super.toString()); 7857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert buf.append('['); 7867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert buf.append("transitionCount=" + transitionCount); 7877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert buf.append(",typeCount=" + typeCount); 7887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert buf.append(",transitionTimes="); 7897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (transitionTimes64 != null) { 7907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert buf.append('['); 7917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (int i = 0; i < transitionTimes64.length; ++i) { 7927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (i > 0) { 7937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert buf.append(','); 7947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 7957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert buf.append(Long.toString(transitionTimes64[i])); 7967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 7977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert buf.append(']'); 7987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 7997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert buf.append("null"); 8007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 8017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert buf.append(",typeOffsets="); 8027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (typeOffsets != null) { 8037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert buf.append('['); 8047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (int i = 0; i < typeOffsets.length; ++i) { 8057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (i > 0) { 8067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert buf.append(','); 8077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 8087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert buf.append(Integer.toString(typeOffsets[i])); 8097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 8107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert buf.append(']'); 8117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 8127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert buf.append("null"); 8137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 8147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert buf.append(",typeMapData="); 8157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (typeMapData != null) { 8167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert buf.append('['); 8177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (int i = 0; i < typeMapData.length; ++i) { 8187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (i > 0) { 8197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert buf.append(','); 8207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 8217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert buf.append(Byte.toString(typeMapData[i])); 8227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 8237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 8247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert buf.append("null"); 8257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 8267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert buf.append(",finalStartYear=" + finalStartYear); 8277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert buf.append(",finalStartMillis=" + finalStartMillis); 8287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert buf.append(",finalZone=" + finalZone); 8297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert buf.append(']'); 8302d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert 8317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return buf.toString(); 8327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 8337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 8347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 8357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Number of transitions, 0..~370 8367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 8377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private int transitionCount; 8387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 8397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 8407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Number of types, 1..255 8417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 8427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private int typeCount; 8437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 8447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 8457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Time of each transition in seconds from 1970 epoch. 8467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 8477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private long[] transitionTimes64; 8487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 8497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 8507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Offset from GMT in seconds for each type. 8517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Length is equal to typeCount 8527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 8537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private int[] typeOffsets; 8547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 8557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 8567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Type description data, consisting of transitionCount uint8_t 8577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * type indices (from 0..typeCount-1). 8587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Length is equal to transitionCount 8597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 8607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private byte[] typeMapData; 8617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 8627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 8637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * For year >= finalStartYear, the finalZone will be used. 8647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 8657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private int finalStartYear = Integer.MAX_VALUE; 8667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 8677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 8687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * For date >= finalStartMillis, the finalZone will be used. 8697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 8707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private double finalStartMillis = Double.MAX_VALUE; 8717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 8727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 8737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * A SimpleTimeZone that governs the behavior for years >= finalYear. 8747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * If and only if finalYear == INT32_MAX then finalZone == 0. 8757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 8767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private SimpleTimeZone finalZone = null; // owned, may be NULL 8772d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert 8787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 8797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * The canonical ID of this zone. Initialized when {@link #getCanonicalID()} 8807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * is invoked first time, or {@link #setID(String)} is called. 8817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 8827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private volatile String canonicalID = null; 8837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 8847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static final String ZONEINFORES = "zoneinfo64"; 8857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 8867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static final boolean DEBUG = ICUDebug.enabled("olson"); 8877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static final int SECONDS_PER_DAY = 24*60*60; 8882d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert 8897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static UResourceBundle loadRule(UResourceBundle top, String ruleid) { 8907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert UResourceBundle r = top.get("Rules"); 8917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert r = r.get(ruleid); 8927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return r; 8937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 8947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 8957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Override 8967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public boolean equals(Object obj){ 8977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (!super.equals(obj)) return false; // super does class check 8987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 8997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert OlsonTimeZone z = (OlsonTimeZone) obj; 9007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 9017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return (Utility.arrayEquals(typeMapData, z.typeMapData) || 9027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // If the pointers are not equal, the zones may still 9037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // be equal if their rules and transitions are equal 9047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert (finalStartYear == z.finalStartYear && 9057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Don't compare finalMillis; if finalYear is ==, so is finalMillis 9067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ((finalZone == null && z.finalZone == null) || 9077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert (finalZone != null && z.finalZone != null && 9087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert finalZone.equals(z.finalZone)) && 9097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert transitionCount == z.transitionCount && 9107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert typeCount == z.typeCount && 9117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Utility.arrayEquals(transitionTimes64, z.transitionTimes64) && 9127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Utility.arrayEquals(typeOffsets, z.typeOffsets) && 9137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Utility.arrayEquals(typeMapData, z.typeMapData) 9147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ))); 9157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 9167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 9177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 9187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Override 9197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public int hashCode(){ 9207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int ret = (int) (finalStartYear ^ (finalStartYear>>>4) + 9217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert transitionCount ^ (transitionCount>>>6) + 9222d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert typeCount ^ (typeCount>>>8) + 9237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Double.doubleToLongBits(finalStartMillis)+ 9242d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert (finalZone == null ? 0 : finalZone.hashCode()) + 9257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert super.hashCode()); 9267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (transitionTimes64 != null) { 9277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for(int i=0; i<transitionTimes64.length; i++){ 9287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ret+=transitionTimes64[i]^(transitionTimes64[i]>>>8); 9297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 9307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 9317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for(int i=0; i<typeOffsets.length; i++){ 9327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ret+=typeOffsets[i]^(typeOffsets[i]>>>8); 9337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 9347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (typeMapData != null) { 9357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for(int i=0; i<typeMapData.length; i++){ 9367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ret+=typeMapData[i] & 0xFF; 9372d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert } 9387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 9397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return ret; 9407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 9417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 9427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // 9437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // BasicTimeZone methods 9447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // 9457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 9467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /* (non-Javadoc) 9477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @see com.ibm.icu.util.BasicTimeZone#getNextTransition(long, boolean) 9487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 9497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Override 9507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public TimeZoneTransition getNextTransition(long base, boolean inclusive) { 9517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert initTransitionRules(); 9527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 9537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (finalZone != null) { 9547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (inclusive && base == firstFinalTZTransition.getTime()) { 9557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return firstFinalTZTransition; 9567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else if (base >= firstFinalTZTransition.getTime()) { 9577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (finalZone.useDaylightTime()) { 9587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert //return finalZone.getNextTransition(base, inclusive); 9597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return finalZoneWithStartYear.getNextTransition(base, inclusive); 9607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 9617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // No more transitions 9627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return null; 9637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 9647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 9657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 9667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (historicRules != null) { 9677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Find a historical transition 9687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int ttidx = transitionCount - 1; 9697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (; ttidx >= firstTZTransitionIdx; ttidx--) { 9707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert long t = transitionTimes64[ttidx] * Grego.MILLIS_PER_SECOND; 9717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (base > t || (!inclusive && base == t)) { 9727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert break; 9737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 9747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 9757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (ttidx == transitionCount - 1) { 9767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return firstFinalTZTransition; 9777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else if (ttidx < firstTZTransitionIdx) { 9787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return firstTZTransition; 9797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 9807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Create a TimeZoneTransition 9817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert TimeZoneRule to = historicRules[getInt(typeMapData[ttidx + 1])]; 9827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert TimeZoneRule from = historicRules[getInt(typeMapData[ttidx])]; 9837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert long startTime = transitionTimes64[ttidx+1] * Grego.MILLIS_PER_SECOND; 9847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 9857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // The transitions loaded from zoneinfo.res may contain non-transition data 9867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (from.getName().equals(to.getName()) && from.getRawOffset() == to.getRawOffset() 9877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert && from.getDSTSavings() == to.getDSTSavings()) { 9887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return getNextTransition(startTime, false); 9897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 9907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 9917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return new TimeZoneTransition(startTime, from, to); 9927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 9937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 9947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return null; 9957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 9967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 9977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /* (non-Javadoc) 9987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @see com.ibm.icu.util.BasicTimeZone#getPreviousTransition(long, boolean) 9997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 10007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Override 10017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public TimeZoneTransition getPreviousTransition(long base, boolean inclusive) { 10027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert initTransitionRules(); 10037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 10047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (finalZone != null) { 10057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (inclusive && base == firstFinalTZTransition.getTime()) { 10067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return firstFinalTZTransition; 10077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else if (base > firstFinalTZTransition.getTime()) { 10087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (finalZone.useDaylightTime()) { 10097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert //return finalZone.getPreviousTransition(base, inclusive); 10107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return finalZoneWithStartYear.getPreviousTransition(base, inclusive); 10117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 10127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return firstFinalTZTransition; 10132d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert } 10147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 10157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 10167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 10177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (historicRules != null) { 10187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Find a historical transition 10197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int ttidx = transitionCount - 1; 10207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (; ttidx >= firstTZTransitionIdx; ttidx--) { 10217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert long t = transitionTimes64[ttidx] * Grego.MILLIS_PER_SECOND; 10227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (base > t || (inclusive && base == t)) { 10237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert break; 10247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 10257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 10267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (ttidx < firstTZTransitionIdx) { 10277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // No more transitions 10287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return null; 10297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else if (ttidx == firstTZTransitionIdx) { 10307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return firstTZTransition; 10317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 10327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Create a TimeZoneTransition 10337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert TimeZoneRule to = historicRules[getInt(typeMapData[ttidx])]; 10347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert TimeZoneRule from = historicRules[getInt(typeMapData[ttidx-1])]; 10357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert long startTime = transitionTimes64[ttidx] * Grego.MILLIS_PER_SECOND; 10367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 10377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // The transitions loaded from zoneinfo.res may contain non-transition data 10387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (from.getName().equals(to.getName()) && from.getRawOffset() == to.getRawOffset() 10397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert && from.getDSTSavings() == to.getDSTSavings()) { 10407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return getPreviousTransition(startTime, false); 10417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 10427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 10437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return new TimeZoneTransition(startTime, from, to); 10447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 10457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 10467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return null; 10477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 10487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 10497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /* (non-Javadoc) 10507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @see com.ibm.icu.util.BasicTimeZone#getTimeZoneRules() 10517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 10527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Override 10537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public TimeZoneRule[] getTimeZoneRules() { 10547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert initTransitionRules(); 10557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int size = 1; 10567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (historicRules != null) { 10577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // historicRules may contain null entries when original zoneinfo data 10587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // includes non transition data. 10597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (int i = 0; i < historicRules.length; i++) { 10607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (historicRules[i] != null) { 10617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert size++; 10627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 10637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 10647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 10657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (finalZone != null) { 10667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (finalZone.useDaylightTime()) { 10677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert size += 2; 10687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 10697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert size++; 10707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 10717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 10727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 10737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert TimeZoneRule[] rules = new TimeZoneRule[size]; 10747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int idx = 0; 10757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert rules[idx++] = initialRule; 10767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 10777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (historicRules != null) { 10787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (int i = 0; i < historicRules.length; i++) { 10797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (historicRules[i] != null) { 10807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert rules[idx++] = historicRules[i]; 10817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 10827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 10837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 10847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 10857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (finalZone != null) { 10867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (finalZone.useDaylightTime()) { 10877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert TimeZoneRule[] stzr = finalZoneWithStartYear.getTimeZoneRules(); 10887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Adding only transition rules 10897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert rules[idx++] = stzr[1]; 10907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert rules[idx++] = stzr[2]; 10917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 10927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Create a TimeArrayTimeZoneRule at finalMillis 10937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert rules[idx++] = new TimeArrayTimeZoneRule(getID() + "(STD)", finalZone.getRawOffset(), 0, 10942d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert new long[] {(long)finalStartMillis}, DateTimeRule.UTC_TIME); 10957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 10967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 10977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return rules; 10987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 10997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 11007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private transient InitialTimeZoneRule initialRule; 11017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private transient TimeZoneTransition firstTZTransition; 11027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private transient int firstTZTransitionIdx; 11037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private transient TimeZoneTransition firstFinalTZTransition; 11047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private transient TimeArrayTimeZoneRule[] historicRules; 11057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private transient SimpleTimeZone finalZoneWithStartYear; // hack 11067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 11077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private transient boolean transitionRulesInitialized; 11087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 11097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private synchronized void initTransitionRules() { 11107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (transitionRulesInitialized) { 11117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return; 11127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 11137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 11147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert initialRule = null; 11157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert firstTZTransition = null; 11167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert firstFinalTZTransition = null; 11177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert historicRules = null; 11187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert firstTZTransitionIdx = 0; 11197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert finalZoneWithStartYear = null; 11207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 11217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String stdName = getID() + "(STD)"; 11227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String dstName = getID() + "(DST)"; 11237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 11247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int raw, dst; 11257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 11267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Create initial rule 11277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert raw = initialRawOffset() * Grego.MILLIS_PER_SECOND; 11287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert dst = initialDstOffset() * Grego.MILLIS_PER_SECOND; 11297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert initialRule = new InitialTimeZoneRule((dst == 0 ? stdName : dstName), raw, dst); 11307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 11317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (transitionCount > 0) { 11327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int transitionIdx, typeIdx; 11337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 11347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // We probably no longer need to check the first "real" transition 11357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // here, because the new tzcode remove such transitions already. 11367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // For now, keeping this code for just in case. Feb 19, 2010 Yoshito 11377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (transitionIdx = 0; transitionIdx < transitionCount; transitionIdx++) { 11387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (getInt(typeMapData[transitionIdx]) != 0) { // type 0 is the initial type 11397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert break; 11407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 11417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert firstTZTransitionIdx++; 11427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 11437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (transitionIdx == transitionCount) { 11447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Actually no transitions... 11457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 11467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Build historic rule array 11477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert long[] times = new long[transitionCount]; 11487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (typeIdx = 0; typeIdx < typeCount; typeIdx++) { 11497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Gather all start times for each pair of offsets 11507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int nTimes = 0; 11517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (transitionIdx = firstTZTransitionIdx; transitionIdx < transitionCount; transitionIdx++) { 11527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (typeIdx == getInt(typeMapData[transitionIdx])) { 11537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert long tt = transitionTimes64[transitionIdx] * Grego.MILLIS_PER_SECOND; 11547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (tt < finalStartMillis) { 11557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Exclude transitions after finalMillis 11567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert times[nTimes++] = tt; 11577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 11587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 11597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 11607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (nTimes > 0) { 11617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert long[] startTimes = new long[nTimes]; 11627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert System.arraycopy(times, 0, startTimes, 0, nTimes); 11637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Create a TimeArrayTimeZoneRule 11647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert raw = typeOffsets[typeIdx*2]*Grego.MILLIS_PER_SECOND; 11657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert dst = typeOffsets[typeIdx*2 + 1]*Grego.MILLIS_PER_SECOND; 11667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (historicRules == null) { 11677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert historicRules = new TimeArrayTimeZoneRule[typeCount]; 11687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 11697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert historicRules[typeIdx] = new TimeArrayTimeZoneRule((dst == 0 ? stdName : dstName), 11707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert raw, dst, startTimes, DateTimeRule.UTC_TIME); 11717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 11727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 11737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 11747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Create initial transition 11757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert typeIdx = getInt(typeMapData[firstTZTransitionIdx]); 11767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert firstTZTransition = new TimeZoneTransition(transitionTimes64[firstTZTransitionIdx] * Grego.MILLIS_PER_SECOND, 11777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert initialRule, historicRules[typeIdx]); 11782d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert 11797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 11807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 11817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 11827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (finalZone != null) { 11837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Get the first occurrence of final rule starts 11847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert long startTime = (long)finalStartMillis; 11857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert TimeZoneRule firstFinalRule; 11867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (finalZone.useDaylightTime()) { 11877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /* 11887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Note: When an OlsonTimeZone is constructed, we should set the final year 11897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * as the start year of finalZone. However, the boundary condition used for 11907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * getting offset from finalZone has some problems. So setting the start year 11917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * in the finalZone will cause a problem. For now, we do not set the valid 11927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * start year when the construction time and create a clone and set the 11937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * start year when extracting rules. 11947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 11957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert finalZoneWithStartYear = (SimpleTimeZone)finalZone.clone(); 11967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert finalZoneWithStartYear.setStartYear(finalStartYear); 11977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 11987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert TimeZoneTransition tzt = finalZoneWithStartYear.getNextTransition(startTime, false); 11997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert firstFinalRule = tzt.getTo(); 12007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert startTime = tzt.getTime(); 12017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 12027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert finalZoneWithStartYear = finalZone; 12037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert firstFinalRule = new TimeArrayTimeZoneRule(finalZone.getID(), 12047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert finalZone.getRawOffset(), 0, new long[] {startTime}, DateTimeRule.UTC_TIME); 12057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 12067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert TimeZoneRule prevRule = null; 12077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (transitionCount > 0) { 12087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert prevRule = historicRules[getInt(typeMapData[transitionCount - 1])]; 12097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 12107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (prevRule == null) { 12117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // No historic transitions, but only finalZone available 12127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert prevRule = initialRule; 12137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 12147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert firstFinalTZTransition = new TimeZoneTransition(startTime, prevRule, firstFinalRule); 12157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 12167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 12177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert transitionRulesInitialized = true; 12187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 12197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 12207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Note: This class does not support back level serialization compatibility 12217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // very well. ICU 4.4 introduced the 64bit transition data. It is probably 12227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // possible to implement this class to make old version of ICU to deserialize 12237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // object stream serialized by ICU 4.4+. However, such implementation will 12247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // introduce unnecessary complexity other than serialization support. 12257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // I decided to provide minimum level of backward compatibility, which 12267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // only support ICU 4.4+ to create an instance of OlsonTimeZone by reloading 12277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // the zone rules from bundles. ICU 4.2 or older version of ICU cannot 12287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // deserialize object stream created by ICU 4.4+. Yoshito -Feb 22, 2010 12297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 12307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static final int currentSerialVersion = 1; 12317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private int serialVersionOnStream = currentSerialVersion; 12327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 12337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException { 12347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert stream.defaultReadObject(); 12357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 12367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (serialVersionOnStream < 1) { 12377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // No version - 4.2 or older 12387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Just reloading the rule from bundle 12397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert boolean initialized = false; 12407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String tzid = getID(); 12417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (tzid != null) { 12427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert try { 12432d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert UResourceBundle top = UResourceBundle.getBundleInstance(ICUData.ICU_BASE_NAME, 12447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ZONEINFORES, ICUResourceBundle.ICU_DATA_CLASS_LOADER); 12457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert UResourceBundle res = ZoneMeta.openOlsonResource(top, tzid); 12467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert construct(top, res); 12477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (finalZone != null){ 12487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert finalZone.setID(tzid); 12497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 12507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert initialized = true; 12512d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert } catch (Exception ignored) { 12527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // throw away 12537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 12547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 12557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (!initialized) { 12567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // final resort 12577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert constructEmpty(); 12587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 12597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 12607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 12617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // need to rebuild transition rules when requested 12627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert transitionRulesInitialized = false; 12637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 12647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 12657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Freezable stuffs 12667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private transient volatile boolean isFrozen = false; 12677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 12687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /* (non-Javadoc) 12697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @see com.ibm.icu.util.TimeZone#isFrozen() 12707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 12712d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert @Override 12727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public boolean isFrozen() { 12737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return isFrozen; 12747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 12757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 12767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /* (non-Javadoc) 12777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @see com.ibm.icu.util.TimeZone#freeze() 12787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 12792d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert @Override 12807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public TimeZone freeze() { 12817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert isFrozen = true; 12827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return this; 12837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 12847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 12857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /* (non-Javadoc) 12867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @see com.ibm.icu.util.TimeZone#cloneAsThawed() 12877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 12882d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert @Override 12897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public TimeZone cloneAsThawed() { 12907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert OlsonTimeZone tz = (OlsonTimeZone)super.cloneAsThawed(); 12917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (finalZone != null) { 12927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // TODO Do we really need this? 12937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert finalZone.setID(getID()); 12947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert tz.finalZone = (SimpleTimeZone) finalZone.clone(); 12957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 12967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 12977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Following data are read-only and never changed. 12987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Therefore, shallow copies should be sufficient. 12997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // 13007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // transitionTimes64 13017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // typeMapData 13027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // typeOffsets 13037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 13047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert tz.isFrozen = false; 13057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return tz; 13067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 13077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert} 1308