1b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/*
2b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru*******************************************************************************
38393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius* Copyright (C) 2007-2013, International Business Machines Corporation and
427f654740f2a26ad62a5c155af9199af9e69b889claireho* others. All Rights Reserved.
5b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru*******************************************************************************
6b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru*/
7b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
854dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius#include "utypeinfo.h"  // for 'typeid' to work
927f654740f2a26ad62a5c155af9199af9e69b889claireho
10b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include "unicode/utypes.h"
11b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
12b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#if !UCONFIG_NO_FORMATTING
13b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
14b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include "unicode/rbtz.h"
15b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include "unicode/gregocal.h"
16b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include "uvector.h"
17b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include "gregoimp.h"
18b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include "cmemory.h"
198393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius#include "umutex.h"
20b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
21b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruU_NAMESPACE_BEGIN
22b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
23b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/**
24b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * A struct representing a time zone transition
25b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */
26b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querustruct Transition {
27b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    UDate time;
28b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    TimeZoneRule* from;
29b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    TimeZoneRule* to;
30b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru};
31b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
32b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querustatic UBool compareRules(UVector* rules1, UVector* rules2) {
33b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (rules1 == NULL && rules2 == NULL) {
34b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return TRUE;
35b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    } else if (rules1 == NULL || rules2 == NULL) {
36b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return FALSE;
37b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
38b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    int32_t size = rules1->size();
39b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (size != rules2->size()) {
40b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return FALSE;
41b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
42b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    for (int32_t i = 0; i < size; i++) {
43b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        TimeZoneRule *r1 = (TimeZoneRule*)rules1->elementAt(i);
44b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        TimeZoneRule *r2 = (TimeZoneRule*)rules2->elementAt(i);
45b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        if (*r1 != *r2) {
46b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            return FALSE;
47b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
48b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
49b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    return TRUE;
50b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
51b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
52b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruUOBJECT_DEFINE_RTTI_IMPLEMENTATION(RuleBasedTimeZone)
53b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
54b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruRuleBasedTimeZone::RuleBasedTimeZone(const UnicodeString& id, InitialTimeZoneRule* initialRule)
55b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru: BasicTimeZone(id), fInitialRule(initialRule), fHistoricRules(NULL), fFinalRules(NULL),
56b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru  fHistoricTransitions(NULL), fUpToDate(FALSE) {
57b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
58b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
59b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruRuleBasedTimeZone::RuleBasedTimeZone(const RuleBasedTimeZone& source)
60b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru: BasicTimeZone(source), fInitialRule(source.fInitialRule->clone()),
61b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru  fHistoricTransitions(NULL), fUpToDate(FALSE) {
62b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    fHistoricRules = copyRules(source.fHistoricRules);
63b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    fFinalRules = copyRules(source.fFinalRules);
64b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (source.fUpToDate) {
65b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        UErrorCode status = U_ZERO_ERROR;
66b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        complete(status);
67b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
68b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
69b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
70b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruRuleBasedTimeZone::~RuleBasedTimeZone() {
71b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    deleteTransitions();
72b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    deleteRules();
73b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
74b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
75b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruRuleBasedTimeZone&
76b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruRuleBasedTimeZone::operator=(const RuleBasedTimeZone& right) {
77b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (*this != right) {
78b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        BasicTimeZone::operator=(right);
79b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        deleteRules();
80b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        fInitialRule = right.fInitialRule->clone();
81b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        fHistoricRules = copyRules(right.fHistoricRules);
82b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        fFinalRules = copyRules(right.fFinalRules);
83b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        deleteTransitions();
84b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        fUpToDate = FALSE;
85b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
86b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    return *this;
87b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
88b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
89b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruUBool
90b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruRuleBasedTimeZone::operator==(const TimeZone& that) const {
91b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (this == &that) {
92b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return TRUE;
93b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
9427f654740f2a26ad62a5c155af9199af9e69b889claireho    if (typeid(*this) != typeid(that)
95b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        || BasicTimeZone::operator==(that) == FALSE) {
96b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return FALSE;
97b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
98b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    RuleBasedTimeZone *rbtz = (RuleBasedTimeZone*)&that;
99b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (*fInitialRule != *(rbtz->fInitialRule)) {
100b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return FALSE;
101b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
102b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (compareRules(fHistoricRules, rbtz->fHistoricRules)
103b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        && compareRules(fFinalRules, rbtz->fFinalRules)) {
104b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return TRUE;
105b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
106b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    return FALSE;
107b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
108b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
109b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruUBool
110b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruRuleBasedTimeZone::operator!=(const TimeZone& that) const {
111b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    return !operator==(that);
112b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
113b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
114b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruvoid
115b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruRuleBasedTimeZone::addTransitionRule(TimeZoneRule* rule, UErrorCode& status) {
116b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (U_FAILURE(status)) {
117b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return;
118b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
11927f654740f2a26ad62a5c155af9199af9e69b889claireho    AnnualTimeZoneRule* atzrule = dynamic_cast<AnnualTimeZoneRule*>(rule);
12027f654740f2a26ad62a5c155af9199af9e69b889claireho    if (atzrule != NULL && atzrule->getEndYear() == AnnualTimeZoneRule::MAX_YEAR) {
121b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // A final rule
122b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        if (fFinalRules == NULL) {
123b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            fFinalRules = new UVector(status);
124b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            if (U_FAILURE(status)) {
125b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                return;
126b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            }
127b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        } else if (fFinalRules->size() >= 2) {
128b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            // Cannot handle more than two final rules
129b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            status = U_INVALID_STATE_ERROR;
130b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            return;
131b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
132b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        fFinalRules->addElement((void*)rule, status);
133b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    } else {
134b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // Non-final rule
135b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        if (fHistoricRules == NULL) {
136b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            fHistoricRules = new UVector(status);
137b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            if (U_FAILURE(status)) {
138b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                return;
139b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            }
140b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
141b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        fHistoricRules->addElement((void*)rule, status);
142b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
143b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // Mark dirty, so transitions are recalculated at next complete() call
144b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    fUpToDate = FALSE;
145b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
146b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1478393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Corneliusstatic UMutex gLock = U_MUTEX_INITIALIZER;
1488393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius
1498393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Corneliusvoid
1508393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig CorneliusRuleBasedTimeZone::completeConst(UErrorCode& status) const {
1518393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    if (U_FAILURE(status)) {
1528393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius        return;
1538393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    }
1548393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    UBool updated;
1558393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    UMTX_CHECK(&gLock, fUpToDate, updated);
1568393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    if (!updated) {
1578393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius        umtx_lock(&gLock);
1588393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius        if (!fUpToDate) {
1598393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius            RuleBasedTimeZone *ncThis = const_cast<RuleBasedTimeZone*>(this);
1608393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius            ncThis->complete(status);
1618393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius        }
1628393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius        umtx_unlock(&gLock);
1638393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    }
1648393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius}
1658393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius
166b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruvoid
167b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruRuleBasedTimeZone::complete(UErrorCode& status) {
168b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (U_FAILURE(status)) {
169b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return;
170b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
171b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (fUpToDate) {
172b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return;
173b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
174b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // Make sure either no final rules or a pair of AnnualTimeZoneRules
175b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // are available.
176b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (fFinalRules != NULL && fFinalRules->size() != 2) {
177b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        status = U_INVALID_STATE_ERROR;
178b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return;
179b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
180b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
181b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    UBool *done = NULL;
182b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // Create a TimezoneTransition and add to the list
183b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (fHistoricRules != NULL || fFinalRules != NULL) {
184b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        TimeZoneRule *curRule = fInitialRule;
185b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        UDate lastTransitionTime = MIN_MILLIS;
186b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
187b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // Build the transition array which represents historical time zone
188b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // transitions.
189b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        if (fHistoricRules != NULL && fHistoricRules->size() > 0) {
190b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            int32_t i;
191b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            int32_t historicCount = fHistoricRules->size();
192b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            done = (UBool*)uprv_malloc(sizeof(UBool) * historicCount);
193b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            if (done == NULL) {
194b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                status = U_MEMORY_ALLOCATION_ERROR;
195b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                goto cleanup;
196b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            }
197b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            for (i = 0; i < historicCount; i++) {
198b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                done[i] = FALSE;
199b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            }
200b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            while (TRUE) {
201b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                int32_t curStdOffset = curRule->getRawOffset();
202b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                int32_t curDstSavings = curRule->getDSTSavings();
203b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                UDate nextTransitionTime = MAX_MILLIS;
204b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                TimeZoneRule *nextRule = NULL;
205b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                TimeZoneRule *r = NULL;
206b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                UBool avail;
207b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                UDate tt;
208b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                UnicodeString curName, name;
209b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                curRule->getName(curName);
210b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
211b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                for (i = 0; i < historicCount; i++) {
212b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    if (done[i]) {
213b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                        continue;
214b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    }
215b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    r = (TimeZoneRule*)fHistoricRules->elementAt(i);
216b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    avail = r->getNextStart(lastTransitionTime, curStdOffset, curDstSavings, false, tt);
217b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    if (!avail) {
218b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                        // No more transitions from this rule - skip this rule next time
219b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                        done[i] = TRUE;
220b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    } else {
221b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                        r->getName(name);
222b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                        if (*r == *curRule ||
223b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                            (name == curName && r->getRawOffset() == curRule->getRawOffset()
224b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                            && r->getDSTSavings() == curRule->getDSTSavings())) {
225b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                            continue;
226b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                        }
227b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                        if (tt < nextTransitionTime) {
228b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                            nextTransitionTime = tt;
229b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                            nextRule = r;
230b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                        }
231b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    }
232b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                }
233b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
234b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                if (nextRule ==  NULL) {
235b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    // Check if all historic rules are done
236b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    UBool bDoneAll = TRUE;
237b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    for (int32_t j = 0; j < historicCount; j++) {
238b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                        if (!done[j]) {
239b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                            bDoneAll = FALSE;
240b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                            break;
241b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                        }
242b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    }
243b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    if (bDoneAll) {
244b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                        break;
245b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    }
246b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                }
247b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
248b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                if (fFinalRules != NULL) {
249b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    // Check if one of final rules has earlier transition date
250b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    for (i = 0; i < 2 /* fFinalRules->size() */; i++) {
251b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                        TimeZoneRule *fr = (TimeZoneRule*)fFinalRules->elementAt(i);
252b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                        if (*fr == *curRule) {
253b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                            continue;
254b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                        }
255b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                        r = (TimeZoneRule*)fFinalRules->elementAt(i);
256b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                        avail = r->getNextStart(lastTransitionTime, curStdOffset, curDstSavings, false, tt);
257b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                        if (avail) {
258b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                            if (tt < nextTransitionTime) {
259b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                                nextTransitionTime = tt;
260b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                                nextRule = r;
261b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                            }
262b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                        }
263b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    }
264b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                }
265b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
266b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                if (nextRule == NULL) {
267b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    // Nothing more
268b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    break;
269b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                }
270b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
271b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                if (fHistoricTransitions == NULL) {
272b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    fHistoricTransitions = new UVector(status);
273b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    if (U_FAILURE(status)) {
274b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                        goto cleanup;
275b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    }
276b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                }
277b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                Transition *trst = (Transition*)uprv_malloc(sizeof(Transition));
278b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                if (trst == NULL) {
279b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    status = U_MEMORY_ALLOCATION_ERROR;
280b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    goto cleanup;
281b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                }
282b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                trst->time = nextTransitionTime;
283b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                trst->from = curRule;
284b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                trst->to = nextRule;
285b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                fHistoricTransitions->addElement(trst, status);
286b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                if (U_FAILURE(status)) {
287b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    goto cleanup;
288b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                }
289b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                lastTransitionTime = nextTransitionTime;
290b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                curRule = nextRule;
291b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            }
292b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
293b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        if (fFinalRules != NULL) {
294b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            if (fHistoricTransitions == NULL) {
295b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                fHistoricTransitions = new UVector(status);
296b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                if (U_FAILURE(status)) {
297b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    goto cleanup;
298b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                }
299b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            }
300b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            // Append the first transition for each
301b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            TimeZoneRule *rule0 = (TimeZoneRule*)fFinalRules->elementAt(0);
302b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            TimeZoneRule *rule1 = (TimeZoneRule*)fFinalRules->elementAt(1);
303b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            UDate tt0, tt1;
304b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            UBool avail0 = rule0->getNextStart(lastTransitionTime, curRule->getRawOffset(), curRule->getDSTSavings(), false, tt0);
305b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            UBool avail1 = rule1->getNextStart(lastTransitionTime, curRule->getRawOffset(), curRule->getDSTSavings(), false, tt1);
306b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            if (!avail0 || !avail1) {
307b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                // Should not happen, because both rules are permanent
308b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                status = U_INVALID_STATE_ERROR;
309b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                goto cleanup;
310b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            }
311b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            Transition *final0 = (Transition*)uprv_malloc(sizeof(Transition));
312b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            if (final0 == NULL) {
313b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                status = U_MEMORY_ALLOCATION_ERROR;
314b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                goto cleanup;
315b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            }
316b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            Transition *final1 = (Transition*)uprv_malloc(sizeof(Transition));
317b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            if (final1 == NULL) {
31885bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho                uprv_free(final0);
319b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                status = U_MEMORY_ALLOCATION_ERROR;
320b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                goto cleanup;
321b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            }
322b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            if (tt0 < tt1) {
323b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                final0->time = tt0;
324b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                final0->from = curRule;
325b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                final0->to = rule0;
326b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                rule1->getNextStart(tt0, rule0->getRawOffset(), rule0->getDSTSavings(), false, final1->time);
327b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                final1->from = rule0;
328b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                final1->to = rule1;
329b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            } else {
330b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                final0->time = tt1;
331b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                final0->from = curRule;
332b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                final0->to = rule1;
333b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                rule0->getNextStart(tt1, rule1->getRawOffset(), rule1->getDSTSavings(), false, final1->time);
334b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                final1->from = rule1;
335b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                final1->to = rule0;
336b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            }
337b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            fHistoricTransitions->addElement(final0, status);
338b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            if (U_FAILURE(status)) {
339b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                goto cleanup;
340b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            }
341b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            fHistoricTransitions->addElement(final1, status);
342b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            if (U_FAILURE(status)) {
343b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                goto cleanup;
344b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            }
345b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
346b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
347b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    fUpToDate = TRUE;
348b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (done != NULL) {
349b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        uprv_free(done);
350b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
351b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    return;
352b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
353b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querucleanup:
354b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    deleteTransitions();
355b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (done != NULL) {
356b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        uprv_free(done);
357b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
358b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    fUpToDate = FALSE;
359b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
360b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
361b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruTimeZone*
362b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruRuleBasedTimeZone::clone(void) const {
363b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    return new RuleBasedTimeZone(*this);
364b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
365b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
366b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruint32_t
367b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruRuleBasedTimeZone::getOffset(uint8_t era, int32_t year, int32_t month, int32_t day,
368b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                             uint8_t dayOfWeek, int32_t millis, UErrorCode& status) const {
369b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (U_FAILURE(status)) {
370b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return 0;
371b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
372b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (month < UCAL_JANUARY || month > UCAL_DECEMBER) {
373b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        status = U_ILLEGAL_ARGUMENT_ERROR;
374b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return 0;
375b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    } else {
376b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return getOffset(era, year, month, day, dayOfWeek, millis,
377b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                         Grego::monthLength(year, month), status);
378b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
379b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
380b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
381b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruint32_t
382b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruRuleBasedTimeZone::getOffset(uint8_t era, int32_t year, int32_t month, int32_t day,
383b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                             uint8_t /*dayOfWeek*/, int32_t millis,
384b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                             int32_t /*monthLength*/, UErrorCode& status) const {
385b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // dayOfWeek and monthLength are unused
386b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (U_FAILURE(status)) {
387b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return 0;
388b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
389b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (era == GregorianCalendar::BC) {
390b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // Convert to extended year
391b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        year = 1 - year;
392b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
393b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    int32_t rawOffset, dstOffset;
394b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    UDate time = (UDate)Grego::fieldsToDay(year, month, day) * U_MILLIS_PER_DAY + millis;
395b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    getOffsetInternal(time, TRUE, kDaylight, kStandard, rawOffset, dstOffset, status);
396b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (U_FAILURE(status)) {
397b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return 0;
398b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
399b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    return (rawOffset + dstOffset);
400b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
401b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
402b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruvoid
403b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruRuleBasedTimeZone::getOffset(UDate date, UBool local, int32_t& rawOffset,
404b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                             int32_t& dstOffset, UErrorCode& status) const {
405b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    getOffsetInternal(date, local, kFormer, kLatter, rawOffset, dstOffset, status);
406b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
407b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
408b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruvoid
409b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruRuleBasedTimeZone::getOffsetFromLocal(UDate date, int32_t nonExistingTimeOpt, int32_t duplicatedTimeOpt,
4108393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius                                      int32_t& rawOffset, int32_t& dstOffset, UErrorCode& status) const {
411b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    getOffsetInternal(date, TRUE, nonExistingTimeOpt, duplicatedTimeOpt, rawOffset, dstOffset, status);
412b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
413b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
414b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
415b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/*
416b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * The internal getOffset implementation
417b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */
418b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruvoid
419b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruRuleBasedTimeZone::getOffsetInternal(UDate date, UBool local,
420b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                                     int32_t NonExistingTimeOpt, int32_t DuplicatedTimeOpt,
421b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                                     int32_t& rawOffset, int32_t& dstOffset,
422b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                                     UErrorCode& status) const {
423b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    rawOffset = 0;
424b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    dstOffset = 0;
425b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
426b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (U_FAILURE(status)) {
427b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return;
428b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
429b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (!fUpToDate) {
430b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // Transitions are not yet resolved.  We cannot do it here
431b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // because this method is const.  Thus, do nothing and return
432b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // error status.
433b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        status = U_INVALID_STATE_ERROR;
434b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return;
435b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
436b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    const TimeZoneRule *rule = NULL;
437b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (fHistoricTransitions == NULL) {
438b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        rule = fInitialRule;
439b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    } else {
440b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        UDate tstart = getTransitionTime((Transition*)fHistoricTransitions->elementAt(0),
441b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            local, NonExistingTimeOpt, DuplicatedTimeOpt);
442b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        if (date < tstart) {
443b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            rule = fInitialRule;
444b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        } else {
445b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            int32_t idx = fHistoricTransitions->size() - 1;
446b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            UDate tend = getTransitionTime((Transition*)fHistoricTransitions->elementAt(idx),
447b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                local, NonExistingTimeOpt, DuplicatedTimeOpt);
448b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            if (date > tend) {
449b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                if (fFinalRules != NULL) {
450b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    rule = findRuleInFinal(date, local, NonExistingTimeOpt, DuplicatedTimeOpt);
451103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius                }
452103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius                if (rule == NULL) {
453103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius                    // no final rules or the given time is before the first transition
454103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius                    // specified by the final rules -> use the last rule
455b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    rule = ((Transition*)fHistoricTransitions->elementAt(idx))->to;
456b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                }
457b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            } else {
458b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                // Find a historical transition
459b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                while (idx >= 0) {
460b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    if (date >= getTransitionTime((Transition*)fHistoricTransitions->elementAt(idx),
461b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                        local, NonExistingTimeOpt, DuplicatedTimeOpt)) {
462b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                        break;
463b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    }
464b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    idx--;
465b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                }
466b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                rule = ((Transition*)fHistoricTransitions->elementAt(idx))->to;
467b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            }
468b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
469b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
470b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (rule != NULL) {
471b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        rawOffset = rule->getRawOffset();
472b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        dstOffset = rule->getDSTSavings();
473b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
474b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
475b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
476b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruvoid
477b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruRuleBasedTimeZone::setRawOffset(int32_t /*offsetMillis*/) {
478b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // We don't support this operation at this moment.
479b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // Nothing to do!
480b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
481b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
482b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruint32_t
483b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruRuleBasedTimeZone::getRawOffset(void) const {
484b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // Note: This implementation returns standard GMT offset
485b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // as of current time.
486b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    UErrorCode status = U_ZERO_ERROR;
487b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    int32_t raw, dst;
488b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    getOffset(uprv_getUTCtime() * U_MILLIS_PER_SECOND,
489b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        FALSE, raw, dst, status);
490b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    return raw;
491b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
492b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
493b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruUBool
494b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruRuleBasedTimeZone::useDaylightTime(void) const {
495b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // Note: This implementation returns true when
496b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // daylight saving time is used as of now or
497b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // after the next transition.
498b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    UErrorCode status = U_ZERO_ERROR;
499b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    UDate now = uprv_getUTCtime() * U_MILLIS_PER_SECOND;
500b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    int32_t raw, dst;
501b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    getOffset(now, FALSE, raw, dst, status);
502b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (dst != 0) {
503b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return TRUE;
504b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
505b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // If DST is not used now, check if DST is used after the next transition
506b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    UDate time;
507b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    TimeZoneRule *from, *to;
508b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    UBool avail = findNext(now, FALSE, time, from, to);
509b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (avail && to->getDSTSavings() != 0) {
510b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return TRUE;
511b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
512b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    return FALSE;
513b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
514b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
515b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruUBool
516b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruRuleBasedTimeZone::inDaylightTime(UDate date, UErrorCode& status) const {
517b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (U_FAILURE(status)) {
518b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return FALSE;
519b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
520b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    int32_t raw, dst;
521b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    getOffset(date, FALSE, raw, dst, status);
522b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (dst != 0) {
523b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return TRUE;
524b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
525b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    return FALSE;
526b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
527b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
528b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruUBool
529b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruRuleBasedTimeZone::hasSameRules(const TimeZone& other) const {
530b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (this == &other) {
531b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return TRUE;
532b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
53327f654740f2a26ad62a5c155af9199af9e69b889claireho    if (typeid(*this) != typeid(other)) {
534b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return FALSE;
535b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
536b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    const RuleBasedTimeZone& that = (const RuleBasedTimeZone&)other;
537b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (*fInitialRule != *(that.fInitialRule)) {
538b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return FALSE;
539b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
540b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (compareRules(fHistoricRules, that.fHistoricRules)
541b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        && compareRules(fFinalRules, that.fFinalRules)) {
542b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return TRUE;
543b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
544b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    return FALSE;
545b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
546b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
547b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruUBool
5488393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig CorneliusRuleBasedTimeZone::getNextTransition(UDate base, UBool inclusive, TimeZoneTransition& result) const {
549b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    UErrorCode status = U_ZERO_ERROR;
5508393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    completeConst(status);
551b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (U_FAILURE(status)) {
552b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return FALSE;
553b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
554b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    UDate transitionTime;
555b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    TimeZoneRule *fromRule, *toRule;
556b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    UBool found = findNext(base, inclusive, transitionTime, fromRule, toRule);
557b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (found) {
558b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        result.setTime(transitionTime);
559b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        result.setFrom((const TimeZoneRule&)*fromRule);
560b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        result.setTo((const TimeZoneRule&)*toRule);
561b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return TRUE;
562b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
563b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    return FALSE;
564b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
565b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
566b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruUBool
5678393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig CorneliusRuleBasedTimeZone::getPreviousTransition(UDate base, UBool inclusive, TimeZoneTransition& result) const {
568b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    UErrorCode status = U_ZERO_ERROR;
5698393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    completeConst(status);
570b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (U_FAILURE(status)) {
571b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return FALSE;
572b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
573b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    UDate transitionTime;
574b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    TimeZoneRule *fromRule, *toRule;
575b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    UBool found = findPrev(base, inclusive, transitionTime, fromRule, toRule);
576b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (found) {
577b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        result.setTime(transitionTime);
578b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        result.setFrom((const TimeZoneRule&)*fromRule);
579b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        result.setTo((const TimeZoneRule&)*toRule);
580b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return TRUE;
581b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
582b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    return FALSE;
583b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
584b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
585b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruint32_t
5868393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig CorneliusRuleBasedTimeZone::countTransitionRules(UErrorCode& /*status*/) const {
587b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    int32_t count = 0;
588b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (fHistoricRules != NULL) {
589b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        count += fHistoricRules->size();
590b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
591b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (fFinalRules != NULL) {
592b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        count += fFinalRules->size();
593b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
594b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    return count;
595b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
596b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
597b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruvoid
598b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruRuleBasedTimeZone::getTimeZoneRules(const InitialTimeZoneRule*& initial,
599b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                                    const TimeZoneRule* trsrules[],
600b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                                    int32_t& trscount,
6018393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius                                    UErrorCode& status) const {
602b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (U_FAILURE(status)) {
603b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return;
604b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
605b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // Initial rule
606b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    initial = fInitialRule;
607b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
608b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // Transition rules
609b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    int32_t cnt = 0;
610b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    int32_t idx;
611b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (fHistoricRules != NULL && cnt < trscount) {
612b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        int32_t historicCount = fHistoricRules->size();
613b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        idx = 0;
614b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        while (cnt < trscount && idx < historicCount) {
615b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            trsrules[cnt++] = (const TimeZoneRule*)fHistoricRules->elementAt(idx++);
616b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
617b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
618b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (fFinalRules != NULL && cnt < trscount) {
619b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        int32_t finalCount = fFinalRules->size();
620b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        idx = 0;
621b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        while (cnt < trscount && idx < finalCount) {
622b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            trsrules[cnt++] = (const TimeZoneRule*)fFinalRules->elementAt(idx++);
623b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
624b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
625b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // Set the result length
626b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    trscount = cnt;
627b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
628b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
629b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruvoid
630b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruRuleBasedTimeZone::deleteRules(void) {
631b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    delete fInitialRule;
632b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    fInitialRule = NULL;
633b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (fHistoricRules != NULL) {
634b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        while (!fHistoricRules->isEmpty()) {
635b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            delete (TimeZoneRule*)(fHistoricRules->orphanElementAt(0));
636b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
637b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        delete fHistoricRules;
638b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        fHistoricRules = NULL;
639b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
640b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (fFinalRules != NULL) {
641b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        while (!fFinalRules->isEmpty()) {
642b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            delete (AnnualTimeZoneRule*)(fFinalRules->orphanElementAt(0));
643b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
644b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        delete fFinalRules;
645b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        fFinalRules = NULL;
646b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
647b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
648b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
649b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruvoid
650b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruRuleBasedTimeZone::deleteTransitions(void) {
651b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (fHistoricTransitions != NULL) {
652b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        while (!fHistoricTransitions->isEmpty()) {
653b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            Transition *trs = (Transition*)fHistoricTransitions->orphanElementAt(0);
654b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            uprv_free(trs);
655b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
656b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        delete fHistoricTransitions;
657b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
658b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    fHistoricTransitions = NULL;
659b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
660b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
661b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruUVector*
662b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruRuleBasedTimeZone::copyRules(UVector* source) {
663b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (source == NULL) {
664b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return NULL;
665b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
666b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    UErrorCode ec = U_ZERO_ERROR;
667b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    int32_t size = source->size();
668b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    UVector *rules = new UVector(size, ec);
669b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (U_FAILURE(ec)) {
670b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return NULL;
671b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
672b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    int32_t i;
673b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    for (i = 0; i < size; i++) {
674b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        rules->addElement(((TimeZoneRule*)source->elementAt(i))->clone(), ec);
675b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        if (U_FAILURE(ec)) {
676b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            break;
677b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
678b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
679b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (U_FAILURE(ec)) {
680b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // In case of error, clean up
681b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        for (i = 0; i < rules->size(); i++) {
682b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            TimeZoneRule *rule = (TimeZoneRule*)rules->orphanElementAt(i);
683b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            delete rule;
684b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
685b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        delete rules;
686b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return NULL;
687b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
688b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    return rules;
689b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
690b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
691b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruTimeZoneRule*
692b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruRuleBasedTimeZone::findRuleInFinal(UDate date, UBool local,
693b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                                   int32_t NonExistingTimeOpt, int32_t DuplicatedTimeOpt) const {
694b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (fFinalRules == NULL) {
695b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return NULL;
696b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
697b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
698b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    AnnualTimeZoneRule* fr0 = (AnnualTimeZoneRule*)fFinalRules->elementAt(0);
699b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    AnnualTimeZoneRule* fr1 = (AnnualTimeZoneRule*)fFinalRules->elementAt(1);
700b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (fr0 == NULL || fr1 == NULL) {
701b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return NULL;
702b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
703b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
704b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    UDate start0, start1;
705b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    UDate base;
706b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    int32_t localDelta;
707b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
708b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    base = date;
709b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (local) {
710b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        localDelta = getLocalDelta(fr1->getRawOffset(), fr1->getDSTSavings(),
711b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                                   fr0->getRawOffset(), fr0->getDSTSavings(),
712b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                                   NonExistingTimeOpt, DuplicatedTimeOpt);
713b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        base -= localDelta;
714b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
715b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    UBool avail0 = fr0->getPreviousStart(base, fr1->getRawOffset(), fr1->getDSTSavings(), TRUE, start0);
716b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
717b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    base = date;
718b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (local) {
719b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        localDelta = getLocalDelta(fr0->getRawOffset(), fr0->getDSTSavings(),
720b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                                   fr1->getRawOffset(), fr1->getDSTSavings(),
721b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                                   NonExistingTimeOpt, DuplicatedTimeOpt);
722b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        base -= localDelta;
723b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
724b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    UBool avail1 = fr1->getPreviousStart(base, fr0->getRawOffset(), fr0->getDSTSavings(), TRUE, start1);
725b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
726103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    if (!avail0 || !avail1) {
727103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius        if (avail0) {
728103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius            return fr0;
729103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius        } else if (avail1) {
730103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius            return fr1;
731103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius        }
732103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius        // Both rules take effect after the given time
733103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius        return NULL;
734b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
735103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius
736103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    return (start0 > start1) ? fr0 : fr1;
737b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
738b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
739b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruUBool
740b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruRuleBasedTimeZone::findNext(UDate base, UBool inclusive, UDate& transitionTime,
741b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                            TimeZoneRule*& fromRule, TimeZoneRule*& toRule) const {
742b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (fHistoricTransitions == NULL) {
743b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return FALSE;
744b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
745b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    UBool isFinal = FALSE;
746b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    UBool found = FALSE;
747b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    Transition result;
748b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    Transition *tzt = (Transition*)fHistoricTransitions->elementAt(0);
749b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    UDate tt = tzt->time;
750b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (tt > base || (inclusive && tt == base)) {
751b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        result = *tzt;
752b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        found = TRUE;
753b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    } else {
754b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        int32_t idx = fHistoricTransitions->size() - 1;
755b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        tzt = (Transition*)fHistoricTransitions->elementAt(idx);
756b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        tt = tzt->time;
757b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        if (inclusive && tt == base) {
758b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            result = *tzt;
759b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            found = TRUE;
760b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        } else if (tt <= base) {
761b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            if (fFinalRules != NULL) {
762b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                // Find a transion time with finalRules
763b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                TimeZoneRule *r0 = (TimeZoneRule*)fFinalRules->elementAt(0);
764b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                TimeZoneRule *r1 = (TimeZoneRule*)fFinalRules->elementAt(1);
765b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                UDate start0, start1;
766b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                UBool avail0 = r0->getNextStart(base, r1->getRawOffset(), r1->getDSTSavings(), inclusive, start0);
767b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                UBool avail1 = r1->getNextStart(base, r0->getRawOffset(), r0->getDSTSavings(), inclusive, start1);
768b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                //  avail0/avail1 should be always TRUE
769b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                if (!avail0 && !avail1) {
770b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    return FALSE;
771b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                }
772b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                if (!avail1 || start0 < start1) {
773b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    result.time = start0;
774b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    result.from = r1;
775b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    result.to = r0;
776b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                } else {
777b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    result.time = start1;
778b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    result.from = r0;
779b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    result.to = r1;
780b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                }
781b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                isFinal = TRUE;
782b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                found = TRUE;
783b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            }
784b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        } else {
785b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            // Find a transition within the historic transitions
786b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            idx--;
787b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            Transition *prev = tzt;
788b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            while (idx > 0) {
789b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                tzt = (Transition*)fHistoricTransitions->elementAt(idx);
790b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                tt = tzt->time;
791b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                if (tt < base || (!inclusive && tt == base)) {
792b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    break;
793b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                }
794b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                idx--;
795b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                prev = tzt;
796b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            }
797b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            result.time = prev->time;
798b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            result.from = prev->from;
799b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            result.to = prev->to;
800b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            found = TRUE;
801b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
802b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
803b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (found) {
804b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // For now, this implementation ignore transitions with only zone name changes.
805b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        if (result.from->getRawOffset() == result.to->getRawOffset()
806b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            && result.from->getDSTSavings() == result.to->getDSTSavings()) {
807b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            if (isFinal) {
808b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                return FALSE;
809b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            } else {
810b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                // No offset changes.  Try next one if not final
811b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                return findNext(result.time, FALSE /* always exclusive */,
812b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    transitionTime, fromRule, toRule);
813b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            }
814b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
815b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        transitionTime = result.time;
816b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        fromRule = result.from;
817b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        toRule = result.to;
818b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return TRUE;
819b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
820b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    return FALSE;
821b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
822b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
823b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruUBool
824b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruRuleBasedTimeZone::findPrev(UDate base, UBool inclusive, UDate& transitionTime,
825b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                            TimeZoneRule*& fromRule, TimeZoneRule*& toRule) const {
826b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (fHistoricTransitions == NULL) {
827b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return FALSE;
828b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
829b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    UBool found = FALSE;
830b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    Transition result;
831b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    Transition *tzt = (Transition*)fHistoricTransitions->elementAt(0);
832b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    UDate tt = tzt->time;
833b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (inclusive && tt == base) {
834b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        result = *tzt;
835b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        found = TRUE;
836b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    } else if (tt < base) {
837b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        int32_t idx = fHistoricTransitions->size() - 1;
838b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        tzt = (Transition*)fHistoricTransitions->elementAt(idx);
839b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        tt = tzt->time;
840b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        if (inclusive && tt == base) {
841b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            result = *tzt;
842b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            found = TRUE;
843b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        } else if (tt < base) {
844b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            if (fFinalRules != NULL) {
845b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                // Find a transion time with finalRules
846b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                TimeZoneRule *r0 = (TimeZoneRule*)fFinalRules->elementAt(0);
847b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                TimeZoneRule *r1 = (TimeZoneRule*)fFinalRules->elementAt(1);
848b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                UDate start0, start1;
849b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                UBool avail0 = r0->getPreviousStart(base, r1->getRawOffset(), r1->getDSTSavings(), inclusive, start0);
850b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                UBool avail1 = r1->getPreviousStart(base, r0->getRawOffset(), r0->getDSTSavings(), inclusive, start1);
851b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                //  avail0/avail1 should be always TRUE
852b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                if (!avail0 && !avail1) {
853b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    return FALSE;
854b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                }
855b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                if (!avail1 || start0 > start1) {
856b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    result.time = start0;
857b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    result.from = r1;
858b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    result.to = r0;
859b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                } else {
860b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    result.time = start1;
861b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    result.from = r0;
862b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    result.to = r1;
863b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                }
864b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            } else {
865b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                result = *tzt;
866b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            }
867b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            found = TRUE;
868b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        } else {
869b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            // Find a transition within the historic transitions
870b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            idx--;
871b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            while (idx >= 0) {
872b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                tzt = (Transition*)fHistoricTransitions->elementAt(idx);
873b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                tt = tzt->time;
874b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                if (tt < base || (inclusive && tt == base)) {
875b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    break;
876b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                }
877b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                idx--;
878b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            }
879b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            result = *tzt;
880b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            found = TRUE;
881b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
882b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
883b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (found) {
884b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // For now, this implementation ignore transitions with only zone name changes.
885b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        if (result.from->getRawOffset() == result.to->getRawOffset()
886b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            && result.from->getDSTSavings() == result.to->getDSTSavings()) {
887b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            // No offset changes.  Try next one if not final
888b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            return findPrev(result.time, FALSE /* always exclusive */,
889b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                transitionTime, fromRule, toRule);
890b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
891b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        transitionTime = result.time;
892b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        fromRule = result.from;
893b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        toRule = result.to;
894b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return TRUE;
895b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
896b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    return FALSE;
897b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
898b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
899b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruUDate
900b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruRuleBasedTimeZone::getTransitionTime(Transition* transition, UBool local,
901b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                                     int32_t NonExistingTimeOpt, int32_t DuplicatedTimeOpt) const {
902b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    UDate time = transition->time;
903b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (local) {
904b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        time += getLocalDelta(transition->from->getRawOffset(), transition->from->getDSTSavings(),
905b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                              transition->to->getRawOffset(), transition->to->getDSTSavings(),
906b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                              NonExistingTimeOpt, DuplicatedTimeOpt);
907b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
908b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    return time;
909b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
910b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
911b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruint32_t
912b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruRuleBasedTimeZone::getLocalDelta(int32_t rawBefore, int32_t dstBefore, int32_t rawAfter, int32_t dstAfter,
913b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                             int32_t NonExistingTimeOpt, int32_t DuplicatedTimeOpt) const {
914b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    int32_t delta = 0;
915b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
916b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    int32_t offsetBefore = rawBefore + dstBefore;
917b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    int32_t offsetAfter = rawAfter + dstAfter;
918b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
919b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    UBool dstToStd = (dstBefore != 0) && (dstAfter == 0);
920b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    UBool stdToDst = (dstBefore == 0) && (dstAfter != 0);
921b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
922b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (offsetAfter - offsetBefore >= 0) {
923b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // Positive transition, which makes a non-existing local time range
924b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        if (((NonExistingTimeOpt & kStdDstMask) == kStandard && dstToStd)
925b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                || ((NonExistingTimeOpt & kStdDstMask) == kDaylight && stdToDst)) {
926b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            delta = offsetBefore;
927b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        } else if (((NonExistingTimeOpt & kStdDstMask) == kStandard && stdToDst)
928b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                || ((NonExistingTimeOpt & kStdDstMask) == kDaylight && dstToStd)) {
929b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            delta = offsetAfter;
930b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        } else if ((NonExistingTimeOpt & kFormerLatterMask) == kLatter) {
931b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            delta = offsetBefore;
932b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        } else {
933b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            // Interprets the time with rule before the transition,
934b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            // default for non-existing time range
935b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            delta = offsetAfter;
936b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
937b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    } else {
938b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // Negative transition, which makes a duplicated local time range
939b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        if (((DuplicatedTimeOpt & kStdDstMask) == kStandard && dstToStd)
940b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                || ((DuplicatedTimeOpt & kStdDstMask) == kDaylight && stdToDst)) {
941b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            delta = offsetAfter;
942b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        } else if (((DuplicatedTimeOpt & kStdDstMask) == kStandard && stdToDst)
943b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                || ((DuplicatedTimeOpt & kStdDstMask) == kDaylight && dstToStd)) {
944b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            delta = offsetBefore;
945b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        } else if ((DuplicatedTimeOpt & kFormerLatterMask) == kFormer) {
946b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            delta = offsetBefore;
947b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        } else {
948b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            // Interprets the time with rule after the transition,
949b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            // default for duplicated local time range
950b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            delta = offsetAfter;
951b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
952b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
953b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    return delta;
954b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
955b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
956b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruU_NAMESPACE_END
957b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
958b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#endif /* #if !UCONFIG_NO_FORMATTING */
959b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
960b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru//eof
961b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
962