12ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller/* GENERATED SOURCE. DO NOT MODIFY. */ 2f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert// © 2016 and later: Unicode, Inc. and others. 3f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert// License & terms of use: http://www.unicode.org/copyright.html#License 42ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller/* 52ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller ******************************************************************************* 62ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Copyright (C) 2007-2014, International Business Machines Corporation and * 72ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * others. All Rights Reserved. * 82ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller ******************************************************************************* 92ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerpackage android.icu.util; 112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport java.util.ArrayList; 122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport java.util.BitSet; 132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport java.util.Date; 142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport java.util.List; 152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport android.icu.impl.Grego; 172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller/** 192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <code>RuleBasedTimeZone</code> is a concrete subclass of <code>TimeZone</code> that allows users to define 202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * custom historic time transition rules. 212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * 222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @see android.icu.util.TimeZoneRule 232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * 24836e6b40a94ec3fb7545a76cb072960442b7eee9Neil Fuller * @hide Only a subset of ICU is exposed in Android 252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerpublic class RuleBasedTimeZone extends BasicTimeZone { 272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller private static final long serialVersionUID = 7580833058949327935L; 292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller private final InitialTimeZoneRule initialRule; 312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller private List<TimeZoneRule> historicRules; 322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller private AnnualTimeZoneRule[] finalRules; 332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller private transient List<TimeZoneTransition> historicTransitions; 352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller private transient boolean upToDate; 362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Constructs a <code>RuleBasedTimeZone</code> object with the ID and the 392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <code>InitialTimeZoneRule</code> 402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * 412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @param id The time zone ID. 422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @param initialRule The initial time zone rule. 432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public RuleBasedTimeZone(String id, InitialTimeZoneRule initialRule) { 452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller super(id); 462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller this.initialRule = initialRule; 472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Adds the <code>TimeZoneRule</code> which represents time transitions. 512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * The <code>TimeZoneRule</code> must have start times, that is, the result 522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * of {@link android.icu.util.TimeZoneRule#isTransitionRule()} must be true. 532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Otherwise, <code>IllegalArgumentException</code> is thrown. 542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * 552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @param rule The <code>TimeZoneRule</code>. 562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public void addTransitionRule(TimeZoneRule rule) { 582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (isFrozen()) { 592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller throw new UnsupportedOperationException("Attempt to modify a frozen RuleBasedTimeZone instance."); 602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (!rule.isTransitionRule()) { 622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller throw new IllegalArgumentException("Rule must be a transition rule"); 632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (rule instanceof AnnualTimeZoneRule 652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller && ((AnnualTimeZoneRule)rule).getEndYear() == AnnualTimeZoneRule.MAX_YEAR) { 662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // One of the final rules applicable in future forever 672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (finalRules == null) { 682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller finalRules = new AnnualTimeZoneRule[2]; 692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller finalRules[0] = (AnnualTimeZoneRule)rule; 702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } else if (finalRules[1] == null) { 712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller finalRules[1] = (AnnualTimeZoneRule)rule; 722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } else { 732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // Only a pair of AnnualTimeZoneRule is allowed. 742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller throw new IllegalStateException("Too many final rules"); 752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } else { 772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // If this is not a final rule, add it to the historic rule list 782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (historicRules == null) { 792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller historicRules = new ArrayList<TimeZoneRule>(); 802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller historicRules.add(rule); 822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // Mark dirty, so transitions are recalculated when offset information is 842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // accessed next time. 852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller upToDate = false; 862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * {@inheritDoc} 902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller @Override 922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public int getOffset(int era, int year, int month, int day, int dayOfWeek, 932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller int milliseconds) { 942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (era == GregorianCalendar.BC) { 952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // Convert to extended year 962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller year = 1 - year; 972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller long time = Grego.fieldsToDay(year, month, day) * Grego.MILLIS_PER_DAY + milliseconds; 992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller int[] offsets = new int[2]; 1002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller getOffset(time, true, LOCAL_DST, LOCAL_STD, offsets); 1012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return (offsets[0] + offsets[1]); 1022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 1032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 1042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 1052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * {@inheritDoc} 1062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 1072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller @Override 1082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public void getOffset(long time, boolean local, int[] offsets) { 1092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller getOffset(time, local, LOCAL_FORMER, LOCAL_LATTER, offsets); 1102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 1112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 1122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 1132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * {@inheritDoc} 1142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @deprecated This API is ICU internal only. 115836e6b40a94ec3fb7545a76cb072960442b7eee9Neil Fuller * @hide draft / provisional / internal are hidden on Android 1162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 1172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller @Deprecated 1182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller @Override 1192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public void getOffsetFromLocal(long date, 1202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller int nonExistingTimeOpt, int duplicatedTimeOpt, int[] offsets) { 1212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller getOffset(date, true, nonExistingTimeOpt, duplicatedTimeOpt, offsets); 1222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 1232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 1242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 1252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * {@inheritDoc} 1262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 1272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller @Override 1282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public int getRawOffset() { 1292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // Note: This implementation returns standard GMT offset 1302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // as of current time. 1312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller long now = System.currentTimeMillis(); 1322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller int[] offsets = new int[2]; 1332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller getOffset(now, false, offsets); 1342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return offsets[0]; 1352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 1362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 1372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 1382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * {@inheritDoc} 1392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 1402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller @Override 1412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public boolean inDaylightTime(Date date) { 1422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller int[] offsets = new int[2]; 1432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller getOffset(date.getTime(), false, offsets); 1442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return (offsets[1] != 0); 1452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 1462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 1472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 1482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * {@inheritDoc} 1492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 1502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller @Override 1512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller ///CLOVER:OFF 1522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public void setRawOffset(int offsetMillis) { 1532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // TODO: Do nothing for now.. 1542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller throw new UnsupportedOperationException("setRawOffset in RuleBasedTimeZone is not supported."); 1552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 1562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller ///CLOVER:ON 1572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 1582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 1592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * {@inheritDoc} 1602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 1612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller @Override 1622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public boolean useDaylightTime() { 1632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // Note: This implementation returns true when 1642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // daylight saving time is used as of now or 1652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // after the next transition. 1662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller long now = System.currentTimeMillis(); 1672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller int[] offsets = new int[2]; 1682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller getOffset(now, false, offsets); 1692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (offsets[1] != 0) { 1702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return true; 1712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 1722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // If DST is not used now, check if DST is used after the next transition 1732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller TimeZoneTransition tt = getNextTransition(now, false); 1742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (tt != null && tt.getTo().getDSTSavings() != 0) { 1752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return true; 1762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 1772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return false; 1782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 1792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 1802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 1812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * {@inheritDoc} 1822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 1832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller @Override 1842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public boolean observesDaylightTime() { 1852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller long time = System.currentTimeMillis(); 1862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 1872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // Check if daylight saving time is observed now. 1882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller int[] offsets = new int[2]; 1892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller getOffset(time, false, offsets); 1902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (offsets[1] != 0) { 1912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return true; 1922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 1932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 1942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // If DST is not used now, check if DST is used after each transition. 1952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller BitSet checkFinals = finalRules == null ? null : new BitSet(finalRules.length); 1962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller while (true) { 1972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller TimeZoneTransition tt = getNextTransition(time, false); 1982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (tt == null) { 1992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // no more transition 2002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller break; 2012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 2022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller TimeZoneRule toRule = tt.getTo(); 2032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (toRule.getDSTSavings() != 0) { 2042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return true; 2052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 2062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (checkFinals != null) { 2072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // final rules exist - check if we saw all of them 2082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller for (int i = 0; i < finalRules.length; i++) { 2092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (finalRules[i].equals(toRule)) { 2102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller checkFinals.set(i); 2112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 2122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 2132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (checkFinals.cardinality() == finalRules.length) { 2142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // already saw all final rules 2152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller break; 2162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 2172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 2182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller time = tt.getTime(); 2192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 2202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return false; 2212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 2222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 2232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 2242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * {@inheritDoc} 2252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 2262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller @Override 2272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public boolean hasSameRules(TimeZone other) { 2282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (this == other) { 2292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return true; 2302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 2312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 2322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (!(other instanceof RuleBasedTimeZone)) { 2332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // We cannot reasonably compare rules in different types 2342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return false; 2352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 2362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller RuleBasedTimeZone otherRBTZ = (RuleBasedTimeZone)other; 2372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 2382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // initial rule 2392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (!initialRule.isEquivalentTo(otherRBTZ.initialRule)) { 2402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return false; 2412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 2422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 2432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // final rules 2442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (finalRules != null && otherRBTZ.finalRules != null) { 2452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller for (int i = 0; i < finalRules.length; i++) { 2462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (finalRules[i] == null && otherRBTZ.finalRules[i] == null) { 2472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller continue; 2482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 2492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (finalRules[i] != null && otherRBTZ.finalRules[i] != null 2502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller && finalRules[i].isEquivalentTo(otherRBTZ.finalRules[i])) { 2512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller continue; 2522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 2532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 2542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return false; 2552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 2562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } else if (finalRules != null || otherRBTZ.finalRules != null) { 2572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return false; 2582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 2592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 2602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // historic rules 2612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (historicRules != null && otherRBTZ.historicRules != null) { 2622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (historicRules.size() != otherRBTZ.historicRules.size()) { 2632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return false; 2642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 2652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller for (TimeZoneRule rule : historicRules) { 2662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller boolean foundSameRule = false; 2672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller for (TimeZoneRule orule : otherRBTZ.historicRules) { 2682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (rule.isEquivalentTo(orule)) { 2692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller foundSameRule = true; 2702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller break; 2712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 2722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 2732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (!foundSameRule) { 2742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return false; 2752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 2762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 2772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } else if (historicRules != null || otherRBTZ.historicRules != null) { 2782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return false; 2792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 2802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return true; 2812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 2822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 2832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // BasicTimeZone methods 2842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 2852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 2862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * {@inheritDoc} 2872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 2882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller @Override 2892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public TimeZoneRule[] getTimeZoneRules() { 2902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller int size = 1; 2912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (historicRules != null) { 2922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller size += historicRules.size(); 2932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 2942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 2952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (finalRules != null) { 2962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (finalRules[1] != null) { 2972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller size += 2; 2982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } else { 2992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller size++; 3002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 3012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 3022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller TimeZoneRule[] rules = new TimeZoneRule[size]; 3032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller rules[0] = initialRule; 3042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 3052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller int idx = 1; 3062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (historicRules != null) { 3072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller for (; idx < historicRules.size() + 1; idx++) { 3082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller rules[idx] = historicRules.get(idx - 1); 3092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 3102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 3112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (finalRules != null) { 3122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller rules[idx++] = finalRules[0]; 3132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (finalRules[1] != null) { 3142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller rules[idx] = finalRules[1]; 3152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 3162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 3172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return rules; 3182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 3192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 3202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 3212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * {@inheritDoc} 3222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 3232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller @Override 3242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public TimeZoneTransition getNextTransition(long base, boolean inclusive) { 3252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller complete(); 3262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (historicTransitions == null) { 3272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return null; 3282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 3292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller boolean isFinal = false; 330f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert TimeZoneTransition result; 3312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller TimeZoneTransition tzt = historicTransitions.get(0); 3322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller long tt = tzt.getTime(); 3332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (tt > base || (inclusive && tt == base)) { 3342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller result = tzt; 3352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } else { 3362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller int idx = historicTransitions.size() - 1; 3372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller tzt = historicTransitions.get(idx); 3382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller tt = tzt.getTime(); 3392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (inclusive && tt == base) { 3402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller result = tzt; 3412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } else if (tt <= base) { 3422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (finalRules != null) { 3432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // Find a transion time with finalRules 3442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller Date start0 = finalRules[0].getNextStart(base, 3452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller finalRules[1].getRawOffset(), finalRules[1].getDSTSavings(), inclusive); 3462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller Date start1 = finalRules[1].getNextStart(base, 3472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller finalRules[0].getRawOffset(), finalRules[0].getDSTSavings(), inclusive); 3482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 3492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (start1.after(start0)) { 3502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller tzt = new TimeZoneTransition(start0.getTime(), finalRules[1], finalRules[0]); 3512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } else { 3522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller tzt = new TimeZoneTransition(start1.getTime(), finalRules[0], finalRules[1]); 3532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 3542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller result = tzt; 3552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller isFinal = true; 3562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } else { 3572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return null; 3582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 3592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } else { 3602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // Find a transition within the historic transitions 3612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller idx--; 3622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller TimeZoneTransition prev = tzt; 3632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller while (idx > 0) { 3642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller tzt = historicTransitions.get(idx); 3652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller tt = tzt.getTime(); 3662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (tt < base || (!inclusive && tt == base)) { 3672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller break; 3682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 3692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller idx--; 3702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller prev = tzt; 3712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 3722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller result = prev; 3732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 3742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 375f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert // For now, this implementation ignore transitions with only zone name changes. 376f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert TimeZoneRule from = result.getFrom(); 377f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert TimeZoneRule to = result.getTo(); 378f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert if (from.getRawOffset() == to.getRawOffset() 379f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert && from.getDSTSavings() == to.getDSTSavings()) { 380f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert // No offset changes. Try next one if not final 381f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert if (isFinal) { 382f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert return null; 383f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert } else { 384f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert result = getNextTransition(result.getTime(), false /* always exclusive */); 3852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 3862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 3872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return result; 3882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 3892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 3902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 3912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * {@inheritDoc} 3922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 3932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller @Override 3942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public TimeZoneTransition getPreviousTransition(long base, boolean inclusive) { 3952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller complete(); 3962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (historicTransitions == null) { 3972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return null; 3982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 399f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert TimeZoneTransition result; 4002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller TimeZoneTransition tzt = historicTransitions.get(0); 4012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller long tt = tzt.getTime(); 4022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (inclusive && tt == base) { 4032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller result = tzt; 4042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } else if (tt >= base) { 4052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return null; 4062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } else { 4072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller int idx = historicTransitions.size() - 1; 4082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller tzt = historicTransitions.get(idx); 4092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller tt = tzt.getTime(); 4102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (inclusive && tt == base) { 4112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller result = tzt; 4122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } else if (tt < base) { 4132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (finalRules != null) { 4142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // Find a transion time with finalRules 4152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller Date start0 = finalRules[0].getPreviousStart(base, 4162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller finalRules[1].getRawOffset(), finalRules[1].getDSTSavings(), inclusive); 4172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller Date start1 = finalRules[1].getPreviousStart(base, 4182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller finalRules[0].getRawOffset(), finalRules[0].getDSTSavings(), inclusive); 4192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 4202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (start1.before(start0)) { 4212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller tzt = new TimeZoneTransition(start0.getTime(), finalRules[1], finalRules[0]); 4222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } else { 4232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller tzt = new TimeZoneTransition(start1.getTime(), finalRules[0], finalRules[1]); 4242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 4252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 4262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller result = tzt; 4272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } else { 4282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // Find a transition within the historic transitions 4292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller idx--; 4302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller while (idx >= 0) { 4312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller tzt = historicTransitions.get(idx); 4322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller tt = tzt.getTime(); 4332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (tt < base || (inclusive && tt == base)) { 4342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller break; 4352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 4362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller idx--; 4372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 4382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller result = tzt; 4392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 4402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 441f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert // For now, this implementation ignore transitions with only zone name changes. 442f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert TimeZoneRule from = result.getFrom(); 443f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert TimeZoneRule to = result.getTo(); 444f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert if (from.getRawOffset() == to.getRawOffset() 445f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert && from.getDSTSavings() == to.getDSTSavings()) { 446f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert // No offset changes. Try previous one 447f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert result = getPreviousTransition(result.getTime(), false /* always exclusive */); 4482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 4492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return result; 4502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 4512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 4522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 4532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * {@inheritDoc} 4542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 4552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller @Override 4562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public Object clone() { 4572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (isFrozen()) { 4582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return this; 4592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 4602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return cloneAsThawed(); 4612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 4622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 4632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // private stuff 4642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 4652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /* 4662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Resolve historic transition times and update fields used for offset 4672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * calculation. 4682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 4692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller private void complete() { 4702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (upToDate) { 4712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // No rules were added since last time. 4722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return; 4732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 4742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 4752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // Make sure either no final rules or a pair of AnnualTimeZoneRules 4762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // are available. 4772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (finalRules != null && finalRules[1] == null) { 4782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller throw new IllegalStateException("Incomplete final rules"); 4792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 4802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 4812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // Create a TimezoneTransition and add to the list 4822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (historicRules != null || finalRules != null) { 4832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller TimeZoneRule curRule = initialRule; 4842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller long lastTransitionTime = Grego.MIN_MILLIS; 4852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 4862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // Build the transition array which represents historical time zone 4872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // transitions. 4882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (historicRules != null) { 4892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller BitSet done = new BitSet(historicRules.size()); // for skipping rules already processed 4902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 4912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller while (true) { 4922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller int curStdOffset = curRule.getRawOffset(); 4932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller int curDstSavings = curRule.getDSTSavings(); 4942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller long nextTransitionTime = Grego.MAX_MILLIS; 4952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller TimeZoneRule nextRule = null; 4962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller Date d; 4972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller long tt; 4982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 4992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller for (int i = 0; i < historicRules.size(); i++) { 5002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (done.get(i)) { 5012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller continue; 5022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 5032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller TimeZoneRule r = historicRules.get(i); 5042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller d = r.getNextStart(lastTransitionTime, curStdOffset, curDstSavings, false); 5052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (d == null) { 5062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // No more transitions from this rule - skip this rule next time 5072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller done.set(i); 5082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } else { 5092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (r == curRule || 5102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller (r.getName().equals(curRule.getName()) 5112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller && r.getRawOffset() == curRule.getRawOffset() 5122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller && r.getDSTSavings() == curRule.getDSTSavings())) { 5132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller continue; 5142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 5152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller tt = d.getTime(); 5162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (tt < nextTransitionTime) { 5172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller nextTransitionTime = tt; 5182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller nextRule = r; 5192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 5202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 5212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 5222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 5232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (nextRule == null) { 5242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // Check if all historic rules are done 5252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller boolean bDoneAll = true; 5262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller for (int j = 0; j < historicRules.size(); j++) { 5272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (!done.get(j)) { 5282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller bDoneAll = false; 5292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller break; 5302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 5312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 5322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (bDoneAll) { 5332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller break; 5342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 5352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 5362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 5372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (finalRules != null) { 5382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // Check if one of final rules has earlier transition date 5392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller for (int i = 0; i < 2 /* finalRules.length */; i++) { 5402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (finalRules[i] == curRule) { 5412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller continue; 5422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 5432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller d = finalRules[i].getNextStart(lastTransitionTime, curStdOffset, curDstSavings, false); 5442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (d != null) { 5452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller tt = d.getTime(); 5462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (tt < nextTransitionTime) { 5472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller nextTransitionTime = tt; 5482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller nextRule = finalRules[i]; 5492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 5502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 5512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 5522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 5532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 5542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (nextRule == null) { 5552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // Nothing more 5562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller break; 5572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 5582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 5592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (historicTransitions == null) { 5602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller historicTransitions = new ArrayList<TimeZoneTransition>(); 5612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 5622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller historicTransitions.add(new TimeZoneTransition(nextTransitionTime, curRule, nextRule)); 5632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller lastTransitionTime = nextTransitionTime; 5642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller curRule = nextRule; 5652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 5662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 5672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (finalRules != null) { 5682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (historicTransitions == null) { 5692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller historicTransitions = new ArrayList<TimeZoneTransition>(); 5702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 5712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // Append the first transition for each 5722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller Date d0 = finalRules[0].getNextStart(lastTransitionTime, curRule.getRawOffset(), curRule.getDSTSavings(), false); 5732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller Date d1 = finalRules[1].getNextStart(lastTransitionTime, curRule.getRawOffset(), curRule.getDSTSavings(), false); 5742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (d1.after(d0)) { 5752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller historicTransitions.add(new TimeZoneTransition(d0.getTime(), curRule, finalRules[0])); 5762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller d1 = finalRules[1].getNextStart(d0.getTime(), finalRules[0].getRawOffset(), finalRules[0].getDSTSavings(), false); 5772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller historicTransitions.add(new TimeZoneTransition(d1.getTime(), finalRules[0], finalRules[1])); 5782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } else { 5792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller historicTransitions.add(new TimeZoneTransition(d1.getTime(), curRule, finalRules[1])); 5802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller d0 = finalRules[0].getNextStart(d1.getTime(), finalRules[1].getRawOffset(), finalRules[1].getDSTSavings(), false); 5812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller historicTransitions.add(new TimeZoneTransition(d0.getTime(), finalRules[1], finalRules[0])); 5822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 5832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 5842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 5852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller upToDate = true; 5862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 5872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 5882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /* 5892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * getOffset internal implementation 5902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 5912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller private void getOffset(long time, boolean local, int NonExistingTimeOpt, int DuplicatedTimeOpt, int[] offsets) { 5922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller complete(); 5932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller TimeZoneRule rule = null; 5942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (historicTransitions == null) { 5952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller rule = initialRule; 5962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } else { 5972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller long tstart = getTransitionTime(historicTransitions.get(0), 5982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller local, NonExistingTimeOpt, DuplicatedTimeOpt); 5992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (time < tstart) { 6002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller rule = initialRule; 6012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } else { 6022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller int idx = historicTransitions.size() - 1; 6032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller long tend = getTransitionTime(historicTransitions.get(idx), 6042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller local, NonExistingTimeOpt, DuplicatedTimeOpt); 6052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (time > tend) { 6062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (finalRules != null) { 6072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller rule = findRuleInFinal(time, local, NonExistingTimeOpt, DuplicatedTimeOpt); 6082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 6092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (rule == null) { 6102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // no final rules or the given time is before the first transition 6112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // specified by the final rules -> use the last rule 6122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller rule = (historicTransitions.get(idx)).getTo(); 6132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 6142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } else { 6152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // Find a historical transition 6162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller while (idx >= 0) { 6172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (time >= getTransitionTime(historicTransitions.get(idx), 6182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller local, NonExistingTimeOpt, DuplicatedTimeOpt)) { 6192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller break; 6202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 6212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller idx--; 6222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 6232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller rule = (historicTransitions.get(idx)).getTo(); 6242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 6252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 6262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 6272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller offsets[0] = rule.getRawOffset(); 6282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller offsets[1] = rule.getDSTSavings(); 6292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 6302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 6312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /* 6322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Find a time zone rule applicable to the specified time 6332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 6342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller private TimeZoneRule findRuleInFinal(long time, boolean local, int NonExistingTimeOpt, int DuplicatedTimeOpt) { 6352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (finalRules == null || finalRules.length != 2 || finalRules[0] == null || finalRules[1] == null) { 6362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return null; 6372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 6382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 6392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller Date start0, start1; 6402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller long base; 6412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller int localDelta; 6422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 6432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller base = time; 6442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (local) { 6452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller localDelta = getLocalDelta(finalRules[1].getRawOffset(), finalRules[1].getDSTSavings(), 6462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller finalRules[0].getRawOffset(), finalRules[0].getDSTSavings(), 6472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller NonExistingTimeOpt, DuplicatedTimeOpt); 6482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller base -= localDelta; 6492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 6502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller start0 = finalRules[0].getPreviousStart(base, finalRules[1].getRawOffset(), finalRules[1].getDSTSavings(), true); 6512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 6522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller base = time; 6532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (local) { 6542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller localDelta = getLocalDelta(finalRules[0].getRawOffset(), finalRules[0].getDSTSavings(), 6552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller finalRules[1].getRawOffset(), finalRules[1].getDSTSavings(), 6562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller NonExistingTimeOpt, DuplicatedTimeOpt); 6572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller base -= localDelta; 6582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 6592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller start1 = finalRules[1].getPreviousStart(base, finalRules[0].getRawOffset(), finalRules[0].getDSTSavings(), true); 6602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 6612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (start0 == null || start1 == null) { 6622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (start0 != null) { 6632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return finalRules[0]; 6642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } else if (start1 != null) { 6652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return finalRules[1]; 6662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 6672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // Both rules take effect after the given time 6682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return null; 6692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 6702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 6712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return start0.after(start1) ? finalRules[0] : finalRules[1]; 6722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 6732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 6742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /* 6752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Get the transition time in local wall clock 6762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 6772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller private static long getTransitionTime(TimeZoneTransition tzt, boolean local, 6782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller int NonExistingTimeOpt, int DuplicatedTimeOpt) { 6792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller long time = tzt.getTime(); 6802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (local) { 6812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller time += getLocalDelta(tzt.getFrom().getRawOffset(), tzt.getFrom().getDSTSavings(), 6822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller tzt.getTo().getRawOffset(), tzt.getTo().getDSTSavings(), 6832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller NonExistingTimeOpt, DuplicatedTimeOpt); 6842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 6852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return time; 6862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 6872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 6882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /* 6892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Returns amount of local time adjustment used for checking rule transitions 6902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 6912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller private static int getLocalDelta(int rawBefore, int dstBefore, int rawAfter, int dstAfter, 6922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller int NonExistingTimeOpt, int DuplicatedTimeOpt) { 6932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller int delta = 0; 6942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 6952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller int offsetBefore = rawBefore + dstBefore; 6962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller int offsetAfter = rawAfter + dstAfter; 6972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 6982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller boolean dstToStd = (dstBefore != 0) && (dstAfter == 0); 6992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller boolean stdToDst = (dstBefore == 0) && (dstAfter != 0); 7002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 7012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (offsetAfter - offsetBefore >= 0) { 7022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // Positive transition, which makes a non-existing local time range 7032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (((NonExistingTimeOpt & STD_DST_MASK) == LOCAL_STD && dstToStd) 7042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller || ((NonExistingTimeOpt & STD_DST_MASK) == LOCAL_DST && stdToDst)) { 7052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller delta = offsetBefore; 7062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } else if (((NonExistingTimeOpt & STD_DST_MASK) == LOCAL_STD && stdToDst) 7072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller || ((NonExistingTimeOpt & STD_DST_MASK) == LOCAL_DST && dstToStd)) { 7082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller delta = offsetAfter; 7092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } else if ((NonExistingTimeOpt & FORMER_LATTER_MASK) == LOCAL_LATTER) { 7102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller delta = offsetBefore; 7112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } else { 7122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // Interprets the time with rule before the transition, 7132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // default for non-existing time range 7142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller delta = offsetAfter; 7152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 7162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } else { 7172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // Negative transition, which makes a duplicated local time range 7182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (((DuplicatedTimeOpt & STD_DST_MASK) == LOCAL_STD && dstToStd) 7192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller || ((DuplicatedTimeOpt & STD_DST_MASK) == LOCAL_DST && stdToDst)) { 7202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller delta = offsetAfter; 7212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } else if (((DuplicatedTimeOpt & STD_DST_MASK) == LOCAL_STD && stdToDst) 7222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller || ((DuplicatedTimeOpt & STD_DST_MASK) == LOCAL_DST && dstToStd)) { 7232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller delta = offsetBefore; 7242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } else if ((DuplicatedTimeOpt & FORMER_LATTER_MASK) == LOCAL_FORMER) { 7252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller delta = offsetBefore; 7262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } else { 7272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // Interprets the time with rule after the transition, 7282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // default for duplicated local time range 7292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller delta = offsetAfter; 7302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 7312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 7322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return delta; 7332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 7342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 7352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // Freezable stuffs 7362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller private volatile transient boolean isFrozen = false; 7372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 7382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 7392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * {@inheritDoc} 7402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 7412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public boolean isFrozen() { 7422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return isFrozen; 7432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 7442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 7452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 7462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * {@inheritDoc} 7472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 7482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public TimeZone freeze() { 7492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller complete(); 7502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller isFrozen = true; 7512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return this; 7522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 7532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 7542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 7552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * {@inheritDoc} 7562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 7572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public TimeZone cloneAsThawed() { 7582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller RuleBasedTimeZone tz = (RuleBasedTimeZone)super.cloneAsThawed(); 7592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (historicRules != null) { 7602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller tz.historicRules = new ArrayList<TimeZoneRule>(historicRules); // rules are immutable 7612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 7622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (finalRules != null) { 7632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller tz.finalRules = finalRules.clone(); 7642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 7652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller tz.isFrozen = false; 7662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return tz; 7672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 7682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller} 7692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 770