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
8b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include "unicode/utypes.h"
9b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
10b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#if !UCONFIG_NO_FORMATTING
11b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
12b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include "unicode/basictz.h"
13b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include "gregoimp.h"
14b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include "uvector.h"
15b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include "cmemory.h"
16b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
17b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruU_NAMESPACE_BEGIN
18b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
19b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#define MILLIS_PER_YEAR (365*24*60*60*1000.0)
20b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
21b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruBasicTimeZone::BasicTimeZone()
22b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru: TimeZone() {
23b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
24b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
25b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruBasicTimeZone::BasicTimeZone(const UnicodeString &id)
26b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru: TimeZone(id) {
27b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
28b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
29b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruBasicTimeZone::BasicTimeZone(const BasicTimeZone& source)
30b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru: TimeZone(source) {
31b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
32b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
33b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruBasicTimeZone::~BasicTimeZone() {
34b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
35b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
36b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruUBool
378393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig CorneliusBasicTimeZone::hasEquivalentTransitions(const BasicTimeZone& tz, UDate start, UDate end,
388393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius                                        UBool ignoreDstAmount, UErrorCode& status) const {
39b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (U_FAILURE(status)) {
40b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return FALSE;
41b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
42b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (hasSameRules(tz)) {
43b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return TRUE;
44b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
45b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // Check the offsets at the start time
46b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    int32_t raw1, raw2, dst1, dst2;
47b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    getOffset(start, FALSE, raw1, dst1, status);
48b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (U_FAILURE(status)) {
49b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return FALSE;
50b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
51b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    tz.getOffset(start, FALSE, raw2, dst2, status);
52b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (U_FAILURE(status)) {
53b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return FALSE;
54b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
55b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (ignoreDstAmount) {
56b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        if ((raw1 + dst1 != raw2 + dst2)
57b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            || (dst1 != 0 && dst2 == 0)
58b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            || (dst1 == 0 && dst2 != 0)) {
59b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            return FALSE;
60b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
61b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    } else {
62b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        if (raw1 != raw2 || dst1 != dst2) {
63b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            return FALSE;
64b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
65b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
66b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // Check transitions in the range
67b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    UDate time = start;
68b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    TimeZoneTransition tr1, tr2;
69b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    while (TRUE) {
70b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        UBool avail1 = getNextTransition(time, FALSE, tr1);
71b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        UBool avail2 = tz.getNextTransition(time, FALSE, tr2);
72b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
73b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        if (ignoreDstAmount) {
74b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            // Skip a transition which only differ the amount of DST savings
7527f654740f2a26ad62a5c155af9199af9e69b889claireho            while (TRUE) {
7627f654740f2a26ad62a5c155af9199af9e69b889claireho                if (avail1
7727f654740f2a26ad62a5c155af9199af9e69b889claireho                        && tr1.getTime() <= end
7827f654740f2a26ad62a5c155af9199af9e69b889claireho                        && (tr1.getFrom()->getRawOffset() + tr1.getFrom()->getDSTSavings()
7927f654740f2a26ad62a5c155af9199af9e69b889claireho                                == tr1.getTo()->getRawOffset() + tr1.getTo()->getDSTSavings())
8027f654740f2a26ad62a5c155af9199af9e69b889claireho                        && (tr1.getFrom()->getDSTSavings() != 0 && tr1.getTo()->getDSTSavings() != 0)) {
8127f654740f2a26ad62a5c155af9199af9e69b889claireho                    getNextTransition(tr1.getTime(), FALSE, tr1);
8227f654740f2a26ad62a5c155af9199af9e69b889claireho                } else {
8327f654740f2a26ad62a5c155af9199af9e69b889claireho                    break;
8427f654740f2a26ad62a5c155af9199af9e69b889claireho                }
85b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            }
8627f654740f2a26ad62a5c155af9199af9e69b889claireho            while (TRUE) {
8727f654740f2a26ad62a5c155af9199af9e69b889claireho                if (avail2
8827f654740f2a26ad62a5c155af9199af9e69b889claireho                        && tr2.getTime() <= end
8927f654740f2a26ad62a5c155af9199af9e69b889claireho                        && (tr2.getFrom()->getRawOffset() + tr2.getFrom()->getDSTSavings()
9027f654740f2a26ad62a5c155af9199af9e69b889claireho                                == tr2.getTo()->getRawOffset() + tr2.getTo()->getDSTSavings())
9127f654740f2a26ad62a5c155af9199af9e69b889claireho                        && (tr2.getFrom()->getDSTSavings() != 0 && tr2.getTo()->getDSTSavings() != 0)) {
9227f654740f2a26ad62a5c155af9199af9e69b889claireho                    tz.getNextTransition(tr2.getTime(), FALSE, tr2);
9327f654740f2a26ad62a5c155af9199af9e69b889claireho                } else {
9427f654740f2a26ad62a5c155af9199af9e69b889claireho                    break;
9527f654740f2a26ad62a5c155af9199af9e69b889claireho                }
96b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            }
97b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
98b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
99b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        UBool inRange1 = (avail1 && tr1.getTime() <= end);
100b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        UBool inRange2 = (avail2 && tr2.getTime() <= end);
101b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        if (!inRange1 && !inRange2) {
102b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            // No more transition in the range
103b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            break;
104b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
105b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        if (!inRange1 || !inRange2) {
106b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            return FALSE;
107b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
108b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        if (tr1.getTime() != tr2.getTime()) {
109b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            return FALSE;
110b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
111b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        if (ignoreDstAmount) {
112b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            if (tr1.getTo()->getRawOffset() + tr1.getTo()->getDSTSavings()
113b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                        != tr2.getTo()->getRawOffset() + tr2.getTo()->getDSTSavings()
11427f654740f2a26ad62a5c155af9199af9e69b889claireho                    || (tr1.getTo()->getDSTSavings() != 0 &&  tr2.getTo()->getDSTSavings() == 0)
11527f654740f2a26ad62a5c155af9199af9e69b889claireho                    || (tr1.getTo()->getDSTSavings() == 0 &&  tr2.getTo()->getDSTSavings() != 0)) {
116b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                return FALSE;
117b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            }
118b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        } else {
119b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            if (tr1.getTo()->getRawOffset() != tr2.getTo()->getRawOffset() ||
120b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                tr1.getTo()->getDSTSavings() != tr2.getTo()->getDSTSavings()) {
121b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                return FALSE;
122b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            }
123b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
124b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        time = tr1.getTime();
125b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
126b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    return TRUE;
127b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
128b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
129b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruvoid
130b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruBasicTimeZone::getSimpleRulesNear(UDate date, InitialTimeZoneRule*& initial,
1318393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius        AnnualTimeZoneRule*& std, AnnualTimeZoneRule*& dst, UErrorCode& status) const {
132b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    initial = NULL;
133b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    std = NULL;
134b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    dst = NULL;
135b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (U_FAILURE(status)) {
136b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return;
137b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
138b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    int32_t initialRaw, initialDst;
139b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    UnicodeString initialName;
140b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
141b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    AnnualTimeZoneRule *ar1 = NULL;
142b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    AnnualTimeZoneRule *ar2 = NULL;
143b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    UnicodeString name;
144b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
145b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    UBool avail;
146b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    TimeZoneTransition tr;
147b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // Get the next transition
148b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    avail = getNextTransition(date, FALSE, tr);
149b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (avail) {
150b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        tr.getFrom()->getName(initialName);
151b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        initialRaw = tr.getFrom()->getRawOffset();
152b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        initialDst = tr.getFrom()->getDSTSavings();
153b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
154b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // Check if the next transition is either DST->STD or STD->DST and
155b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // within roughly 1 year from the specified date
156b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        UDate nextTransitionTime = tr.getTime();
157b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        if (((tr.getFrom()->getDSTSavings() == 0 && tr.getTo()->getDSTSavings() != 0)
158b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru              || (tr.getFrom()->getDSTSavings() != 0 && tr.getTo()->getDSTSavings() == 0))
159b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            && (date + MILLIS_PER_YEAR > nextTransitionTime)) {
160b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
161b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            int32_t year, month, dom, dow, doy, mid;
162b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            UDate d;
163b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
164b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            // Get local wall time for the next transition time
165b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            Grego::timeToFields(nextTransitionTime + initialRaw + initialDst,
166b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                year, month, dom, dow, doy, mid);
167b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            int32_t weekInMonth = Grego::dayOfWeekInMonth(year, month, dom);
168b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            // Create DOW rule
169b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            DateTimeRule *dtr = new DateTimeRule(month, weekInMonth, dow, mid, DateTimeRule::WALL_TIME);
170b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            tr.getTo()->getName(name);
17150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
17250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            // Note:  SimpleTimeZone does not support raw offset change.
17350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            // So we always use raw offset of the given time for the rule,
17450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            // even raw offset is changed.  This will result that the result
17550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            // zone to return wrong offset after the transition.
17650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            // When we encounter such case, we do not inspect next next
17750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            // transition for another rule.
17850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            ar1 = new AnnualTimeZoneRule(name, initialRaw, tr.getTo()->getDSTSavings(),
179b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                dtr, year, AnnualTimeZoneRule::MAX_YEAR);
180b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
18150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            if (tr.getTo()->getRawOffset() == initialRaw) {
18250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                // Get the next next transition
18350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                avail = getNextTransition(nextTransitionTime, FALSE, tr);
18450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                if (avail) {
18550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                    // Check if the next next transition is either DST->STD or STD->DST
18650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                    // and within roughly 1 year from the next transition
18750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                    if (((tr.getFrom()->getDSTSavings() == 0 && tr.getTo()->getDSTSavings() != 0)
18850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                          || (tr.getFrom()->getDSTSavings() != 0 && tr.getTo()->getDSTSavings() == 0))
18950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                         && nextTransitionTime + MILLIS_PER_YEAR > tr.getTime()) {
19050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
19150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                        // Get local wall time for the next transition time
19250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                        Grego::timeToFields(tr.getTime() + tr.getFrom()->getRawOffset() + tr.getFrom()->getDSTSavings(),
19350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                            year, month, dom, dow, doy, mid);
19450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                        weekInMonth = Grego::dayOfWeekInMonth(year, month, dom);
19550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                        // Generate another DOW rule
19650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                        dtr = new DateTimeRule(month, weekInMonth, dow, mid, DateTimeRule::WALL_TIME);
19750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                        tr.getTo()->getName(name);
19850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                        ar2 = new AnnualTimeZoneRule(name, tr.getTo()->getRawOffset(), tr.getTo()->getDSTSavings(),
19950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                            dtr, year - 1, AnnualTimeZoneRule::MAX_YEAR);
20050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
20150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                        // Make sure this rule can be applied to the specified date
20250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                        avail = ar2->getPreviousStart(date, tr.getFrom()->getRawOffset(), tr.getFrom()->getDSTSavings(), TRUE, d);
20350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                        if (!avail || d > date
20450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                                || initialRaw != tr.getTo()->getRawOffset()
20550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                                || initialDst != tr.getTo()->getDSTSavings()) {
20650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                            // We cannot use this rule as the second transition rule
20750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                            delete ar2;
20850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                            ar2 = NULL;
20950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                        }
210b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    }
211b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                }
212b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            }
213b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            if (ar2 == NULL) {
214b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                // Try previous transition
215b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                avail = getPreviousTransition(date, TRUE, tr);
216b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                if (avail) {
217b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    // Check if the previous transition is either DST->STD or STD->DST.
218b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    // The actual transition time does not matter here.
219b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    if ((tr.getFrom()->getDSTSavings() == 0 && tr.getTo()->getDSTSavings() != 0)
220b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                        || (tr.getFrom()->getDSTSavings() != 0 && tr.getTo()->getDSTSavings() == 0)) {
221b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
222b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                        // Generate another DOW rule
223b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                        Grego::timeToFields(tr.getTime() + tr.getFrom()->getRawOffset() + tr.getFrom()->getDSTSavings(),
224b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                            year, month, dom, dow, doy, mid);
225b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                        weekInMonth = Grego::dayOfWeekInMonth(year, month, dom);
226b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                        dtr = new DateTimeRule(month, weekInMonth, dow, mid, DateTimeRule::WALL_TIME);
227b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                        tr.getTo()->getName(name);
22850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
22950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                        // second rule raw/dst offsets should match raw/dst offsets
23050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                        // at the given time
23150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                        ar2 = new AnnualTimeZoneRule(name, initialRaw, initialDst,
232b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                            dtr, ar1->getStartYear() - 1, AnnualTimeZoneRule::MAX_YEAR);
233b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
234b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                        // Check if this rule start after the first rule after the specified date
235b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                        avail = ar2->getNextStart(date, tr.getFrom()->getRawOffset(), tr.getFrom()->getDSTSavings(), FALSE, d);
236b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                        if (!avail || d <= nextTransitionTime) {
237b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                            // We cannot use this rule as the second transition rule
238b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                            delete ar2;
239b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                            ar2 = NULL;
240b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                        }
241b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    }
242b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                }
243b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            }
244b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            if (ar2 == NULL) {
245b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                // Cannot find a good pair of AnnualTimeZoneRule
246b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                delete ar1;
247b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                ar1 = NULL;
248b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            } else {
249b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                // The initial rule should represent the rule before the previous transition
250b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                ar1->getName(initialName);
251b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                initialRaw = ar1->getRawOffset();
252b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                initialDst = ar1->getDSTSavings();
253b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            }
254b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
255c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    }
256c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    else {
257b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // Try the previous one
258b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        avail = getPreviousTransition(date, TRUE, tr);
259b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        if (avail) {
260b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            tr.getTo()->getName(initialName);
261b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            initialRaw = tr.getTo()->getRawOffset();
262b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            initialDst = tr.getTo()->getDSTSavings();
263b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        } else {
264b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            // No transitions in the past.  Just use the current offsets
265b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            getOffset(date, FALSE, initialRaw, initialDst, status);
266b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            if (U_FAILURE(status)) {
267b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                return;
268b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            }
269b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
270b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
271b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // Set the initial rule
272b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    initial = new InitialTimeZoneRule(initialName, initialRaw, initialDst);
273b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
274b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // Set the standard and daylight saving rules
275b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (ar1 != NULL && ar2 != NULL) {
276b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        if (ar1->getDSTSavings() != 0) {
277b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            dst = ar1;
278b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            std = ar2;
279b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        } else {
280b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            std = ar1;
281b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            dst = ar2;
282b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
283b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
284b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
285b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
286b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruvoid
287b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruBasicTimeZone::getTimeZoneRulesAfter(UDate start, InitialTimeZoneRule*& initial,
2888393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius                                     UVector*& transitionRules, UErrorCode& status) const {
289b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (U_FAILURE(status)) {
290b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return;
291b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
292b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
293b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    const InitialTimeZoneRule *orgini;
294b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    const TimeZoneRule **orgtrs = NULL;
295b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    TimeZoneTransition tzt;
296b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    UBool avail;
297b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    UVector *orgRules = NULL;
298b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    int32_t ruleCount;
299b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    TimeZoneRule *r = NULL;
300b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    UBool *done = NULL;
301b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    InitialTimeZoneRule *res_initial = NULL;
302b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    UVector *filteredRules = NULL;
303b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    UnicodeString name;
304b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    int32_t i;
305b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    UDate time, t;
306b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    UDate *newTimes = NULL;
307b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    UDate firstStart;
308b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    UBool bFinalStd = FALSE, bFinalDst = FALSE;
309b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
310b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // Original transition rules
311b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    ruleCount = countTransitionRules(status);
312b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (U_FAILURE(status)) {
313b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return;
314b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
315b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    orgRules = new UVector(ruleCount, status);
316b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (U_FAILURE(status)) {
317b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return;
318b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
319b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    orgtrs = (const TimeZoneRule**)uprv_malloc(sizeof(TimeZoneRule*)*ruleCount);
320b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (orgtrs == NULL) {
321b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        status = U_MEMORY_ALLOCATION_ERROR;
322b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        goto error;
323b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
324b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    getTimeZoneRules(orgini, orgtrs, ruleCount, status);
325b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (U_FAILURE(status)) {
326b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        goto error;
327b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
328b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    for (i = 0; i < ruleCount; i++) {
329b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        orgRules->addElement(orgtrs[i]->clone(), status);
330b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        if (U_FAILURE(status)) {
331b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            goto error;
332b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
333b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
334b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    uprv_free(orgtrs);
335b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    orgtrs = NULL;
336b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
337b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    avail = getPreviousTransition(start, TRUE, tzt);
338b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (!avail) {
339b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // No need to filter out rules only applicable to time before the start
340b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        initial = orgini->clone();
341b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        transitionRules = orgRules;
342b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return;
343b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
344b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
345b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    done = (UBool*)uprv_malloc(sizeof(UBool)*ruleCount);
346b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (done == NULL) {
347b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        status = U_MEMORY_ALLOCATION_ERROR;
348b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        goto error;
349b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
350b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    filteredRules = new UVector(status);
351b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (U_FAILURE(status)) {
352b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        goto error;
353b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
354b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
355b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // Create initial rule
356b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    tzt.getTo()->getName(name);
357b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    res_initial = new InitialTimeZoneRule(name, tzt.getTo()->getRawOffset(),
358b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        tzt.getTo()->getDSTSavings());
359b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
360b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // Mark rules which does not need to be processed
361b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    for (i = 0; i < ruleCount; i++) {
362b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        r = (TimeZoneRule*)orgRules->elementAt(i);
363b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        avail = r->getNextStart(start, res_initial->getRawOffset(), res_initial->getDSTSavings(), FALSE, time);
364b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        done[i] = !avail;
365b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
366b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
367b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    time = start;
368b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    while (!bFinalStd || !bFinalDst) {
369b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        avail = getNextTransition(time, FALSE, tzt);
370b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        if (!avail) {
371b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            break;
372b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
37327f654740f2a26ad62a5c155af9199af9e69b889claireho        UDate updatedTime = tzt.getTime();
37427f654740f2a26ad62a5c155af9199af9e69b889claireho        if (updatedTime == time) {
37527f654740f2a26ad62a5c155af9199af9e69b889claireho            // Can get here if rules for start & end of daylight time have exactly
37627f654740f2a26ad62a5c155af9199af9e69b889claireho            // the same time.
37727f654740f2a26ad62a5c155af9199af9e69b889claireho            // TODO:  fix getNextTransition() to prevent it?
37827f654740f2a26ad62a5c155af9199af9e69b889claireho            status = U_INVALID_STATE_ERROR;
37927f654740f2a26ad62a5c155af9199af9e69b889claireho            goto error;
38027f654740f2a26ad62a5c155af9199af9e69b889claireho        }
38127f654740f2a26ad62a5c155af9199af9e69b889claireho        time = updatedTime;
382b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
383b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        const TimeZoneRule *toRule = tzt.getTo();
384b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        for (i = 0; i < ruleCount; i++) {
385b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            r = (TimeZoneRule*)orgRules->elementAt(i);
386b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            if (*r == *toRule) {
387b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                break;
388b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            }
389b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
390b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        if (i >= ruleCount) {
391b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            // This case should never happen
392b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            status = U_INVALID_STATE_ERROR;
393b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            goto error;
394b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
395b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        if (done[i]) {
396b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            continue;
397b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
39827f654740f2a26ad62a5c155af9199af9e69b889claireho        const TimeArrayTimeZoneRule *tar = dynamic_cast<const TimeArrayTimeZoneRule *>(toRule);
39927f654740f2a26ad62a5c155af9199af9e69b889claireho        const AnnualTimeZoneRule *ar;
40027f654740f2a26ad62a5c155af9199af9e69b889claireho        if (tar != NULL) {
401b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            // Get the previous raw offset and DST savings before the very first start time
402b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            TimeZoneTransition tzt0;
403b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            t = start;
404b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            while (TRUE) {
405b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                avail = getNextTransition(t, FALSE, tzt0);
406b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                if (!avail) {
407b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    break;
408b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                }
409b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                if (*(tzt0.getTo()) == *tar) {
410b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    break;
411b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                }
412b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                t = tzt0.getTime();
413b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            }
414b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            if (avail) {
415b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                // Check if the entire start times to be added
416b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                tar->getFirstStart(tzt.getFrom()->getRawOffset(), tzt.getFrom()->getDSTSavings(), firstStart);
417b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                if (firstStart > start) {
418b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    // Just add the rule as is
419b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    filteredRules->addElement(tar->clone(), status);
420b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    if (U_FAILURE(status)) {
421b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                        goto error;
422b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    }
423b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                } else {
424b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    // Colllect transitions after the start time
425b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    int32_t startTimes;
426b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    DateTimeRule::TimeRuleType timeType;
427b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    int32_t idx;
428b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
429b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    startTimes = tar->countStartTimes();
430b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    timeType = tar->getTimeType();
431b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    for (idx = 0; idx < startTimes; idx++) {
432b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                        tar->getStartTimeAt(idx, t);
433b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                        if (timeType == DateTimeRule::STANDARD_TIME) {
434b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                            t -= tzt.getFrom()->getRawOffset();
435b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                        }
436b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                        if (timeType == DateTimeRule::WALL_TIME) {
437b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                            t -= tzt.getFrom()->getDSTSavings();
438b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                        }
439b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                        if (t > start) {
440b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                            break;
441b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                        }
442b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    }
443b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    int32_t asize = startTimes - idx;
444b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    if (asize > 0) {
445b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                        newTimes = (UDate*)uprv_malloc(sizeof(UDate) * asize);
446b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                        if (newTimes == NULL) {
447b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                            status = U_MEMORY_ALLOCATION_ERROR;
448b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                            goto error;
449b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                        }
450b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                        for (int32_t newidx = 0; newidx < asize; newidx++) {
451b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                            tar->getStartTimeAt(idx + newidx, newTimes[newidx]);
452b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                            if (U_FAILURE(status)) {
453b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                                uprv_free(newTimes);
454b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                                newTimes = NULL;
455b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                                goto error;
456b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                            }
457b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                        }
458b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                        tar->getName(name);
459b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                        TimeArrayTimeZoneRule *newTar = new TimeArrayTimeZoneRule(name,
460b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                            tar->getRawOffset(), tar->getDSTSavings(), newTimes, asize, timeType);
461b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                        uprv_free(newTimes);
462b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                        filteredRules->addElement(newTar, status);
463b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                        if (U_FAILURE(status)) {
464b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                            goto error;
465b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                        }
466b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    }
467b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                }
468b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            }
46927f654740f2a26ad62a5c155af9199af9e69b889claireho        } else if ((ar = dynamic_cast<const AnnualTimeZoneRule *>(toRule)) != NULL) {
470b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            ar->getFirstStart(tzt.getFrom()->getRawOffset(), tzt.getFrom()->getDSTSavings(), firstStart);
471b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            if (firstStart == tzt.getTime()) {
472b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                // Just add the rule as is
473b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                filteredRules->addElement(ar->clone(), status);
474b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                if (U_FAILURE(status)) {
475b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    goto error;
476b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                }
477b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            } else {
478b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                // Calculate the transition year
479b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                int32_t year, month, dom, dow, doy, mid;
480b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                Grego::timeToFields(tzt.getTime(), year, month, dom, dow, doy, mid);
481b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                // Re-create the rule
482b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                ar->getName(name);
483b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                AnnualTimeZoneRule *newAr = new AnnualTimeZoneRule(name, ar->getRawOffset(), ar->getDSTSavings(),
484b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    *(ar->getRule()), year, ar->getEndYear());
485b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                filteredRules->addElement(newAr, status);
486b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                if (U_FAILURE(status)) {
487b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    goto error;
488b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                }
489b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            }
490b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            // check if this is a final rule
491b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            if (ar->getEndYear() == AnnualTimeZoneRule::MAX_YEAR) {
492b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                // After bot final standard and dst rules are processed,
493b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                // exit this while loop.
494b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                if (ar->getDSTSavings() == 0) {
495b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    bFinalStd = TRUE;
496b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                } else {
497b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    bFinalDst = TRUE;
498b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                }
499b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            }
500b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
501b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        done[i] = TRUE;
502b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
503b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
504b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // Set the results
505b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (orgRules != NULL) {
506b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        while (!orgRules->isEmpty()) {
507b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            r = (TimeZoneRule*)orgRules->orphanElementAt(0);
508b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            delete r;
509b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
510b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        delete orgRules;
511b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
512b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (done != NULL) {
513b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        uprv_free(done);
514b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
515b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
516b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    initial = res_initial;
517b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    transitionRules = filteredRules;
518b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    return;
519b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
520b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruerror:
521b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (orgtrs != NULL) {
522b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        uprv_free(orgtrs);
523b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
524b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (orgRules != NULL) {
525b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        while (!orgRules->isEmpty()) {
526b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            r = (TimeZoneRule*)orgRules->orphanElementAt(0);
527b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            delete r;
528b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
529b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        delete orgRules;
530b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
531b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (done != NULL) {
53227f654740f2a26ad62a5c155af9199af9e69b889claireho        if (filteredRules != NULL) {
53327f654740f2a26ad62a5c155af9199af9e69b889claireho            while (!filteredRules->isEmpty()) {
53427f654740f2a26ad62a5c155af9199af9e69b889claireho                r = (TimeZoneRule*)filteredRules->orphanElementAt(0);
53527f654740f2a26ad62a5c155af9199af9e69b889claireho                delete r;
53627f654740f2a26ad62a5c155af9199af9e69b889claireho            }
53727f654740f2a26ad62a5c155af9199af9e69b889claireho            delete filteredRules;
53827f654740f2a26ad62a5c155af9199af9e69b889claireho        }
53927f654740f2a26ad62a5c155af9199af9e69b889claireho        delete res_initial;
540b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        uprv_free(done);
541b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
542b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
543b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    initial = NULL;
544b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    transitionRules = NULL;
545b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
546b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
547b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruvoid
548b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste QueruBasicTimeZone::getOffsetFromLocal(UDate /*date*/, int32_t /*nonExistingTimeOpt*/, int32_t /*duplicatedTimeOpt*/,
5498393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius                            int32_t& /*rawOffset*/, int32_t& /*dstOffset*/, UErrorCode& status) const {
550b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (U_FAILURE(status)) {
551b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return;
552b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
553b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    status = U_UNSUPPORTED_ERROR;
554b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
555b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
556b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruU_NAMESPACE_END
557b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
558b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#endif /* #if !UCONFIG_NO_FORMATTING */
559b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
560b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru//eof
561