]> git.saurik.com Git - apple/icu.git/blob - icuSources/i18n/tzrule.cpp
ICU-62107.0.1.tar.gz
[apple/icu.git] / icuSources / i18n / tzrule.cpp
1 // © 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
3 /*
4 *******************************************************************************
5 * Copyright (C) 2007-2012, International Business Machines Corporation and
6 * others. All Rights Reserved.
7 *******************************************************************************
8 */
9
10 #include "utypeinfo.h" // for 'typeid' to work
11
12 #include "unicode/utypes.h"
13
14 #if !UCONFIG_NO_FORMATTING
15
16 #include "unicode/tzrule.h"
17 #include "unicode/ucal.h"
18 #include "gregoimp.h"
19 #include "cmemory.h"
20 #include "uarrsort.h"
21
22 U_CDECL_BEGIN
23 // UComparator function for sorting start times
24 static int32_t U_CALLCONV
25 compareDates(const void * /*context*/, const void *left, const void *right) {
26 UDate l = *((UDate*)left);
27 UDate r = *((UDate*)right);
28 int32_t res = l < r ? -1 : (l == r ? 0 : 1);
29 return res;
30 }
31 U_CDECL_END
32
33 U_NAMESPACE_BEGIN
34
35 TimeZoneRule::TimeZoneRule(const UnicodeString& name, int32_t rawOffset, int32_t dstSavings)
36 : UObject(), fName(name), fRawOffset(rawOffset), fDSTSavings(dstSavings) {
37 }
38
39 TimeZoneRule::TimeZoneRule(const TimeZoneRule& source)
40 : UObject(source), fName(source.fName), fRawOffset(source.fRawOffset), fDSTSavings(source.fDSTSavings) {
41 }
42
43 TimeZoneRule::~TimeZoneRule() {
44 }
45
46 TimeZoneRule&
47 TimeZoneRule::operator=(const TimeZoneRule& right) {
48 if (this != &right) {
49 fName = right.fName;
50 fRawOffset = right.fRawOffset;
51 fDSTSavings = right.fDSTSavings;
52 }
53 return *this;
54 }
55
56 UBool
57 TimeZoneRule::operator==(const TimeZoneRule& that) const {
58 return ((this == &that) ||
59 (typeid(*this) == typeid(that) &&
60 fName == that.fName &&
61 fRawOffset == that.fRawOffset &&
62 fDSTSavings == that.fDSTSavings));
63 }
64
65 UBool
66 TimeZoneRule::operator!=(const TimeZoneRule& that) const {
67 return !operator==(that);
68 }
69
70 UnicodeString&
71 TimeZoneRule::getName(UnicodeString& name) const {
72 name = fName;
73 return name;
74 }
75
76 int32_t
77 TimeZoneRule::getRawOffset(void) const {
78 return fRawOffset;
79 }
80
81 int32_t
82 TimeZoneRule::getDSTSavings(void) const {
83 return fDSTSavings;
84 }
85
86 UBool
87 TimeZoneRule::isEquivalentTo(const TimeZoneRule& other) const {
88 return ((this == &other) ||
89 (typeid(*this) == typeid(other) &&
90 fRawOffset == other.fRawOffset &&
91 fDSTSavings == other.fDSTSavings));
92 }
93
94
95 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(InitialTimeZoneRule)
96
97 InitialTimeZoneRule::InitialTimeZoneRule(const UnicodeString& name,
98 int32_t rawOffset,
99 int32_t dstSavings)
100 : TimeZoneRule(name, rawOffset, dstSavings) {
101 }
102
103 InitialTimeZoneRule::InitialTimeZoneRule(const InitialTimeZoneRule& source)
104 : TimeZoneRule(source) {
105 }
106
107 InitialTimeZoneRule::~InitialTimeZoneRule() {
108 }
109
110 InitialTimeZoneRule*
111 InitialTimeZoneRule::clone(void) const {
112 return new InitialTimeZoneRule(*this);
113 }
114
115 InitialTimeZoneRule&
116 InitialTimeZoneRule::operator=(const InitialTimeZoneRule& right) {
117 if (this != &right) {
118 TimeZoneRule::operator=(right);
119 }
120 return *this;
121 }
122
123 UBool
124 InitialTimeZoneRule::operator==(const TimeZoneRule& that) const {
125 return ((this == &that) ||
126 (typeid(*this) == typeid(that) &&
127 TimeZoneRule::operator==(that)));
128 }
129
130 UBool
131 InitialTimeZoneRule::operator!=(const TimeZoneRule& that) const {
132 return !operator==(that);
133 }
134
135 UBool
136 InitialTimeZoneRule::isEquivalentTo(const TimeZoneRule& other) const {
137 if (this == &other) {
138 return TRUE;
139 }
140 if (typeid(*this) != typeid(other) || TimeZoneRule::isEquivalentTo(other) == FALSE) {
141 return FALSE;
142 }
143 return TRUE;
144 }
145
146 UBool
147 InitialTimeZoneRule::getFirstStart(int32_t /*prevRawOffset*/,
148 int32_t /*prevDSTSavings*/,
149 UDate& /*result*/) const {
150 return FALSE;
151 }
152
153 UBool
154 InitialTimeZoneRule::getFinalStart(int32_t /*prevRawOffset*/,
155 int32_t /*prevDSTSavings*/,
156 UDate& /*result*/) const {
157 return FALSE;
158 }
159
160 UBool
161 InitialTimeZoneRule::getNextStart(UDate /*base*/,
162 int32_t /*prevRawOffset*/,
163 int32_t /*prevDSTSavings*/,
164 UBool /*inclusive*/,
165 UDate& /*result*/) const {
166 return FALSE;
167 }
168
169 UBool
170 InitialTimeZoneRule::getPreviousStart(UDate /*base*/,
171 int32_t /*prevRawOffset*/,
172 int32_t /*prevDSTSavings*/,
173 UBool /*inclusive*/,
174 UDate& /*result*/) const {
175 return FALSE;
176 }
177
178
179 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(AnnualTimeZoneRule)
180
181 const int32_t AnnualTimeZoneRule::MAX_YEAR = 0x7FFFFFFF; /* max signed int32 */
182
183 AnnualTimeZoneRule::AnnualTimeZoneRule(const UnicodeString& name,
184 int32_t rawOffset,
185 int32_t dstSavings,
186 const DateTimeRule& dateTimeRule,
187 int32_t startYear,
188 int32_t endYear)
189 : TimeZoneRule(name, rawOffset, dstSavings), fDateTimeRule(new DateTimeRule(dateTimeRule)),
190 fStartYear(startYear), fEndYear(endYear) {
191 }
192
193 AnnualTimeZoneRule::AnnualTimeZoneRule(const UnicodeString& name,
194 int32_t rawOffset,
195 int32_t dstSavings,
196 DateTimeRule* dateTimeRule,
197 int32_t startYear,
198 int32_t endYear)
199 : TimeZoneRule(name, rawOffset, dstSavings), fDateTimeRule(dateTimeRule),
200 fStartYear(startYear), fEndYear(endYear) {
201 }
202
203 AnnualTimeZoneRule::AnnualTimeZoneRule(const AnnualTimeZoneRule& source)
204 : TimeZoneRule(source), fDateTimeRule(new DateTimeRule(*(source.fDateTimeRule))),
205 fStartYear(source.fStartYear), fEndYear(source.fEndYear) {
206 }
207
208 AnnualTimeZoneRule::~AnnualTimeZoneRule() {
209 delete fDateTimeRule;
210 }
211
212 AnnualTimeZoneRule*
213 AnnualTimeZoneRule::clone(void) const {
214 return new AnnualTimeZoneRule(*this);
215 }
216
217 AnnualTimeZoneRule&
218 AnnualTimeZoneRule::operator=(const AnnualTimeZoneRule& right) {
219 if (this != &right) {
220 TimeZoneRule::operator=(right);
221 delete fDateTimeRule;
222 fDateTimeRule = right.fDateTimeRule->clone();
223 fStartYear = right.fStartYear;
224 fEndYear = right.fEndYear;
225 }
226 return *this;
227 }
228
229 UBool
230 AnnualTimeZoneRule::operator==(const TimeZoneRule& that) const {
231 if (this == &that) {
232 return TRUE;
233 }
234 if (typeid(*this) != typeid(that)) {
235 return FALSE;
236 }
237 AnnualTimeZoneRule *atzr = (AnnualTimeZoneRule*)&that;
238 return (*fDateTimeRule == *(atzr->fDateTimeRule) &&
239 fStartYear == atzr->fStartYear &&
240 fEndYear == atzr->fEndYear);
241 }
242
243 UBool
244 AnnualTimeZoneRule::operator!=(const TimeZoneRule& that) const {
245 return !operator==(that);
246 }
247
248 const DateTimeRule*
249 AnnualTimeZoneRule::getRule() const {
250 return fDateTimeRule;
251 }
252
253 int32_t
254 AnnualTimeZoneRule::getStartYear() const {
255 return fStartYear;
256 }
257
258 int32_t
259 AnnualTimeZoneRule::getEndYear() const {
260 return fEndYear;
261 }
262
263 UBool
264 AnnualTimeZoneRule::getStartInYear(int32_t year,
265 int32_t prevRawOffset,
266 int32_t prevDSTSavings,
267 UDate &result) const {
268 if (year < fStartYear || year > fEndYear) {
269 return FALSE;
270 }
271 double ruleDay;
272 DateTimeRule::DateRuleType type = fDateTimeRule->getDateRuleType();
273 if (type == DateTimeRule::DOM) {
274 ruleDay = Grego::fieldsToDay(year, fDateTimeRule->getRuleMonth(), fDateTimeRule->getRuleDayOfMonth());
275 } else {
276 UBool after = TRUE;
277 if (type == DateTimeRule::DOW) {
278 // Normalize DOW rule into DOW_GEQ_DOM or DOW_LEQ_DOM
279 int32_t weeks = fDateTimeRule->getRuleWeekInMonth();
280 if (weeks > 0) {
281 ruleDay = Grego::fieldsToDay(year, fDateTimeRule->getRuleMonth(), 1);
282 ruleDay += 7 * (weeks - 1);
283 } else {
284 after = FALSE;
285 ruleDay = Grego::fieldsToDay(year, fDateTimeRule->getRuleMonth(),
286 Grego::monthLength(year, fDateTimeRule->getRuleMonth()));
287 ruleDay += 7 * (weeks + 1);
288 }
289 } else {
290 int32_t month = fDateTimeRule->getRuleMonth();
291 int32_t dom = fDateTimeRule->getRuleDayOfMonth();
292 if (type == DateTimeRule::DOW_LEQ_DOM) {
293 after = FALSE;
294 // Handle Feb <=29
295 if (month == UCAL_FEBRUARY && dom == 29 && !Grego::isLeapYear(year)) {
296 dom--;
297 }
298 }
299 ruleDay = Grego::fieldsToDay(year, month, dom);
300 }
301 int32_t dow = Grego::dayOfWeek(ruleDay);
302 int32_t delta = fDateTimeRule->getRuleDayOfWeek() - dow;
303 if (after) {
304 delta = delta < 0 ? delta + 7 : delta;
305 } else {
306 delta = delta > 0 ? delta - 7 : delta;
307 }
308 ruleDay += delta;
309 }
310
311 result = ruleDay*U_MILLIS_PER_DAY + fDateTimeRule->getRuleMillisInDay();
312 if (fDateTimeRule->getTimeRuleType() != DateTimeRule::UTC_TIME) {
313 result -= prevRawOffset;
314 }
315 if (fDateTimeRule->getTimeRuleType() == DateTimeRule::WALL_TIME) {
316 result -= prevDSTSavings;
317 }
318 return TRUE;
319 }
320
321 UBool
322 AnnualTimeZoneRule::isEquivalentTo(const TimeZoneRule& other) const {
323 if (this == &other) {
324 return TRUE;
325 }
326 if (typeid(*this) != typeid(other) || TimeZoneRule::isEquivalentTo(other) == FALSE) {
327 return FALSE;
328 }
329 AnnualTimeZoneRule* that = (AnnualTimeZoneRule*)&other;
330 return (*fDateTimeRule == *(that->fDateTimeRule) &&
331 fStartYear == that->fStartYear &&
332 fEndYear == that->fEndYear);
333 }
334
335 UBool
336 AnnualTimeZoneRule::getFirstStart(int32_t prevRawOffset,
337 int32_t prevDSTSavings,
338 UDate& result) const {
339 return getStartInYear(fStartYear, prevRawOffset, prevDSTSavings, result);
340 }
341
342 UBool
343 AnnualTimeZoneRule::getFinalStart(int32_t prevRawOffset,
344 int32_t prevDSTSavings,
345 UDate& result) const {
346 if (fEndYear == MAX_YEAR) {
347 return FALSE;
348 }
349 return getStartInYear(fEndYear, prevRawOffset, prevDSTSavings, result);
350 }
351
352 UBool
353 AnnualTimeZoneRule::getNextStart(UDate base,
354 int32_t prevRawOffset,
355 int32_t prevDSTSavings,
356 UBool inclusive,
357 UDate& result) const {
358 int32_t year, month, dom, dow, doy, mid;
359 Grego::timeToFields(base, year, month, dom, dow, doy, mid);
360 if (year < fStartYear) {
361 return getFirstStart(prevRawOffset, prevDSTSavings, result);
362 }
363 UDate tmp;
364 if (getStartInYear(year, prevRawOffset, prevDSTSavings, tmp)) {
365 if (tmp < base || (!inclusive && (tmp == base))) {
366 // Return the next one
367 return getStartInYear(year + 1, prevRawOffset, prevDSTSavings, result);
368 } else {
369 result = tmp;
370 return TRUE;
371 }
372 }
373 return FALSE;
374 }
375
376 UBool
377 AnnualTimeZoneRule::getPreviousStart(UDate base,
378 int32_t prevRawOffset,
379 int32_t prevDSTSavings,
380 UBool inclusive,
381 UDate& result) const {
382 int32_t year, month, dom, dow, doy, mid;
383 Grego::timeToFields(base, year, month, dom, dow, doy, mid);
384 if (year > fEndYear) {
385 return getFinalStart(prevRawOffset, prevDSTSavings, result);
386 }
387 UDate tmp;
388 if (getStartInYear(year, prevRawOffset, prevDSTSavings, tmp)) {
389 if (tmp > base || (!inclusive && (tmp == base))) {
390 // Return the previous one
391 return getStartInYear(year - 1, prevRawOffset, prevDSTSavings, result);
392 } else {
393 result = tmp;
394 return TRUE;
395 }
396 }
397 return FALSE;
398 }
399
400 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(TimeArrayTimeZoneRule)
401
402 TimeArrayTimeZoneRule::TimeArrayTimeZoneRule(const UnicodeString& name,
403 int32_t rawOffset,
404 int32_t dstSavings,
405 const UDate* startTimes,
406 int32_t numStartTimes,
407 DateTimeRule::TimeRuleType timeRuleType)
408 : TimeZoneRule(name, rawOffset, dstSavings), fTimeRuleType(timeRuleType),
409 fStartTimes(NULL) {
410 UErrorCode status = U_ZERO_ERROR;
411 initStartTimes(startTimes, numStartTimes, status);
412 //TODO - status?
413 }
414
415
416 TimeArrayTimeZoneRule::TimeArrayTimeZoneRule(const TimeArrayTimeZoneRule& source)
417 : TimeZoneRule(source), fTimeRuleType(source.fTimeRuleType), fStartTimes(NULL) {
418 UErrorCode status = U_ZERO_ERROR;
419 initStartTimes(source.fStartTimes, source.fNumStartTimes, status);
420 //TODO - status?
421 }
422
423
424 TimeArrayTimeZoneRule::~TimeArrayTimeZoneRule() {
425 if (fStartTimes != NULL && fStartTimes != fLocalStartTimes) {
426 uprv_free(fStartTimes);
427 }
428 }
429
430 TimeArrayTimeZoneRule*
431 TimeArrayTimeZoneRule::clone(void) const {
432 return new TimeArrayTimeZoneRule(*this);
433 }
434
435
436 TimeArrayTimeZoneRule&
437 TimeArrayTimeZoneRule::operator=(const TimeArrayTimeZoneRule& right) {
438 if (this != &right) {
439 TimeZoneRule::operator=(right);
440 UErrorCode status = U_ZERO_ERROR;
441 initStartTimes(right.fStartTimes, right.fNumStartTimes, status);
442 //TODO - status?
443 fTimeRuleType = right.fTimeRuleType;
444 }
445 return *this;
446 }
447
448 UBool
449 TimeArrayTimeZoneRule::operator==(const TimeZoneRule& that) const {
450 if (this == &that) {
451 return TRUE;
452 }
453 if (typeid(*this) != typeid(that) || TimeZoneRule::operator==(that) == FALSE) {
454 return FALSE;
455 }
456 TimeArrayTimeZoneRule *tatzr = (TimeArrayTimeZoneRule*)&that;
457 if (fTimeRuleType != tatzr->fTimeRuleType ||
458 fNumStartTimes != tatzr->fNumStartTimes) {
459 return FALSE;
460 }
461 // Compare start times
462 UBool res = TRUE;
463 for (int32_t i = 0; i < fNumStartTimes; i++) {
464 if (fStartTimes[i] != tatzr->fStartTimes[i]) {
465 res = FALSE;
466 break;
467 }
468 }
469 return res;
470 }
471
472 UBool
473 TimeArrayTimeZoneRule::operator!=(const TimeZoneRule& that) const {
474 return !operator==(that);
475 }
476
477 DateTimeRule::TimeRuleType
478 TimeArrayTimeZoneRule::getTimeType(void) const {
479 return fTimeRuleType;
480 }
481
482 UBool
483 TimeArrayTimeZoneRule::getStartTimeAt(int32_t index, UDate& result) const {
484 if (index >= fNumStartTimes || index < 0) {
485 return FALSE;
486 }
487 result = fStartTimes[index];
488 return TRUE;
489 }
490
491 int32_t
492 TimeArrayTimeZoneRule::countStartTimes(void) const {
493 return fNumStartTimes;
494 }
495
496 UBool
497 TimeArrayTimeZoneRule::isEquivalentTo(const TimeZoneRule& other) const {
498 if (this == &other) {
499 return TRUE;
500 }
501 if (typeid(*this) != typeid(other) || TimeZoneRule::isEquivalentTo(other) == FALSE) {
502 return FALSE;
503 }
504 TimeArrayTimeZoneRule* that = (TimeArrayTimeZoneRule*)&other;
505 if (fTimeRuleType != that->fTimeRuleType ||
506 fNumStartTimes != that->fNumStartTimes) {
507 return FALSE;
508 }
509 // Compare start times
510 UBool res = TRUE;
511 for (int32_t i = 0; i < fNumStartTimes; i++) {
512 if (fStartTimes[i] != that->fStartTimes[i]) {
513 res = FALSE;
514 break;
515 }
516 }
517 return res;
518 }
519
520 UBool
521 TimeArrayTimeZoneRule::getFirstStart(int32_t prevRawOffset,
522 int32_t prevDSTSavings,
523 UDate& result) const {
524 if (fNumStartTimes <= 0 || fStartTimes == NULL) {
525 return FALSE;
526 }
527 result = getUTC(fStartTimes[0], prevRawOffset, prevDSTSavings);
528 return TRUE;
529 }
530
531 UBool
532 TimeArrayTimeZoneRule::getFinalStart(int32_t prevRawOffset,
533 int32_t prevDSTSavings,
534 UDate& result) const {
535 if (fNumStartTimes <= 0 || fStartTimes == NULL) {
536 return FALSE;
537 }
538 result = getUTC(fStartTimes[fNumStartTimes - 1], prevRawOffset, prevDSTSavings);
539 return TRUE;
540 }
541
542 UBool
543 TimeArrayTimeZoneRule::getNextStart(UDate base,
544 int32_t prevRawOffset,
545 int32_t prevDSTSavings,
546 UBool inclusive,
547 UDate& result) const {
548 int32_t i = fNumStartTimes - 1;
549 for (; i >= 0; i--) {
550 UDate time = getUTC(fStartTimes[i], prevRawOffset, prevDSTSavings);
551 if (time < base || (!inclusive && time == base)) {
552 break;
553 }
554 result = time;
555 }
556 if (i == fNumStartTimes - 1) {
557 return FALSE;
558 }
559 return TRUE;
560 }
561
562 UBool
563 TimeArrayTimeZoneRule::getPreviousStart(UDate base,
564 int32_t prevRawOffset,
565 int32_t prevDSTSavings,
566 UBool inclusive,
567 UDate& result) const {
568 int32_t i = fNumStartTimes - 1;
569 for (; i >= 0; i--) {
570 UDate time = getUTC(fStartTimes[i], prevRawOffset, prevDSTSavings);
571 if (time < base || (inclusive && time == base)) {
572 result = time;
573 return TRUE;
574 }
575 }
576 return FALSE;
577 }
578
579
580 // ---- private methods ------
581
582 UBool
583 TimeArrayTimeZoneRule::initStartTimes(const UDate source[], int32_t size, UErrorCode& status) {
584 // Free old array
585 if (fStartTimes != NULL && fStartTimes != fLocalStartTimes) {
586 uprv_free(fStartTimes);
587 }
588 // Allocate new one if needed
589 if (size > TIMEARRAY_STACK_BUFFER_SIZE) {
590 fStartTimes = (UDate*)uprv_malloc(sizeof(UDate)*size);
591 if (fStartTimes == NULL) {
592 status = U_MEMORY_ALLOCATION_ERROR;
593 fNumStartTimes = 0;
594 return FALSE;
595 }
596 } else {
597 fStartTimes = (UDate*)fLocalStartTimes;
598 }
599 uprv_memcpy(fStartTimes, source, sizeof(UDate)*size);
600 fNumStartTimes = size;
601 // Sort dates
602 uprv_sortArray(fStartTimes, fNumStartTimes, (int32_t)sizeof(UDate), compareDates, NULL, TRUE, &status);
603 if (U_FAILURE(status)) {
604 if (fStartTimes != NULL && fStartTimes != fLocalStartTimes) {
605 uprv_free(fStartTimes);
606 }
607 fNumStartTimes = 0;
608 return FALSE;
609 }
610 return TRUE;
611 }
612
613 UDate
614 TimeArrayTimeZoneRule::getUTC(UDate time, int32_t raw, int32_t dst) const {
615 if (fTimeRuleType != DateTimeRule::UTC_TIME) {
616 time -= raw;
617 }
618 if (fTimeRuleType == DateTimeRule::WALL_TIME) {
619 time -= dst;
620 }
621 return time;
622 }
623
624 U_NAMESPACE_END
625
626 #endif /* #if !UCONFIG_NO_FORMATTING */
627
628 //eof
629