blob: dfc3aea6cbc41a54b6a76b7367b6131d001810bf [file] [log] [blame]
Jungshik Shin87232d82017-05-13 21:10:13 -07001// © 2016 and later: Unicode, Inc. and others.
Jungshik Shin5feb9ad2016-10-21 12:52:48 -07002// License & terms of use: http://www.unicode.org/copyright.html
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00003/*
4*******************************************************************************
5* Copyright (C) 2007-2013, International Business Machines Corporation and
6* others. All Rights Reserved.
7*******************************************************************************
8*/
9
10#include "unicode/utypes.h"
11
12#if !UCONFIG_NO_FORMATTING
13
14#include "unicode/basictz.h"
15#include "gregoimp.h"
16#include "uvector.h"
17#include "cmemory.h"
18
19U_NAMESPACE_BEGIN
20
21#define MILLIS_PER_YEAR (365*24*60*60*1000.0)
22
23BasicTimeZone::BasicTimeZone()
24: TimeZone() {
25}
26
27BasicTimeZone::BasicTimeZone(const UnicodeString &id)
28: TimeZone(id) {
29}
30
31BasicTimeZone::BasicTimeZone(const BasicTimeZone& source)
32: TimeZone(source) {
33}
34
35BasicTimeZone::~BasicTimeZone() {
36}
37
38UBool
39BasicTimeZone::hasEquivalentTransitions(const BasicTimeZone& tz, UDate start, UDate end,
40 UBool ignoreDstAmount, UErrorCode& status) const {
41 if (U_FAILURE(status)) {
Frank Tang1f164ee2022-11-08 12:31:27 -080042 return false;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +000043 }
44 if (hasSameRules(tz)) {
Frank Tang1f164ee2022-11-08 12:31:27 -080045 return true;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +000046 }
47 // Check the offsets at the start time
48 int32_t raw1, raw2, dst1, dst2;
Frank Tang1f164ee2022-11-08 12:31:27 -080049 getOffset(start, false, raw1, dst1, status);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +000050 if (U_FAILURE(status)) {
Frank Tang1f164ee2022-11-08 12:31:27 -080051 return false;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +000052 }
Frank Tang1f164ee2022-11-08 12:31:27 -080053 tz.getOffset(start, false, raw2, dst2, status);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +000054 if (U_FAILURE(status)) {
Frank Tang1f164ee2022-11-08 12:31:27 -080055 return false;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +000056 }
57 if (ignoreDstAmount) {
58 if ((raw1 + dst1 != raw2 + dst2)
59 || (dst1 != 0 && dst2 == 0)
60 || (dst1 == 0 && dst2 != 0)) {
Frank Tang1f164ee2022-11-08 12:31:27 -080061 return false;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +000062 }
63 } else {
64 if (raw1 != raw2 || dst1 != dst2) {
Frank Tang1f164ee2022-11-08 12:31:27 -080065 return false;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +000066 }
67 }
68 // Check transitions in the range
69 UDate time = start;
70 TimeZoneTransition tr1, tr2;
Frank Tang1f164ee2022-11-08 12:31:27 -080071 while (true) {
72 UBool avail1 = getNextTransition(time, false, tr1);
73 UBool avail2 = tz.getNextTransition(time, false, tr2);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +000074
75 if (ignoreDstAmount) {
76 // Skip a transition which only differ the amount of DST savings
Frank Tang1f164ee2022-11-08 12:31:27 -080077 while (true) {
jshin@chromium.org6f31ac32014-03-26 22:15:14 +000078 if (avail1
79 && tr1.getTime() <= end
80 && (tr1.getFrom()->getRawOffset() + tr1.getFrom()->getDSTSavings()
81 == tr1.getTo()->getRawOffset() + tr1.getTo()->getDSTSavings())
82 && (tr1.getFrom()->getDSTSavings() != 0 && tr1.getTo()->getDSTSavings() != 0)) {
Frank Tang1f164ee2022-11-08 12:31:27 -080083 getNextTransition(tr1.getTime(), false, tr1);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +000084 } else {
85 break;
86 }
87 }
Frank Tang1f164ee2022-11-08 12:31:27 -080088 while (true) {
jshin@chromium.org6f31ac32014-03-26 22:15:14 +000089 if (avail2
90 && tr2.getTime() <= end
91 && (tr2.getFrom()->getRawOffset() + tr2.getFrom()->getDSTSavings()
92 == tr2.getTo()->getRawOffset() + tr2.getTo()->getDSTSavings())
93 && (tr2.getFrom()->getDSTSavings() != 0 && tr2.getTo()->getDSTSavings() != 0)) {
Frank Tang1f164ee2022-11-08 12:31:27 -080094 tz.getNextTransition(tr2.getTime(), false, tr2);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +000095 } else {
96 break;
97 }
98 }
99 }
100
101 UBool inRange1 = (avail1 && tr1.getTime() <= end);
102 UBool inRange2 = (avail2 && tr2.getTime() <= end);
103 if (!inRange1 && !inRange2) {
104 // No more transition in the range
105 break;
106 }
107 if (!inRange1 || !inRange2) {
Frank Tang1f164ee2022-11-08 12:31:27 -0800108 return false;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000109 }
110 if (tr1.getTime() != tr2.getTime()) {
Frank Tang1f164ee2022-11-08 12:31:27 -0800111 return false;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000112 }
113 if (ignoreDstAmount) {
114 if (tr1.getTo()->getRawOffset() + tr1.getTo()->getDSTSavings()
115 != tr2.getTo()->getRawOffset() + tr2.getTo()->getDSTSavings()
116 || (tr1.getTo()->getDSTSavings() != 0 && tr2.getTo()->getDSTSavings() == 0)
117 || (tr1.getTo()->getDSTSavings() == 0 && tr2.getTo()->getDSTSavings() != 0)) {
Frank Tang1f164ee2022-11-08 12:31:27 -0800118 return false;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000119 }
120 } else {
121 if (tr1.getTo()->getRawOffset() != tr2.getTo()->getRawOffset() ||
122 tr1.getTo()->getDSTSavings() != tr2.getTo()->getDSTSavings()) {
Frank Tang1f164ee2022-11-08 12:31:27 -0800123 return false;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000124 }
125 }
126 time = tr1.getTime();
127 }
Frank Tang1f164ee2022-11-08 12:31:27 -0800128 return true;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000129}
130
131void
132BasicTimeZone::getSimpleRulesNear(UDate date, InitialTimeZoneRule*& initial,
133 AnnualTimeZoneRule*& std, AnnualTimeZoneRule*& dst, UErrorCode& status) const {
134 initial = NULL;
135 std = NULL;
136 dst = NULL;
137 if (U_FAILURE(status)) {
138 return;
139 }
140 int32_t initialRaw, initialDst;
141 UnicodeString initialName;
142
143 AnnualTimeZoneRule *ar1 = NULL;
144 AnnualTimeZoneRule *ar2 = NULL;
145 UnicodeString name;
146
147 UBool avail;
148 TimeZoneTransition tr;
149 // Get the next transition
Frank Tang1f164ee2022-11-08 12:31:27 -0800150 avail = getNextTransition(date, false, tr);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000151 if (avail) {
152 tr.getFrom()->getName(initialName);
153 initialRaw = tr.getFrom()->getRawOffset();
154 initialDst = tr.getFrom()->getDSTSavings();
155
156 // Check if the next transition is either DST->STD or STD->DST and
157 // within roughly 1 year from the specified date
158 UDate nextTransitionTime = tr.getTime();
159 if (((tr.getFrom()->getDSTSavings() == 0 && tr.getTo()->getDSTSavings() != 0)
160 || (tr.getFrom()->getDSTSavings() != 0 && tr.getTo()->getDSTSavings() == 0))
161 && (date + MILLIS_PER_YEAR > nextTransitionTime)) {
162
163 int32_t year, month, dom, dow, doy, mid;
164 UDate d;
165
166 // Get local wall time for the next transition time
167 Grego::timeToFields(nextTransitionTime + initialRaw + initialDst,
168 year, month, dom, dow, doy, mid);
169 int32_t weekInMonth = Grego::dayOfWeekInMonth(year, month, dom);
170 // Create DOW rule
171 DateTimeRule *dtr = new DateTimeRule(month, weekInMonth, dow, mid, DateTimeRule::WALL_TIME);
172 tr.getTo()->getName(name);
173
174 // Note: SimpleTimeZone does not support raw offset change.
175 // So we always use raw offset of the given time for the rule,
176 // even raw offset is changed. This will result that the result
177 // zone to return wrong offset after the transition.
178 // When we encounter such case, we do not inspect next next
179 // transition for another rule.
180 ar1 = new AnnualTimeZoneRule(name, initialRaw, tr.getTo()->getDSTSavings(),
181 dtr, year, AnnualTimeZoneRule::MAX_YEAR);
182
183 if (tr.getTo()->getRawOffset() == initialRaw) {
184 // Get the next next transition
Frank Tang1f164ee2022-11-08 12:31:27 -0800185 avail = getNextTransition(nextTransitionTime, false, tr);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000186 if (avail) {
187 // Check if the next next transition is either DST->STD or STD->DST
188 // and within roughly 1 year from the next transition
189 if (((tr.getFrom()->getDSTSavings() == 0 && tr.getTo()->getDSTSavings() != 0)
190 || (tr.getFrom()->getDSTSavings() != 0 && tr.getTo()->getDSTSavings() == 0))
191 && nextTransitionTime + MILLIS_PER_YEAR > tr.getTime()) {
192
193 // Get local wall time for the next transition time
194 Grego::timeToFields(tr.getTime() + tr.getFrom()->getRawOffset() + tr.getFrom()->getDSTSavings(),
195 year, month, dom, dow, doy, mid);
196 weekInMonth = Grego::dayOfWeekInMonth(year, month, dom);
197 // Generate another DOW rule
198 dtr = new DateTimeRule(month, weekInMonth, dow, mid, DateTimeRule::WALL_TIME);
199 tr.getTo()->getName(name);
200 ar2 = new AnnualTimeZoneRule(name, tr.getTo()->getRawOffset(), tr.getTo()->getDSTSavings(),
201 dtr, year - 1, AnnualTimeZoneRule::MAX_YEAR);
202
203 // Make sure this rule can be applied to the specified date
Frank Tang1f164ee2022-11-08 12:31:27 -0800204 avail = ar2->getPreviousStart(date, tr.getFrom()->getRawOffset(), tr.getFrom()->getDSTSavings(), true, d);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000205 if (!avail || d > date
206 || initialRaw != tr.getTo()->getRawOffset()
207 || initialDst != tr.getTo()->getDSTSavings()) {
208 // We cannot use this rule as the second transition rule
209 delete ar2;
210 ar2 = NULL;
211 }
212 }
213 }
214 }
215 if (ar2 == NULL) {
216 // Try previous transition
Frank Tang1f164ee2022-11-08 12:31:27 -0800217 avail = getPreviousTransition(date, true, tr);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000218 if (avail) {
219 // Check if the previous transition is either DST->STD or STD->DST.
220 // The actual transition time does not matter here.
221 if ((tr.getFrom()->getDSTSavings() == 0 && tr.getTo()->getDSTSavings() != 0)
222 || (tr.getFrom()->getDSTSavings() != 0 && tr.getTo()->getDSTSavings() == 0)) {
223
224 // Generate another DOW rule
225 Grego::timeToFields(tr.getTime() + tr.getFrom()->getRawOffset() + tr.getFrom()->getDSTSavings(),
226 year, month, dom, dow, doy, mid);
227 weekInMonth = Grego::dayOfWeekInMonth(year, month, dom);
228 dtr = new DateTimeRule(month, weekInMonth, dow, mid, DateTimeRule::WALL_TIME);
229 tr.getTo()->getName(name);
230
231 // second rule raw/dst offsets should match raw/dst offsets
232 // at the given time
233 ar2 = new AnnualTimeZoneRule(name, initialRaw, initialDst,
234 dtr, ar1->getStartYear() - 1, AnnualTimeZoneRule::MAX_YEAR);
235
236 // Check if this rule start after the first rule after the specified date
Frank Tang1f164ee2022-11-08 12:31:27 -0800237 avail = ar2->getNextStart(date, tr.getFrom()->getRawOffset(), tr.getFrom()->getDSTSavings(), false, d);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000238 if (!avail || d <= nextTransitionTime) {
239 // We cannot use this rule as the second transition rule
240 delete ar2;
241 ar2 = NULL;
242 }
243 }
244 }
245 }
246 if (ar2 == NULL) {
247 // Cannot find a good pair of AnnualTimeZoneRule
248 delete ar1;
249 ar1 = NULL;
250 } else {
251 // The initial rule should represent the rule before the previous transition
252 ar1->getName(initialName);
253 initialRaw = ar1->getRawOffset();
254 initialDst = ar1->getDSTSavings();
255 }
256 }
257 }
258 else {
259 // Try the previous one
Frank Tang1f164ee2022-11-08 12:31:27 -0800260 avail = getPreviousTransition(date, true, tr);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000261 if (avail) {
262 tr.getTo()->getName(initialName);
263 initialRaw = tr.getTo()->getRawOffset();
264 initialDst = tr.getTo()->getDSTSavings();
265 } else {
266 // No transitions in the past. Just use the current offsets
Frank Tang1f164ee2022-11-08 12:31:27 -0800267 getOffset(date, false, initialRaw, initialDst, status);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000268 if (U_FAILURE(status)) {
269 return;
270 }
271 }
272 }
273 // Set the initial rule
274 initial = new InitialTimeZoneRule(initialName, initialRaw, initialDst);
275
276 // Set the standard and daylight saving rules
277 if (ar1 != NULL && ar2 != NULL) {
278 if (ar1->getDSTSavings() != 0) {
279 dst = ar1;
280 std = ar2;
281 } else {
282 std = ar1;
283 dst = ar2;
284 }
285 }
286}
287
288void
289BasicTimeZone::getTimeZoneRulesAfter(UDate start, InitialTimeZoneRule*& initial,
290 UVector*& transitionRules, UErrorCode& status) const {
291 if (U_FAILURE(status)) {
292 return;
293 }
294
295 const InitialTimeZoneRule *orgini;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000296 TimeZoneTransition tzt;
Frank Tang3e05d9d2021-11-08 14:04:04 -0800297 bool avail;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000298 int32_t ruleCount;
Frank Tang3e05d9d2021-11-08 14:04:04 -0800299 TimeZoneRule *r = nullptr;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000300 UnicodeString name;
301 int32_t i;
302 UDate time, t;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000303 UDate firstStart;
Frank Tang3e05d9d2021-11-08 14:04:04 -0800304 UBool bFinalStd = false, bFinalDst = false;
305
306 initial = nullptr;
307 transitionRules = nullptr;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000308
309 // Original transition rules
310 ruleCount = countTransitionRules(status);
311 if (U_FAILURE(status)) {
312 return;
313 }
Frank Tang3e05d9d2021-11-08 14:04:04 -0800314 LocalPointer<UVector> orgRules(
315 new UVector(uprv_deleteUObject, nullptr, ruleCount, status), status);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000316 if (U_FAILURE(status)) {
317 return;
318 }
Frank Tang3e05d9d2021-11-08 14:04:04 -0800319 LocalMemory<const TimeZoneRule *> orgtrs(
320 static_cast<const TimeZoneRule **>(uprv_malloc(sizeof(TimeZoneRule*)*ruleCount)));
321 if (orgtrs.isNull()) {
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000322 status = U_MEMORY_ALLOCATION_ERROR;
Frank Tang3e05d9d2021-11-08 14:04:04 -0800323 return;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000324 }
Frank Tang3e05d9d2021-11-08 14:04:04 -0800325 getTimeZoneRules(orgini, &orgtrs[0], ruleCount, status);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000326 if (U_FAILURE(status)) {
Frank Tang3e05d9d2021-11-08 14:04:04 -0800327 return;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000328 }
329 for (i = 0; i < ruleCount; i++) {
Frank Tang3e05d9d2021-11-08 14:04:04 -0800330 LocalPointer<TimeZoneRule> lpRule(orgtrs[i]->clone(), status);
331 orgRules->adoptElement(lpRule.orphan(), status);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000332 if (U_FAILURE(status)) {
Frank Tang3e05d9d2021-11-08 14:04:04 -0800333 return;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000334 }
335 }
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000336
Frank Tang1f164ee2022-11-08 12:31:27 -0800337 avail = getPreviousTransition(start, true, tzt);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000338 if (!avail) {
339 // No need to filter out rules only applicable to time before the start
340 initial = orgini->clone();
Frank Tang3e05d9d2021-11-08 14:04:04 -0800341 if (initial == nullptr) {
342 status = U_MEMORY_ALLOCATION_ERROR;
343 return;
344 }
345 transitionRules = orgRules.orphan();
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000346 return;
347 }
348
Frank Tang3e05d9d2021-11-08 14:04:04 -0800349 LocalMemory<bool> done(static_cast<bool *>(uprv_malloc(sizeof(bool)*ruleCount)));
350 if (done.isNull()) {
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000351 status = U_MEMORY_ALLOCATION_ERROR;
Frank Tang3e05d9d2021-11-08 14:04:04 -0800352 return;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000353 }
Frank Tang3e05d9d2021-11-08 14:04:04 -0800354 LocalPointer<UVector> filteredRules(
355 new UVector(uprv_deleteUObject, nullptr, status), status);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000356 if (U_FAILURE(status)) {
Frank Tang3e05d9d2021-11-08 14:04:04 -0800357 return;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000358 }
359
360 // Create initial rule
361 tzt.getTo()->getName(name);
Frank Tang3e05d9d2021-11-08 14:04:04 -0800362 LocalPointer<InitialTimeZoneRule> res_initial(
363 new InitialTimeZoneRule(name, tzt.getTo()->getRawOffset(), tzt.getTo()->getDSTSavings()), status);
364 if (U_FAILURE(status)) {
365 return;
366 }
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000367
368 // Mark rules which does not need to be processed
369 for (i = 0; i < ruleCount; i++) {
370 r = (TimeZoneRule*)orgRules->elementAt(i);
Frank Tang1f164ee2022-11-08 12:31:27 -0800371 avail = r->getNextStart(start, res_initial->getRawOffset(), res_initial->getDSTSavings(), false, time);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000372 done[i] = !avail;
373 }
374
375 time = start;
376 while (!bFinalStd || !bFinalDst) {
Frank Tang1f164ee2022-11-08 12:31:27 -0800377 avail = getNextTransition(time, false, tzt);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000378 if (!avail) {
379 break;
380 }
381 UDate updatedTime = tzt.getTime();
382 if (updatedTime == time) {
383 // Can get here if rules for start & end of daylight time have exactly
384 // the same time.
385 // TODO: fix getNextTransition() to prevent it?
386 status = U_INVALID_STATE_ERROR;
Frank Tang3e05d9d2021-11-08 14:04:04 -0800387 return;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000388 }
389 time = updatedTime;
390
391 const TimeZoneRule *toRule = tzt.getTo();
392 for (i = 0; i < ruleCount; i++) {
393 r = (TimeZoneRule*)orgRules->elementAt(i);
394 if (*r == *toRule) {
395 break;
396 }
397 }
398 if (i >= ruleCount) {
399 // This case should never happen
400 status = U_INVALID_STATE_ERROR;
Frank Tang3e05d9d2021-11-08 14:04:04 -0800401 return;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000402 }
403 if (done[i]) {
404 continue;
405 }
406 const TimeArrayTimeZoneRule *tar = dynamic_cast<const TimeArrayTimeZoneRule *>(toRule);
407 const AnnualTimeZoneRule *ar;
408 if (tar != NULL) {
409 // Get the previous raw offset and DST savings before the very first start time
410 TimeZoneTransition tzt0;
411 t = start;
Frank Tang1f164ee2022-11-08 12:31:27 -0800412 while (true) {
413 avail = getNextTransition(t, false, tzt0);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000414 if (!avail) {
415 break;
416 }
417 if (*(tzt0.getTo()) == *tar) {
418 break;
419 }
420 t = tzt0.getTime();
421 }
422 if (avail) {
423 // Check if the entire start times to be added
424 tar->getFirstStart(tzt.getFrom()->getRawOffset(), tzt.getFrom()->getDSTSavings(), firstStart);
425 if (firstStart > start) {
426 // Just add the rule as is
Frank Tang3e05d9d2021-11-08 14:04:04 -0800427 LocalPointer<TimeArrayTimeZoneRule> lpTar(tar->clone(), status);
428 filteredRules->adoptElement(lpTar.orphan(), status);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000429 if (U_FAILURE(status)) {
Frank Tang3e05d9d2021-11-08 14:04:04 -0800430 return;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000431 }
432 } else {
Frank Tang7e7574b2021-04-13 21:19:13 -0700433 // Collect transitions after the start time
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000434 int32_t startTimes;
435 DateTimeRule::TimeRuleType timeType;
436 int32_t idx;
437
438 startTimes = tar->countStartTimes();
439 timeType = tar->getTimeType();
440 for (idx = 0; idx < startTimes; idx++) {
441 tar->getStartTimeAt(idx, t);
442 if (timeType == DateTimeRule::STANDARD_TIME) {
443 t -= tzt.getFrom()->getRawOffset();
444 }
445 if (timeType == DateTimeRule::WALL_TIME) {
446 t -= tzt.getFrom()->getDSTSavings();
447 }
448 if (t > start) {
449 break;
450 }
451 }
Frank Tang3e05d9d2021-11-08 14:04:04 -0800452 if (U_FAILURE(status)) {
453 return;
454 }
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000455 int32_t asize = startTimes - idx;
456 if (asize > 0) {
Frank Tang3e05d9d2021-11-08 14:04:04 -0800457 LocalMemory<UDate> newTimes(static_cast<UDate *>(uprv_malloc(sizeof(UDate) * asize)));
458 if (newTimes.isNull()) {
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000459 status = U_MEMORY_ALLOCATION_ERROR;
Frank Tang3e05d9d2021-11-08 14:04:04 -0800460 return;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000461 }
462 for (int32_t newidx = 0; newidx < asize; newidx++) {
463 tar->getStartTimeAt(idx + newidx, newTimes[newidx]);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000464 }
465 tar->getName(name);
Frank Tang3e05d9d2021-11-08 14:04:04 -0800466 LocalPointer<TimeArrayTimeZoneRule> newTar(new TimeArrayTimeZoneRule(
467 name, tar->getRawOffset(), tar->getDSTSavings(), &newTimes[0], asize, timeType), status);
468 filteredRules->adoptElement(newTar.orphan(), status);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000469 if (U_FAILURE(status)) {
Frank Tang3e05d9d2021-11-08 14:04:04 -0800470 return;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000471 }
472 }
473 }
474 }
475 } else if ((ar = dynamic_cast<const AnnualTimeZoneRule *>(toRule)) != NULL) {
476 ar->getFirstStart(tzt.getFrom()->getRawOffset(), tzt.getFrom()->getDSTSavings(), firstStart);
477 if (firstStart == tzt.getTime()) {
478 // Just add the rule as is
Frank Tang3e05d9d2021-11-08 14:04:04 -0800479 LocalPointer<AnnualTimeZoneRule> arClone(ar->clone(), status);
480 filteredRules->adoptElement(arClone.orphan(), status);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000481 if (U_FAILURE(status)) {
Frank Tang3e05d9d2021-11-08 14:04:04 -0800482 return;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000483 }
484 } else {
485 // Calculate the transition year
486 int32_t year, month, dom, dow, doy, mid;
487 Grego::timeToFields(tzt.getTime(), year, month, dom, dow, doy, mid);
488 // Re-create the rule
489 ar->getName(name);
Frank Tang3e05d9d2021-11-08 14:04:04 -0800490 LocalPointer<AnnualTimeZoneRule> newAr(new AnnualTimeZoneRule(name, ar->getRawOffset(), ar->getDSTSavings(),
491 *(ar->getRule()), year, ar->getEndYear()), status);
492 filteredRules->adoptElement(newAr.orphan(), status);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000493 if (U_FAILURE(status)) {
Frank Tang3e05d9d2021-11-08 14:04:04 -0800494 return;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000495 }
496 }
497 // check if this is a final rule
498 if (ar->getEndYear() == AnnualTimeZoneRule::MAX_YEAR) {
499 // After bot final standard and dst rules are processed,
500 // exit this while loop.
501 if (ar->getDSTSavings() == 0) {
Frank Tang1f164ee2022-11-08 12:31:27 -0800502 bFinalStd = true;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000503 } else {
Frank Tang1f164ee2022-11-08 12:31:27 -0800504 bFinalDst = true;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000505 }
506 }
507 }
Frank Tang3e05d9d2021-11-08 14:04:04 -0800508 done[i] = true;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000509 }
510
511 // Set the results
Frank Tang3e05d9d2021-11-08 14:04:04 -0800512 initial = res_initial.orphan();
513 transitionRules = filteredRules.orphan();
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000514 return;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000515}
516
517void
Frank Tang7e7574b2021-04-13 21:19:13 -0700518BasicTimeZone::getOffsetFromLocal(UDate /*date*/, UTimeZoneLocalOption /*nonExistingTimeOpt*/,
519 UTimeZoneLocalOption /*duplicatedTimeOpt*/,
520 int32_t& /*rawOffset*/, int32_t& /*dstOffset*/,
521 UErrorCode& status) const {
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000522 if (U_FAILURE(status)) {
523 return;
524 }
525 status = U_UNSUPPORTED_ERROR;
526}
527
Frank Tang7e7574b2021-04-13 21:19:13 -0700528void BasicTimeZone::getOffsetFromLocal(UDate date, int32_t nonExistingTimeOpt, int32_t duplicatedTimeOpt,
529 int32_t& rawOffset, int32_t& dstOffset,
530 UErrorCode& status) const {
531 getOffsetFromLocal(date, (UTimeZoneLocalOption)nonExistingTimeOpt,
532 (UTimeZoneLocalOption)duplicatedTimeOpt, rawOffset, dstOffset, status);
533}
534
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000535U_NAMESPACE_END
536
537#endif /* #if !UCONFIG_NO_FORMATTING */
538
539//eof