xref: /aosp_15_r20/external/icu/icu4c/source/i18n/basictz.cpp (revision 0e209d3975ff4a8c132096b14b0e9364a753506e)
1*0e209d39SAndroid Build Coastguard Worker // © 2016 and later: Unicode, Inc. and others.
2*0e209d39SAndroid Build Coastguard Worker // License & terms of use: http://www.unicode.org/copyright.html
3*0e209d39SAndroid Build Coastguard Worker /*
4*0e209d39SAndroid Build Coastguard Worker *******************************************************************************
5*0e209d39SAndroid Build Coastguard Worker * Copyright (C) 2007-2013, International Business Machines Corporation and
6*0e209d39SAndroid Build Coastguard Worker * others. All Rights Reserved.
7*0e209d39SAndroid Build Coastguard Worker *******************************************************************************
8*0e209d39SAndroid Build Coastguard Worker */
9*0e209d39SAndroid Build Coastguard Worker 
10*0e209d39SAndroid Build Coastguard Worker #include "unicode/utypes.h"
11*0e209d39SAndroid Build Coastguard Worker 
12*0e209d39SAndroid Build Coastguard Worker #if !UCONFIG_NO_FORMATTING
13*0e209d39SAndroid Build Coastguard Worker 
14*0e209d39SAndroid Build Coastguard Worker #include "unicode/basictz.h"
15*0e209d39SAndroid Build Coastguard Worker #include "gregoimp.h"
16*0e209d39SAndroid Build Coastguard Worker #include "uvector.h"
17*0e209d39SAndroid Build Coastguard Worker #include "cmemory.h"
18*0e209d39SAndroid Build Coastguard Worker 
19*0e209d39SAndroid Build Coastguard Worker U_NAMESPACE_BEGIN
20*0e209d39SAndroid Build Coastguard Worker 
21*0e209d39SAndroid Build Coastguard Worker #define MILLIS_PER_YEAR (365*24*60*60*1000.0)
22*0e209d39SAndroid Build Coastguard Worker 
BasicTimeZone()23*0e209d39SAndroid Build Coastguard Worker BasicTimeZone::BasicTimeZone()
24*0e209d39SAndroid Build Coastguard Worker : TimeZone() {
25*0e209d39SAndroid Build Coastguard Worker }
26*0e209d39SAndroid Build Coastguard Worker 
BasicTimeZone(const UnicodeString & id)27*0e209d39SAndroid Build Coastguard Worker BasicTimeZone::BasicTimeZone(const UnicodeString &id)
28*0e209d39SAndroid Build Coastguard Worker : TimeZone(id) {
29*0e209d39SAndroid Build Coastguard Worker }
30*0e209d39SAndroid Build Coastguard Worker 
BasicTimeZone(const BasicTimeZone & source)31*0e209d39SAndroid Build Coastguard Worker BasicTimeZone::BasicTimeZone(const BasicTimeZone& source)
32*0e209d39SAndroid Build Coastguard Worker : TimeZone(source) {
33*0e209d39SAndroid Build Coastguard Worker }
34*0e209d39SAndroid Build Coastguard Worker 
~BasicTimeZone()35*0e209d39SAndroid Build Coastguard Worker BasicTimeZone::~BasicTimeZone() {
36*0e209d39SAndroid Build Coastguard Worker }
37*0e209d39SAndroid Build Coastguard Worker 
38*0e209d39SAndroid Build Coastguard Worker UBool
hasEquivalentTransitions(const BasicTimeZone & tz,UDate start,UDate end,UBool ignoreDstAmount,UErrorCode & status) const39*0e209d39SAndroid Build Coastguard Worker BasicTimeZone::hasEquivalentTransitions(const BasicTimeZone& tz, UDate start, UDate end,
40*0e209d39SAndroid Build Coastguard Worker                                         UBool ignoreDstAmount, UErrorCode& status) const {
41*0e209d39SAndroid Build Coastguard Worker     if (U_FAILURE(status)) {
42*0e209d39SAndroid Build Coastguard Worker         return false;
43*0e209d39SAndroid Build Coastguard Worker     }
44*0e209d39SAndroid Build Coastguard Worker     if (hasSameRules(tz)) {
45*0e209d39SAndroid Build Coastguard Worker         return true;
46*0e209d39SAndroid Build Coastguard Worker     }
47*0e209d39SAndroid Build Coastguard Worker     // Check the offsets at the start time
48*0e209d39SAndroid Build Coastguard Worker     int32_t raw1, raw2, dst1, dst2;
49*0e209d39SAndroid Build Coastguard Worker     getOffset(start, false, raw1, dst1, status);
50*0e209d39SAndroid Build Coastguard Worker     if (U_FAILURE(status)) {
51*0e209d39SAndroid Build Coastguard Worker         return false;
52*0e209d39SAndroid Build Coastguard Worker     }
53*0e209d39SAndroid Build Coastguard Worker     tz.getOffset(start, false, raw2, dst2, status);
54*0e209d39SAndroid Build Coastguard Worker     if (U_FAILURE(status)) {
55*0e209d39SAndroid Build Coastguard Worker         return false;
56*0e209d39SAndroid Build Coastguard Worker     }
57*0e209d39SAndroid Build Coastguard Worker     if (ignoreDstAmount) {
58*0e209d39SAndroid Build Coastguard Worker         if ((raw1 + dst1 != raw2 + dst2)
59*0e209d39SAndroid Build Coastguard Worker             || (dst1 != 0 && dst2 == 0)
60*0e209d39SAndroid Build Coastguard Worker             || (dst1 == 0 && dst2 != 0)) {
61*0e209d39SAndroid Build Coastguard Worker             return false;
62*0e209d39SAndroid Build Coastguard Worker         }
63*0e209d39SAndroid Build Coastguard Worker     } else {
64*0e209d39SAndroid Build Coastguard Worker         if (raw1 != raw2 || dst1 != dst2) {
65*0e209d39SAndroid Build Coastguard Worker             return false;
66*0e209d39SAndroid Build Coastguard Worker         }
67*0e209d39SAndroid Build Coastguard Worker     }
68*0e209d39SAndroid Build Coastguard Worker     // Check transitions in the range
69*0e209d39SAndroid Build Coastguard Worker     UDate time = start;
70*0e209d39SAndroid Build Coastguard Worker     TimeZoneTransition tr1, tr2;
71*0e209d39SAndroid Build Coastguard Worker     while (true) {
72*0e209d39SAndroid Build Coastguard Worker         UBool avail1 = getNextTransition(time, false, tr1);
73*0e209d39SAndroid Build Coastguard Worker         UBool avail2 = tz.getNextTransition(time, false, tr2);
74*0e209d39SAndroid Build Coastguard Worker 
75*0e209d39SAndroid Build Coastguard Worker         if (ignoreDstAmount) {
76*0e209d39SAndroid Build Coastguard Worker             // Skip a transition which only differ the amount of DST savings
77*0e209d39SAndroid Build Coastguard Worker             while (true) {
78*0e209d39SAndroid Build Coastguard Worker                 if (avail1
79*0e209d39SAndroid Build Coastguard Worker                         && tr1.getTime() <= end
80*0e209d39SAndroid Build Coastguard Worker                         && (tr1.getFrom()->getRawOffset() + tr1.getFrom()->getDSTSavings()
81*0e209d39SAndroid Build Coastguard Worker                                 == tr1.getTo()->getRawOffset() + tr1.getTo()->getDSTSavings())
82*0e209d39SAndroid Build Coastguard Worker                         && (tr1.getFrom()->getDSTSavings() != 0 && tr1.getTo()->getDSTSavings() != 0)) {
83*0e209d39SAndroid Build Coastguard Worker                     getNextTransition(tr1.getTime(), false, tr1);
84*0e209d39SAndroid Build Coastguard Worker                 } else {
85*0e209d39SAndroid Build Coastguard Worker                     break;
86*0e209d39SAndroid Build Coastguard Worker                 }
87*0e209d39SAndroid Build Coastguard Worker             }
88*0e209d39SAndroid Build Coastguard Worker             while (true) {
89*0e209d39SAndroid Build Coastguard Worker                 if (avail2
90*0e209d39SAndroid Build Coastguard Worker                         && tr2.getTime() <= end
91*0e209d39SAndroid Build Coastguard Worker                         && (tr2.getFrom()->getRawOffset() + tr2.getFrom()->getDSTSavings()
92*0e209d39SAndroid Build Coastguard Worker                                 == tr2.getTo()->getRawOffset() + tr2.getTo()->getDSTSavings())
93*0e209d39SAndroid Build Coastguard Worker                         && (tr2.getFrom()->getDSTSavings() != 0 && tr2.getTo()->getDSTSavings() != 0)) {
94*0e209d39SAndroid Build Coastguard Worker                     tz.getNextTransition(tr2.getTime(), false, tr2);
95*0e209d39SAndroid Build Coastguard Worker                 } else {
96*0e209d39SAndroid Build Coastguard Worker                     break;
97*0e209d39SAndroid Build Coastguard Worker                 }
98*0e209d39SAndroid Build Coastguard Worker             }
99*0e209d39SAndroid Build Coastguard Worker         }
100*0e209d39SAndroid Build Coastguard Worker 
101*0e209d39SAndroid Build Coastguard Worker         UBool inRange1 = (avail1 && tr1.getTime() <= end);
102*0e209d39SAndroid Build Coastguard Worker         UBool inRange2 = (avail2 && tr2.getTime() <= end);
103*0e209d39SAndroid Build Coastguard Worker         if (!inRange1 && !inRange2) {
104*0e209d39SAndroid Build Coastguard Worker             // No more transition in the range
105*0e209d39SAndroid Build Coastguard Worker             break;
106*0e209d39SAndroid Build Coastguard Worker         }
107*0e209d39SAndroid Build Coastguard Worker         if (!inRange1 || !inRange2) {
108*0e209d39SAndroid Build Coastguard Worker             return false;
109*0e209d39SAndroid Build Coastguard Worker         }
110*0e209d39SAndroid Build Coastguard Worker         if (tr1.getTime() != tr2.getTime()) {
111*0e209d39SAndroid Build Coastguard Worker             return false;
112*0e209d39SAndroid Build Coastguard Worker         }
113*0e209d39SAndroid Build Coastguard Worker         if (ignoreDstAmount) {
114*0e209d39SAndroid Build Coastguard Worker             if (tr1.getTo()->getRawOffset() + tr1.getTo()->getDSTSavings()
115*0e209d39SAndroid Build Coastguard Worker                         != tr2.getTo()->getRawOffset() + tr2.getTo()->getDSTSavings()
116*0e209d39SAndroid Build Coastguard Worker                     || (tr1.getTo()->getDSTSavings() != 0 &&  tr2.getTo()->getDSTSavings() == 0)
117*0e209d39SAndroid Build Coastguard Worker                     || (tr1.getTo()->getDSTSavings() == 0 &&  tr2.getTo()->getDSTSavings() != 0)) {
118*0e209d39SAndroid Build Coastguard Worker                 return false;
119*0e209d39SAndroid Build Coastguard Worker             }
120*0e209d39SAndroid Build Coastguard Worker         } else {
121*0e209d39SAndroid Build Coastguard Worker             if (tr1.getTo()->getRawOffset() != tr2.getTo()->getRawOffset() ||
122*0e209d39SAndroid Build Coastguard Worker                 tr1.getTo()->getDSTSavings() != tr2.getTo()->getDSTSavings()) {
123*0e209d39SAndroid Build Coastguard Worker                 return false;
124*0e209d39SAndroid Build Coastguard Worker             }
125*0e209d39SAndroid Build Coastguard Worker         }
126*0e209d39SAndroid Build Coastguard Worker         time = tr1.getTime();
127*0e209d39SAndroid Build Coastguard Worker     }
128*0e209d39SAndroid Build Coastguard Worker     return true;
129*0e209d39SAndroid Build Coastguard Worker }
130*0e209d39SAndroid Build Coastguard Worker 
131*0e209d39SAndroid Build Coastguard Worker void
getSimpleRulesNear(UDate date,InitialTimeZoneRule * & initial,AnnualTimeZoneRule * & std,AnnualTimeZoneRule * & dst,UErrorCode & status) const132*0e209d39SAndroid Build Coastguard Worker BasicTimeZone::getSimpleRulesNear(UDate date, InitialTimeZoneRule*& initial,
133*0e209d39SAndroid Build Coastguard Worker         AnnualTimeZoneRule*& std, AnnualTimeZoneRule*& dst, UErrorCode& status) const {
134*0e209d39SAndroid Build Coastguard Worker     initial = nullptr;
135*0e209d39SAndroid Build Coastguard Worker     std = nullptr;
136*0e209d39SAndroid Build Coastguard Worker     dst = nullptr;
137*0e209d39SAndroid Build Coastguard Worker     if (U_FAILURE(status)) {
138*0e209d39SAndroid Build Coastguard Worker         return;
139*0e209d39SAndroid Build Coastguard Worker     }
140*0e209d39SAndroid Build Coastguard Worker     int32_t initialRaw, initialDst;
141*0e209d39SAndroid Build Coastguard Worker     UnicodeString initialName;
142*0e209d39SAndroid Build Coastguard Worker 
143*0e209d39SAndroid Build Coastguard Worker     AnnualTimeZoneRule *ar1 = nullptr;
144*0e209d39SAndroid Build Coastguard Worker     AnnualTimeZoneRule *ar2 = nullptr;
145*0e209d39SAndroid Build Coastguard Worker     UnicodeString name;
146*0e209d39SAndroid Build Coastguard Worker 
147*0e209d39SAndroid Build Coastguard Worker     UBool avail;
148*0e209d39SAndroid Build Coastguard Worker     TimeZoneTransition tr;
149*0e209d39SAndroid Build Coastguard Worker     // Get the next transition
150*0e209d39SAndroid Build Coastguard Worker     avail = getNextTransition(date, false, tr);
151*0e209d39SAndroid Build Coastguard Worker     if (avail) {
152*0e209d39SAndroid Build Coastguard Worker         tr.getFrom()->getName(initialName);
153*0e209d39SAndroid Build Coastguard Worker         initialRaw = tr.getFrom()->getRawOffset();
154*0e209d39SAndroid Build Coastguard Worker         initialDst = tr.getFrom()->getDSTSavings();
155*0e209d39SAndroid Build Coastguard Worker 
156*0e209d39SAndroid Build Coastguard Worker         // Check if the next transition is either DST->STD or STD->DST and
157*0e209d39SAndroid Build Coastguard Worker         // within roughly 1 year from the specified date
158*0e209d39SAndroid Build Coastguard Worker         UDate nextTransitionTime = tr.getTime();
159*0e209d39SAndroid Build Coastguard Worker         if (((tr.getFrom()->getDSTSavings() == 0 && tr.getTo()->getDSTSavings() != 0)
160*0e209d39SAndroid Build Coastguard Worker               || (tr.getFrom()->getDSTSavings() != 0 && tr.getTo()->getDSTSavings() == 0))
161*0e209d39SAndroid Build Coastguard Worker             && (date + MILLIS_PER_YEAR > nextTransitionTime)) {
162*0e209d39SAndroid Build Coastguard Worker 
163*0e209d39SAndroid Build Coastguard Worker             int32_t year, month, dom, dow, doy, mid;
164*0e209d39SAndroid Build Coastguard Worker             UDate d;
165*0e209d39SAndroid Build Coastguard Worker 
166*0e209d39SAndroid Build Coastguard Worker             // Get local wall time for the next transition time
167*0e209d39SAndroid Build Coastguard Worker             Grego::timeToFields(nextTransitionTime + initialRaw + initialDst,
168*0e209d39SAndroid Build Coastguard Worker                 year, month, dom, dow, doy, mid);
169*0e209d39SAndroid Build Coastguard Worker             int32_t weekInMonth = Grego::dayOfWeekInMonth(year, month, dom);
170*0e209d39SAndroid Build Coastguard Worker             // Create DOW rule
171*0e209d39SAndroid Build Coastguard Worker             DateTimeRule *dtr = new DateTimeRule(month, weekInMonth, dow, mid, DateTimeRule::WALL_TIME);
172*0e209d39SAndroid Build Coastguard Worker             tr.getTo()->getName(name);
173*0e209d39SAndroid Build Coastguard Worker 
174*0e209d39SAndroid Build Coastguard Worker             // Note:  SimpleTimeZone does not support raw offset change.
175*0e209d39SAndroid Build Coastguard Worker             // So we always use raw offset of the given time for the rule,
176*0e209d39SAndroid Build Coastguard Worker             // even raw offset is changed.  This will result that the result
177*0e209d39SAndroid Build Coastguard Worker             // zone to return wrong offset after the transition.
178*0e209d39SAndroid Build Coastguard Worker             // When we encounter such case, we do not inspect next next
179*0e209d39SAndroid Build Coastguard Worker             // transition for another rule.
180*0e209d39SAndroid Build Coastguard Worker             ar1 = new AnnualTimeZoneRule(name, initialRaw, tr.getTo()->getDSTSavings(),
181*0e209d39SAndroid Build Coastguard Worker                 dtr, year, AnnualTimeZoneRule::MAX_YEAR);
182*0e209d39SAndroid Build Coastguard Worker 
183*0e209d39SAndroid Build Coastguard Worker             if (tr.getTo()->getRawOffset() == initialRaw) {
184*0e209d39SAndroid Build Coastguard Worker                 // Get the next next transition
185*0e209d39SAndroid Build Coastguard Worker                 avail = getNextTransition(nextTransitionTime, false, tr);
186*0e209d39SAndroid Build Coastguard Worker                 if (avail) {
187*0e209d39SAndroid Build Coastguard Worker                     // Check if the next next transition is either DST->STD or STD->DST
188*0e209d39SAndroid Build Coastguard Worker                     // and within roughly 1 year from the next transition
189*0e209d39SAndroid Build Coastguard Worker                     if (((tr.getFrom()->getDSTSavings() == 0 && tr.getTo()->getDSTSavings() != 0)
190*0e209d39SAndroid Build Coastguard Worker                           || (tr.getFrom()->getDSTSavings() != 0 && tr.getTo()->getDSTSavings() == 0))
191*0e209d39SAndroid Build Coastguard Worker                          && nextTransitionTime + MILLIS_PER_YEAR > tr.getTime()) {
192*0e209d39SAndroid Build Coastguard Worker 
193*0e209d39SAndroid Build Coastguard Worker                         // Get local wall time for the next transition time
194*0e209d39SAndroid Build Coastguard Worker                         Grego::timeToFields(tr.getTime() + tr.getFrom()->getRawOffset() + tr.getFrom()->getDSTSavings(),
195*0e209d39SAndroid Build Coastguard Worker                             year, month, dom, dow, doy, mid);
196*0e209d39SAndroid Build Coastguard Worker                         weekInMonth = Grego::dayOfWeekInMonth(year, month, dom);
197*0e209d39SAndroid Build Coastguard Worker                         // Generate another DOW rule
198*0e209d39SAndroid Build Coastguard Worker                         dtr = new DateTimeRule(month, weekInMonth, dow, mid, DateTimeRule::WALL_TIME);
199*0e209d39SAndroid Build Coastguard Worker                         tr.getTo()->getName(name);
200*0e209d39SAndroid Build Coastguard Worker                         ar2 = new AnnualTimeZoneRule(name, tr.getTo()->getRawOffset(), tr.getTo()->getDSTSavings(),
201*0e209d39SAndroid Build Coastguard Worker                             dtr, year - 1, AnnualTimeZoneRule::MAX_YEAR);
202*0e209d39SAndroid Build Coastguard Worker 
203*0e209d39SAndroid Build Coastguard Worker                         // Make sure this rule can be applied to the specified date
204*0e209d39SAndroid Build Coastguard Worker                         avail = ar2->getPreviousStart(date, tr.getFrom()->getRawOffset(), tr.getFrom()->getDSTSavings(), true, d);
205*0e209d39SAndroid Build Coastguard Worker                         if (!avail || d > date
206*0e209d39SAndroid Build Coastguard Worker                                 || initialRaw != tr.getTo()->getRawOffset()
207*0e209d39SAndroid Build Coastguard Worker                                 || initialDst != tr.getTo()->getDSTSavings()) {
208*0e209d39SAndroid Build Coastguard Worker                             // We cannot use this rule as the second transition rule
209*0e209d39SAndroid Build Coastguard Worker                             delete ar2;
210*0e209d39SAndroid Build Coastguard Worker                             ar2 = nullptr;
211*0e209d39SAndroid Build Coastguard Worker                         }
212*0e209d39SAndroid Build Coastguard Worker                     }
213*0e209d39SAndroid Build Coastguard Worker                 }
214*0e209d39SAndroid Build Coastguard Worker             }
215*0e209d39SAndroid Build Coastguard Worker             if (ar2 == nullptr) {
216*0e209d39SAndroid Build Coastguard Worker                 // Try previous transition
217*0e209d39SAndroid Build Coastguard Worker                 avail = getPreviousTransition(date, true, tr);
218*0e209d39SAndroid Build Coastguard Worker                 if (avail) {
219*0e209d39SAndroid Build Coastguard Worker                     // Check if the previous transition is either DST->STD or STD->DST.
220*0e209d39SAndroid Build Coastguard Worker                     // The actual transition time does not matter here.
221*0e209d39SAndroid Build Coastguard Worker                     if ((tr.getFrom()->getDSTSavings() == 0 && tr.getTo()->getDSTSavings() != 0)
222*0e209d39SAndroid Build Coastguard Worker                         || (tr.getFrom()->getDSTSavings() != 0 && tr.getTo()->getDSTSavings() == 0)) {
223*0e209d39SAndroid Build Coastguard Worker 
224*0e209d39SAndroid Build Coastguard Worker                         // Generate another DOW rule
225*0e209d39SAndroid Build Coastguard Worker                         Grego::timeToFields(tr.getTime() + tr.getFrom()->getRawOffset() + tr.getFrom()->getDSTSavings(),
226*0e209d39SAndroid Build Coastguard Worker                             year, month, dom, dow, doy, mid);
227*0e209d39SAndroid Build Coastguard Worker                         weekInMonth = Grego::dayOfWeekInMonth(year, month, dom);
228*0e209d39SAndroid Build Coastguard Worker                         dtr = new DateTimeRule(month, weekInMonth, dow, mid, DateTimeRule::WALL_TIME);
229*0e209d39SAndroid Build Coastguard Worker                         tr.getTo()->getName(name);
230*0e209d39SAndroid Build Coastguard Worker 
231*0e209d39SAndroid Build Coastguard Worker                         // second rule raw/dst offsets should match raw/dst offsets
232*0e209d39SAndroid Build Coastguard Worker                         // at the given time
233*0e209d39SAndroid Build Coastguard Worker                         ar2 = new AnnualTimeZoneRule(name, initialRaw, initialDst,
234*0e209d39SAndroid Build Coastguard Worker                             dtr, ar1->getStartYear() - 1, AnnualTimeZoneRule::MAX_YEAR);
235*0e209d39SAndroid Build Coastguard Worker 
236*0e209d39SAndroid Build Coastguard Worker                         // Check if this rule start after the first rule after the specified date
237*0e209d39SAndroid Build Coastguard Worker                         avail = ar2->getNextStart(date, tr.getFrom()->getRawOffset(), tr.getFrom()->getDSTSavings(), false, d);
238*0e209d39SAndroid Build Coastguard Worker                         if (!avail || d <= nextTransitionTime) {
239*0e209d39SAndroid Build Coastguard Worker                             // We cannot use this rule as the second transition rule
240*0e209d39SAndroid Build Coastguard Worker                             delete ar2;
241*0e209d39SAndroid Build Coastguard Worker                             ar2 = nullptr;
242*0e209d39SAndroid Build Coastguard Worker                         }
243*0e209d39SAndroid Build Coastguard Worker                     }
244*0e209d39SAndroid Build Coastguard Worker                 }
245*0e209d39SAndroid Build Coastguard Worker             }
246*0e209d39SAndroid Build Coastguard Worker             if (ar2 == nullptr) {
247*0e209d39SAndroid Build Coastguard Worker                 // Cannot find a good pair of AnnualTimeZoneRule
248*0e209d39SAndroid Build Coastguard Worker                 delete ar1;
249*0e209d39SAndroid Build Coastguard Worker                 ar1 = nullptr;
250*0e209d39SAndroid Build Coastguard Worker             } else {
251*0e209d39SAndroid Build Coastguard Worker                 // The initial rule should represent the rule before the previous transition
252*0e209d39SAndroid Build Coastguard Worker                 ar1->getName(initialName);
253*0e209d39SAndroid Build Coastguard Worker                 initialRaw = ar1->getRawOffset();
254*0e209d39SAndroid Build Coastguard Worker                 initialDst = ar1->getDSTSavings();
255*0e209d39SAndroid Build Coastguard Worker             }
256*0e209d39SAndroid Build Coastguard Worker         }
257*0e209d39SAndroid Build Coastguard Worker     }
258*0e209d39SAndroid Build Coastguard Worker     else {
259*0e209d39SAndroid Build Coastguard Worker         // Try the previous one
260*0e209d39SAndroid Build Coastguard Worker         avail = getPreviousTransition(date, true, tr);
261*0e209d39SAndroid Build Coastguard Worker         if (avail) {
262*0e209d39SAndroid Build Coastguard Worker             tr.getTo()->getName(initialName);
263*0e209d39SAndroid Build Coastguard Worker             initialRaw = tr.getTo()->getRawOffset();
264*0e209d39SAndroid Build Coastguard Worker             initialDst = tr.getTo()->getDSTSavings();
265*0e209d39SAndroid Build Coastguard Worker         } else {
266*0e209d39SAndroid Build Coastguard Worker             // No transitions in the past.  Just use the current offsets
267*0e209d39SAndroid Build Coastguard Worker             getOffset(date, false, initialRaw, initialDst, status);
268*0e209d39SAndroid Build Coastguard Worker             if (U_FAILURE(status)) {
269*0e209d39SAndroid Build Coastguard Worker                 return;
270*0e209d39SAndroid Build Coastguard Worker             }
271*0e209d39SAndroid Build Coastguard Worker         }
272*0e209d39SAndroid Build Coastguard Worker     }
273*0e209d39SAndroid Build Coastguard Worker     // Set the initial rule
274*0e209d39SAndroid Build Coastguard Worker     initial = new InitialTimeZoneRule(initialName, initialRaw, initialDst);
275*0e209d39SAndroid Build Coastguard Worker 
276*0e209d39SAndroid Build Coastguard Worker     // Set the standard and daylight saving rules
277*0e209d39SAndroid Build Coastguard Worker     if (ar1 != nullptr && ar2 != nullptr) {
278*0e209d39SAndroid Build Coastguard Worker         if (ar1->getDSTSavings() != 0) {
279*0e209d39SAndroid Build Coastguard Worker             dst = ar1;
280*0e209d39SAndroid Build Coastguard Worker             std = ar2;
281*0e209d39SAndroid Build Coastguard Worker         } else {
282*0e209d39SAndroid Build Coastguard Worker             std = ar1;
283*0e209d39SAndroid Build Coastguard Worker             dst = ar2;
284*0e209d39SAndroid Build Coastguard Worker         }
285*0e209d39SAndroid Build Coastguard Worker     }
286*0e209d39SAndroid Build Coastguard Worker }
287*0e209d39SAndroid Build Coastguard Worker 
288*0e209d39SAndroid Build Coastguard Worker void
getTimeZoneRulesAfter(UDate start,InitialTimeZoneRule * & initial,UVector * & transitionRules,UErrorCode & status) const289*0e209d39SAndroid Build Coastguard Worker BasicTimeZone::getTimeZoneRulesAfter(UDate start, InitialTimeZoneRule*& initial,
290*0e209d39SAndroid Build Coastguard Worker                                      UVector*& transitionRules, UErrorCode& status) const {
291*0e209d39SAndroid Build Coastguard Worker     if (U_FAILURE(status)) {
292*0e209d39SAndroid Build Coastguard Worker         return;
293*0e209d39SAndroid Build Coastguard Worker     }
294*0e209d39SAndroid Build Coastguard Worker 
295*0e209d39SAndroid Build Coastguard Worker     const InitialTimeZoneRule *orgini;
296*0e209d39SAndroid Build Coastguard Worker     TimeZoneTransition tzt;
297*0e209d39SAndroid Build Coastguard Worker     bool avail;
298*0e209d39SAndroid Build Coastguard Worker     int32_t ruleCount;
299*0e209d39SAndroid Build Coastguard Worker     TimeZoneRule *r = nullptr;
300*0e209d39SAndroid Build Coastguard Worker     UnicodeString name;
301*0e209d39SAndroid Build Coastguard Worker     int32_t i;
302*0e209d39SAndroid Build Coastguard Worker     UDate time, t;
303*0e209d39SAndroid Build Coastguard Worker     UDate firstStart;
304*0e209d39SAndroid Build Coastguard Worker     UBool bFinalStd = false, bFinalDst = false;
305*0e209d39SAndroid Build Coastguard Worker 
306*0e209d39SAndroid Build Coastguard Worker     initial = nullptr;
307*0e209d39SAndroid Build Coastguard Worker     transitionRules = nullptr;
308*0e209d39SAndroid Build Coastguard Worker 
309*0e209d39SAndroid Build Coastguard Worker     // Original transition rules
310*0e209d39SAndroid Build Coastguard Worker     ruleCount = countTransitionRules(status);
311*0e209d39SAndroid Build Coastguard Worker     if (U_FAILURE(status)) {
312*0e209d39SAndroid Build Coastguard Worker         return;
313*0e209d39SAndroid Build Coastguard Worker     }
314*0e209d39SAndroid Build Coastguard Worker     LocalPointer<UVector> orgRules(
315*0e209d39SAndroid Build Coastguard Worker         new UVector(uprv_deleteUObject, nullptr, ruleCount, status), status);
316*0e209d39SAndroid Build Coastguard Worker     if (U_FAILURE(status)) {
317*0e209d39SAndroid Build Coastguard Worker         return;
318*0e209d39SAndroid Build Coastguard Worker     }
319*0e209d39SAndroid Build Coastguard Worker     LocalMemory<const TimeZoneRule *> orgtrs(
320*0e209d39SAndroid Build Coastguard Worker         static_cast<const TimeZoneRule **>(uprv_malloc(sizeof(TimeZoneRule*)*ruleCount)));
321*0e209d39SAndroid Build Coastguard Worker     if (orgtrs.isNull()) {
322*0e209d39SAndroid Build Coastguard Worker         status = U_MEMORY_ALLOCATION_ERROR;
323*0e209d39SAndroid Build Coastguard Worker         return;
324*0e209d39SAndroid Build Coastguard Worker     }
325*0e209d39SAndroid Build Coastguard Worker     getTimeZoneRules(orgini, &orgtrs[0], ruleCount, status);
326*0e209d39SAndroid Build Coastguard Worker     if (U_FAILURE(status)) {
327*0e209d39SAndroid Build Coastguard Worker         return;
328*0e209d39SAndroid Build Coastguard Worker     }
329*0e209d39SAndroid Build Coastguard Worker     for (i = 0; i < ruleCount; i++) {
330*0e209d39SAndroid Build Coastguard Worker         LocalPointer<TimeZoneRule> lpRule(orgtrs[i]->clone(), status);
331*0e209d39SAndroid Build Coastguard Worker         orgRules->adoptElement(lpRule.orphan(), status);
332*0e209d39SAndroid Build Coastguard Worker         if (U_FAILURE(status)) {
333*0e209d39SAndroid Build Coastguard Worker             return;
334*0e209d39SAndroid Build Coastguard Worker         }
335*0e209d39SAndroid Build Coastguard Worker     }
336*0e209d39SAndroid Build Coastguard Worker 
337*0e209d39SAndroid Build Coastguard Worker     avail = getPreviousTransition(start, true, tzt);
338*0e209d39SAndroid Build Coastguard Worker     if (!avail) {
339*0e209d39SAndroid Build Coastguard Worker         // No need to filter out rules only applicable to time before the start
340*0e209d39SAndroid Build Coastguard Worker         initial = orgini->clone();
341*0e209d39SAndroid Build Coastguard Worker         if (initial == nullptr) {
342*0e209d39SAndroid Build Coastguard Worker             status = U_MEMORY_ALLOCATION_ERROR;
343*0e209d39SAndroid Build Coastguard Worker             return;
344*0e209d39SAndroid Build Coastguard Worker         }
345*0e209d39SAndroid Build Coastguard Worker         transitionRules = orgRules.orphan();
346*0e209d39SAndroid Build Coastguard Worker         return;
347*0e209d39SAndroid Build Coastguard Worker     }
348*0e209d39SAndroid Build Coastguard Worker 
349*0e209d39SAndroid Build Coastguard Worker     LocalMemory<bool> done(static_cast<bool *>(uprv_malloc(sizeof(bool)*ruleCount)));
350*0e209d39SAndroid Build Coastguard Worker     if (done.isNull()) {
351*0e209d39SAndroid Build Coastguard Worker         status = U_MEMORY_ALLOCATION_ERROR;
352*0e209d39SAndroid Build Coastguard Worker         return;
353*0e209d39SAndroid Build Coastguard Worker     }
354*0e209d39SAndroid Build Coastguard Worker     LocalPointer<UVector> filteredRules(
355*0e209d39SAndroid Build Coastguard Worker         new UVector(uprv_deleteUObject, nullptr, status), status);
356*0e209d39SAndroid Build Coastguard Worker     if (U_FAILURE(status)) {
357*0e209d39SAndroid Build Coastguard Worker         return;
358*0e209d39SAndroid Build Coastguard Worker     }
359*0e209d39SAndroid Build Coastguard Worker 
360*0e209d39SAndroid Build Coastguard Worker     // Create initial rule
361*0e209d39SAndroid Build Coastguard Worker     tzt.getTo()->getName(name);
362*0e209d39SAndroid Build Coastguard Worker     LocalPointer<InitialTimeZoneRule> res_initial(
363*0e209d39SAndroid Build Coastguard Worker         new InitialTimeZoneRule(name, tzt.getTo()->getRawOffset(), tzt.getTo()->getDSTSavings()), status);
364*0e209d39SAndroid Build Coastguard Worker     if (U_FAILURE(status)) {
365*0e209d39SAndroid Build Coastguard Worker         return;
366*0e209d39SAndroid Build Coastguard Worker     }
367*0e209d39SAndroid Build Coastguard Worker 
368*0e209d39SAndroid Build Coastguard Worker     // Mark rules which does not need to be processed
369*0e209d39SAndroid Build Coastguard Worker     for (i = 0; i < ruleCount; i++) {
370*0e209d39SAndroid Build Coastguard Worker         r = (TimeZoneRule*)orgRules->elementAt(i);
371*0e209d39SAndroid Build Coastguard Worker         avail = r->getNextStart(start, res_initial->getRawOffset(), res_initial->getDSTSavings(), false, time);
372*0e209d39SAndroid Build Coastguard Worker         done[i] = !avail;
373*0e209d39SAndroid Build Coastguard Worker     }
374*0e209d39SAndroid Build Coastguard Worker 
375*0e209d39SAndroid Build Coastguard Worker     time = start;
376*0e209d39SAndroid Build Coastguard Worker     while (!bFinalStd || !bFinalDst) {
377*0e209d39SAndroid Build Coastguard Worker         avail = getNextTransition(time, false, tzt);
378*0e209d39SAndroid Build Coastguard Worker         if (!avail) {
379*0e209d39SAndroid Build Coastguard Worker             break;
380*0e209d39SAndroid Build Coastguard Worker         }
381*0e209d39SAndroid Build Coastguard Worker         UDate updatedTime = tzt.getTime();
382*0e209d39SAndroid Build Coastguard Worker         if (updatedTime == time) {
383*0e209d39SAndroid Build Coastguard Worker             // Can get here if rules for start & end of daylight time have exactly
384*0e209d39SAndroid Build Coastguard Worker             // the same time.
385*0e209d39SAndroid Build Coastguard Worker             // TODO:  fix getNextTransition() to prevent it?
386*0e209d39SAndroid Build Coastguard Worker             status = U_INVALID_STATE_ERROR;
387*0e209d39SAndroid Build Coastguard Worker             return;
388*0e209d39SAndroid Build Coastguard Worker         }
389*0e209d39SAndroid Build Coastguard Worker         time = updatedTime;
390*0e209d39SAndroid Build Coastguard Worker 
391*0e209d39SAndroid Build Coastguard Worker         const TimeZoneRule *toRule = tzt.getTo();
392*0e209d39SAndroid Build Coastguard Worker         for (i = 0; i < ruleCount; i++) {
393*0e209d39SAndroid Build Coastguard Worker             r = (TimeZoneRule*)orgRules->elementAt(i);
394*0e209d39SAndroid Build Coastguard Worker             if (*r == *toRule) {
395*0e209d39SAndroid Build Coastguard Worker                 break;
396*0e209d39SAndroid Build Coastguard Worker             }
397*0e209d39SAndroid Build Coastguard Worker         }
398*0e209d39SAndroid Build Coastguard Worker         if (i >= ruleCount) {
399*0e209d39SAndroid Build Coastguard Worker             // This case should never happen
400*0e209d39SAndroid Build Coastguard Worker             status = U_INVALID_STATE_ERROR;
401*0e209d39SAndroid Build Coastguard Worker             return;
402*0e209d39SAndroid Build Coastguard Worker         }
403*0e209d39SAndroid Build Coastguard Worker         if (done[i]) {
404*0e209d39SAndroid Build Coastguard Worker             continue;
405*0e209d39SAndroid Build Coastguard Worker         }
406*0e209d39SAndroid Build Coastguard Worker         const TimeArrayTimeZoneRule *tar = dynamic_cast<const TimeArrayTimeZoneRule *>(toRule);
407*0e209d39SAndroid Build Coastguard Worker         const AnnualTimeZoneRule *ar;
408*0e209d39SAndroid Build Coastguard Worker         if (tar != nullptr) {
409*0e209d39SAndroid Build Coastguard Worker             // Get the previous raw offset and DST savings before the very first start time
410*0e209d39SAndroid Build Coastguard Worker             TimeZoneTransition tzt0;
411*0e209d39SAndroid Build Coastguard Worker             t = start;
412*0e209d39SAndroid Build Coastguard Worker             while (true) {
413*0e209d39SAndroid Build Coastguard Worker                 avail = getNextTransition(t, false, tzt0);
414*0e209d39SAndroid Build Coastguard Worker                 if (!avail) {
415*0e209d39SAndroid Build Coastguard Worker                     break;
416*0e209d39SAndroid Build Coastguard Worker                 }
417*0e209d39SAndroid Build Coastguard Worker                 if (*(tzt0.getTo()) == *tar) {
418*0e209d39SAndroid Build Coastguard Worker                     break;
419*0e209d39SAndroid Build Coastguard Worker                 }
420*0e209d39SAndroid Build Coastguard Worker                 t = tzt0.getTime();
421*0e209d39SAndroid Build Coastguard Worker             }
422*0e209d39SAndroid Build Coastguard Worker             if (avail) {
423*0e209d39SAndroid Build Coastguard Worker                 // Check if the entire start times to be added
424*0e209d39SAndroid Build Coastguard Worker                 tar->getFirstStart(tzt.getFrom()->getRawOffset(), tzt.getFrom()->getDSTSavings(), firstStart);
425*0e209d39SAndroid Build Coastguard Worker                 if (firstStart > start) {
426*0e209d39SAndroid Build Coastguard Worker                     // Just add the rule as is
427*0e209d39SAndroid Build Coastguard Worker                     LocalPointer<TimeArrayTimeZoneRule> lpTar(tar->clone(), status);
428*0e209d39SAndroid Build Coastguard Worker                     filteredRules->adoptElement(lpTar.orphan(), status);
429*0e209d39SAndroid Build Coastguard Worker                     if (U_FAILURE(status)) {
430*0e209d39SAndroid Build Coastguard Worker                         return;
431*0e209d39SAndroid Build Coastguard Worker                     }
432*0e209d39SAndroid Build Coastguard Worker                 } else {
433*0e209d39SAndroid Build Coastguard Worker                     // Collect transitions after the start time
434*0e209d39SAndroid Build Coastguard Worker                     int32_t startTimes;
435*0e209d39SAndroid Build Coastguard Worker                     DateTimeRule::TimeRuleType timeType;
436*0e209d39SAndroid Build Coastguard Worker                     int32_t idx;
437*0e209d39SAndroid Build Coastguard Worker 
438*0e209d39SAndroid Build Coastguard Worker                     startTimes = tar->countStartTimes();
439*0e209d39SAndroid Build Coastguard Worker                     timeType = tar->getTimeType();
440*0e209d39SAndroid Build Coastguard Worker                     for (idx = 0; idx < startTimes; idx++) {
441*0e209d39SAndroid Build Coastguard Worker                         tar->getStartTimeAt(idx, t);
442*0e209d39SAndroid Build Coastguard Worker                         if (timeType == DateTimeRule::STANDARD_TIME) {
443*0e209d39SAndroid Build Coastguard Worker                             t -= tzt.getFrom()->getRawOffset();
444*0e209d39SAndroid Build Coastguard Worker                         }
445*0e209d39SAndroid Build Coastguard Worker                         if (timeType == DateTimeRule::WALL_TIME) {
446*0e209d39SAndroid Build Coastguard Worker                             t -= tzt.getFrom()->getDSTSavings();
447*0e209d39SAndroid Build Coastguard Worker                         }
448*0e209d39SAndroid Build Coastguard Worker                         if (t > start) {
449*0e209d39SAndroid Build Coastguard Worker                             break;
450*0e209d39SAndroid Build Coastguard Worker                         }
451*0e209d39SAndroid Build Coastguard Worker                     }
452*0e209d39SAndroid Build Coastguard Worker                     if (U_FAILURE(status)) {
453*0e209d39SAndroid Build Coastguard Worker                         return;
454*0e209d39SAndroid Build Coastguard Worker                     }
455*0e209d39SAndroid Build Coastguard Worker                     int32_t asize = startTimes - idx;
456*0e209d39SAndroid Build Coastguard Worker                     if (asize > 0) {
457*0e209d39SAndroid Build Coastguard Worker                         LocalMemory<UDate> newTimes(static_cast<UDate *>(uprv_malloc(sizeof(UDate) * asize)));
458*0e209d39SAndroid Build Coastguard Worker                         if (newTimes.isNull()) {
459*0e209d39SAndroid Build Coastguard Worker                             status = U_MEMORY_ALLOCATION_ERROR;
460*0e209d39SAndroid Build Coastguard Worker                             return;
461*0e209d39SAndroid Build Coastguard Worker                         }
462*0e209d39SAndroid Build Coastguard Worker                         for (int32_t newidx = 0; newidx < asize; newidx++) {
463*0e209d39SAndroid Build Coastguard Worker                             tar->getStartTimeAt(idx + newidx, newTimes[newidx]);
464*0e209d39SAndroid Build Coastguard Worker                         }
465*0e209d39SAndroid Build Coastguard Worker                         tar->getName(name);
466*0e209d39SAndroid Build Coastguard Worker                         LocalPointer<TimeArrayTimeZoneRule> newTar(new TimeArrayTimeZoneRule(
467*0e209d39SAndroid Build Coastguard Worker                                 name, tar->getRawOffset(), tar->getDSTSavings(), &newTimes[0], asize, timeType), status);
468*0e209d39SAndroid Build Coastguard Worker                         filteredRules->adoptElement(newTar.orphan(), status);
469*0e209d39SAndroid Build Coastguard Worker                         if (U_FAILURE(status)) {
470*0e209d39SAndroid Build Coastguard Worker                             return;
471*0e209d39SAndroid Build Coastguard Worker                         }
472*0e209d39SAndroid Build Coastguard Worker                     }
473*0e209d39SAndroid Build Coastguard Worker                 }
474*0e209d39SAndroid Build Coastguard Worker             }
475*0e209d39SAndroid Build Coastguard Worker         } else if ((ar = dynamic_cast<const AnnualTimeZoneRule *>(toRule)) != nullptr) {
476*0e209d39SAndroid Build Coastguard Worker             ar->getFirstStart(tzt.getFrom()->getRawOffset(), tzt.getFrom()->getDSTSavings(), firstStart);
477*0e209d39SAndroid Build Coastguard Worker             if (firstStart == tzt.getTime()) {
478*0e209d39SAndroid Build Coastguard Worker                 // Just add the rule as is
479*0e209d39SAndroid Build Coastguard Worker                 LocalPointer<AnnualTimeZoneRule> arClone(ar->clone(), status);
480*0e209d39SAndroid Build Coastguard Worker                 filteredRules->adoptElement(arClone.orphan(), status);
481*0e209d39SAndroid Build Coastguard Worker                 if (U_FAILURE(status)) {
482*0e209d39SAndroid Build Coastguard Worker                     return;
483*0e209d39SAndroid Build Coastguard Worker                 }
484*0e209d39SAndroid Build Coastguard Worker             } else {
485*0e209d39SAndroid Build Coastguard Worker                 // Calculate the transition year
486*0e209d39SAndroid Build Coastguard Worker                 int32_t year, month, dom, dow, doy, mid;
487*0e209d39SAndroid Build Coastguard Worker                 Grego::timeToFields(tzt.getTime(), year, month, dom, dow, doy, mid);
488*0e209d39SAndroid Build Coastguard Worker                 // Re-create the rule
489*0e209d39SAndroid Build Coastguard Worker                 ar->getName(name);
490*0e209d39SAndroid Build Coastguard Worker                 LocalPointer<AnnualTimeZoneRule> newAr(new AnnualTimeZoneRule(name, ar->getRawOffset(), ar->getDSTSavings(),
491*0e209d39SAndroid Build Coastguard Worker                     *(ar->getRule()), year, ar->getEndYear()), status);
492*0e209d39SAndroid Build Coastguard Worker                 filteredRules->adoptElement(newAr.orphan(), status);
493*0e209d39SAndroid Build Coastguard Worker                 if (U_FAILURE(status)) {
494*0e209d39SAndroid Build Coastguard Worker                     return;
495*0e209d39SAndroid Build Coastguard Worker                 }
496*0e209d39SAndroid Build Coastguard Worker             }
497*0e209d39SAndroid Build Coastguard Worker             // check if this is a final rule
498*0e209d39SAndroid Build Coastguard Worker             if (ar->getEndYear() == AnnualTimeZoneRule::MAX_YEAR) {
499*0e209d39SAndroid Build Coastguard Worker                 // After bot final standard and dst rules are processed,
500*0e209d39SAndroid Build Coastguard Worker                 // exit this while loop.
501*0e209d39SAndroid Build Coastguard Worker                 if (ar->getDSTSavings() == 0) {
502*0e209d39SAndroid Build Coastguard Worker                     bFinalStd = true;
503*0e209d39SAndroid Build Coastguard Worker                 } else {
504*0e209d39SAndroid Build Coastguard Worker                     bFinalDst = true;
505*0e209d39SAndroid Build Coastguard Worker                 }
506*0e209d39SAndroid Build Coastguard Worker             }
507*0e209d39SAndroid Build Coastguard Worker         }
508*0e209d39SAndroid Build Coastguard Worker         done[i] = true;
509*0e209d39SAndroid Build Coastguard Worker     }
510*0e209d39SAndroid Build Coastguard Worker 
511*0e209d39SAndroid Build Coastguard Worker     // Set the results
512*0e209d39SAndroid Build Coastguard Worker     initial = res_initial.orphan();
513*0e209d39SAndroid Build Coastguard Worker     transitionRules = filteredRules.orphan();
514*0e209d39SAndroid Build Coastguard Worker }
515*0e209d39SAndroid Build Coastguard Worker 
516*0e209d39SAndroid Build Coastguard Worker void
getOffsetFromLocal(UDate,UTimeZoneLocalOption,UTimeZoneLocalOption,int32_t &,int32_t &,UErrorCode & status) const517*0e209d39SAndroid Build Coastguard Worker BasicTimeZone::getOffsetFromLocal(UDate /*date*/, UTimeZoneLocalOption /*nonExistingTimeOpt*/,
518*0e209d39SAndroid Build Coastguard Worker                                   UTimeZoneLocalOption /*duplicatedTimeOpt*/,
519*0e209d39SAndroid Build Coastguard Worker                                   int32_t& /*rawOffset*/, int32_t& /*dstOffset*/,
520*0e209d39SAndroid Build Coastguard Worker                                   UErrorCode& status) const {
521*0e209d39SAndroid Build Coastguard Worker     if (U_FAILURE(status)) {
522*0e209d39SAndroid Build Coastguard Worker         return;
523*0e209d39SAndroid Build Coastguard Worker     }
524*0e209d39SAndroid Build Coastguard Worker     status = U_UNSUPPORTED_ERROR;
525*0e209d39SAndroid Build Coastguard Worker }
526*0e209d39SAndroid Build Coastguard Worker 
getOffsetFromLocal(UDate date,int32_t nonExistingTimeOpt,int32_t duplicatedTimeOpt,int32_t & rawOffset,int32_t & dstOffset,UErrorCode & status) const527*0e209d39SAndroid Build Coastguard Worker void BasicTimeZone::getOffsetFromLocal(UDate date, int32_t nonExistingTimeOpt, int32_t duplicatedTimeOpt,
528*0e209d39SAndroid Build Coastguard Worker                                        int32_t& rawOffset, int32_t& dstOffset,
529*0e209d39SAndroid Build Coastguard Worker                                        UErrorCode& status) const {
530*0e209d39SAndroid Build Coastguard Worker     getOffsetFromLocal(date, (UTimeZoneLocalOption)nonExistingTimeOpt,
531*0e209d39SAndroid Build Coastguard Worker                        (UTimeZoneLocalOption)duplicatedTimeOpt, rawOffset, dstOffset, status);
532*0e209d39SAndroid Build Coastguard Worker }
533*0e209d39SAndroid Build Coastguard Worker 
534*0e209d39SAndroid Build Coastguard Worker U_NAMESPACE_END
535*0e209d39SAndroid Build Coastguard Worker 
536*0e209d39SAndroid Build Coastguard Worker #endif /* #if !UCONFIG_NO_FORMATTING */
537*0e209d39SAndroid Build Coastguard Worker 
538*0e209d39SAndroid Build Coastguard Worker //eof
539