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