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