]> git.saurik.com Git - apple/icu.git/blob - icuSources/i18n/tzrule.cpp
ICU-511.35.tar.gz
[apple/icu.git] / icuSources / i18n / tzrule.cpp
1 /*
2 *******************************************************************************
3 * Copyright (C) 2007-2012, International Business Machines Corporation and
4 * others. All Rights Reserved.
5 *******************************************************************************
6 */
7
8 #include "utypeinfo.h" // for 'typeid' to work
9
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
20 U_CDECL_BEGIN
21 // UComparator function for sorting start times
22 static int32_t U_CALLCONV
23 compareDates(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 }
29 U_CDECL_END
30
31 U_NAMESPACE_BEGIN
32
33 TimeZoneRule::TimeZoneRule(const UnicodeString& name, int32_t rawOffset, int32_t dstSavings)
34 : UObject(), fName(name), fRawOffset(rawOffset), fDSTSavings(dstSavings) {
35 }
36
37 TimeZoneRule::TimeZoneRule(const TimeZoneRule& source)
38 : UObject(source), fName(source.fName), fRawOffset(source.fRawOffset), fDSTSavings(source.fDSTSavings) {
39 }
40
41 TimeZoneRule::~TimeZoneRule() {
42 }
43
44 TimeZoneRule&
45 TimeZoneRule::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
54 UBool
55 TimeZoneRule::operator==(const TimeZoneRule& that) const {
56 return ((this == &that) ||
57 (typeid(*this) == typeid(that) &&
58 fName == that.fName &&
59 fRawOffset == that.fRawOffset &&
60 fDSTSavings == that.fDSTSavings));
61 }
62
63 UBool
64 TimeZoneRule::operator!=(const TimeZoneRule& that) const {
65 return !operator==(that);
66 }
67
68 UnicodeString&
69 TimeZoneRule::getName(UnicodeString& name) const {
70 name = fName;
71 return name;
72 }
73
74 int32_t
75 TimeZoneRule::getRawOffset(void) const {
76 return fRawOffset;
77 }
78
79 int32_t
80 TimeZoneRule::getDSTSavings(void) const {
81 return fDSTSavings;
82 }
83
84 UBool
85 TimeZoneRule::isEquivalentTo(const TimeZoneRule& other) const {
86 return ((this == &other) ||
87 (typeid(*this) == typeid(other) &&
88 fRawOffset == other.fRawOffset &&
89 fDSTSavings == other.fDSTSavings));
90 }
91
92
93 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(InitialTimeZoneRule)
94
95 InitialTimeZoneRule::InitialTimeZoneRule(const UnicodeString& name,
96 int32_t rawOffset,
97 int32_t dstSavings)
98 : TimeZoneRule(name, rawOffset, dstSavings) {
99 }
100
101 InitialTimeZoneRule::InitialTimeZoneRule(const InitialTimeZoneRule& source)
102 : TimeZoneRule(source) {
103 }
104
105 InitialTimeZoneRule::~InitialTimeZoneRule() {
106 }
107
108 InitialTimeZoneRule*
109 InitialTimeZoneRule::clone(void) const {
110 return new InitialTimeZoneRule(*this);
111 }
112
113 InitialTimeZoneRule&
114 InitialTimeZoneRule::operator=(const InitialTimeZoneRule& right) {
115 if (this != &right) {
116 TimeZoneRule::operator=(right);
117 }
118 return *this;
119 }
120
121 UBool
122 InitialTimeZoneRule::operator==(const TimeZoneRule& that) const {
123 return ((this == &that) ||
124 (typeid(*this) == typeid(that) &&
125 TimeZoneRule::operator==(that)));
126 }
127
128 UBool
129 InitialTimeZoneRule::operator!=(const TimeZoneRule& that) const {
130 return !operator==(that);
131 }
132
133 UBool
134 InitialTimeZoneRule::isEquivalentTo(const TimeZoneRule& other) const {
135 if (this == &other) {
136 return TRUE;
137 }
138 if (typeid(*this) != typeid(other) || TimeZoneRule::isEquivalentTo(other) == FALSE) {
139 return FALSE;
140 }
141 return TRUE;
142 }
143
144 UBool
145 InitialTimeZoneRule::getFirstStart(int32_t /*prevRawOffset*/,
146 int32_t /*prevDSTSavings*/,
147 UDate& /*result*/) const {
148 return FALSE;
149 }
150
151 UBool
152 InitialTimeZoneRule::getFinalStart(int32_t /*prevRawOffset*/,
153 int32_t /*prevDSTSavings*/,
154 UDate& /*result*/) const {
155 return FALSE;
156 }
157
158 UBool
159 InitialTimeZoneRule::getNextStart(UDate /*base*/,
160 int32_t /*prevRawOffset*/,
161 int32_t /*prevDSTSavings*/,
162 UBool /*inclusive*/,
163 UDate& /*result*/) const {
164 return FALSE;
165 }
166
167 UBool
168 InitialTimeZoneRule::getPreviousStart(UDate /*base*/,
169 int32_t /*prevRawOffset*/,
170 int32_t /*prevDSTSavings*/,
171 UBool /*inclusive*/,
172 UDate& /*result*/) const {
173 return FALSE;
174 }
175
176
177 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(AnnualTimeZoneRule)
178
179 const int32_t AnnualTimeZoneRule::MAX_YEAR = 0x7FFFFFFF; /* max signed int32 */
180
181 AnnualTimeZoneRule::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
191 AnnualTimeZoneRule::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
201 AnnualTimeZoneRule::AnnualTimeZoneRule(const AnnualTimeZoneRule& source)
202 : TimeZoneRule(source), fDateTimeRule(new DateTimeRule(*(source.fDateTimeRule))),
203 fStartYear(source.fStartYear), fEndYear(source.fEndYear) {
204 }
205
206 AnnualTimeZoneRule::~AnnualTimeZoneRule() {
207 delete fDateTimeRule;
208 }
209
210 AnnualTimeZoneRule*
211 AnnualTimeZoneRule::clone(void) const {
212 return new AnnualTimeZoneRule(*this);
213 }
214
215 AnnualTimeZoneRule&
216 AnnualTimeZoneRule::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
227 UBool
228 AnnualTimeZoneRule::operator==(const TimeZoneRule& that) const {
229 if (this == &that) {
230 return TRUE;
231 }
232 if (typeid(*this) != typeid(that)) {
233 return FALSE;
234 }
235 AnnualTimeZoneRule *atzr = (AnnualTimeZoneRule*)&that;
236 return (*fDateTimeRule == *(atzr->fDateTimeRule) &&
237 fStartYear == atzr->fStartYear &&
238 fEndYear == atzr->fEndYear);
239 }
240
241 UBool
242 AnnualTimeZoneRule::operator!=(const TimeZoneRule& that) const {
243 return !operator==(that);
244 }
245
246 const DateTimeRule*
247 AnnualTimeZoneRule::getRule() const {
248 return fDateTimeRule;
249 }
250
251 int32_t
252 AnnualTimeZoneRule::getStartYear() const {
253 return fStartYear;
254 }
255
256 int32_t
257 AnnualTimeZoneRule::getEndYear() const {
258 return fEndYear;
259 }
260
261 UBool
262 AnnualTimeZoneRule::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
319 UBool
320 AnnualTimeZoneRule::isEquivalentTo(const TimeZoneRule& other) const {
321 if (this == &other) {
322 return TRUE;
323 }
324 if (typeid(*this) != typeid(other) || TimeZoneRule::isEquivalentTo(other) == FALSE) {
325 return FALSE;
326 }
327 AnnualTimeZoneRule* that = (AnnualTimeZoneRule*)&other;
328 return (*fDateTimeRule == *(that->fDateTimeRule) &&
329 fStartYear == that->fStartYear &&
330 fEndYear == that->fEndYear);
331 }
332
333 UBool
334 AnnualTimeZoneRule::getFirstStart(int32_t prevRawOffset,
335 int32_t prevDSTSavings,
336 UDate& result) const {
337 return getStartInYear(fStartYear, prevRawOffset, prevDSTSavings, result);
338 }
339
340 UBool
341 AnnualTimeZoneRule::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
350 UBool
351 AnnualTimeZoneRule::getNextStart(UDate base,
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
374 UBool
375 AnnualTimeZoneRule::getPreviousStart(UDate base,
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
398 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(TimeArrayTimeZoneRule)
399
400 TimeArrayTimeZoneRule::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
414 TimeArrayTimeZoneRule::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
422 TimeArrayTimeZoneRule::~TimeArrayTimeZoneRule() {
423 if (fStartTimes != NULL && fStartTimes != fLocalStartTimes) {
424 uprv_free(fStartTimes);
425 }
426 }
427
428 TimeArrayTimeZoneRule*
429 TimeArrayTimeZoneRule::clone(void) const {
430 return new TimeArrayTimeZoneRule(*this);
431 }
432
433
434 TimeArrayTimeZoneRule&
435 TimeArrayTimeZoneRule::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
446 UBool
447 TimeArrayTimeZoneRule::operator==(const TimeZoneRule& that) const {
448 if (this == &that) {
449 return TRUE;
450 }
451 if (typeid(*this) != typeid(that) || TimeZoneRule::operator==(that) == FALSE) {
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
470 UBool
471 TimeArrayTimeZoneRule::operator!=(const TimeZoneRule& that) const {
472 return !operator==(that);
473 }
474
475 DateTimeRule::TimeRuleType
476 TimeArrayTimeZoneRule::getTimeType(void) const {
477 return fTimeRuleType;
478 }
479
480 UBool
481 TimeArrayTimeZoneRule::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
489 int32_t
490 TimeArrayTimeZoneRule::countStartTimes(void) const {
491 return fNumStartTimes;
492 }
493
494 UBool
495 TimeArrayTimeZoneRule::isEquivalentTo(const TimeZoneRule& other) const {
496 if (this == &other) {
497 return TRUE;
498 }
499 if (typeid(*this) != typeid(other) || TimeZoneRule::isEquivalentTo(other) == FALSE) {
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
518 UBool
519 TimeArrayTimeZoneRule::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
529 UBool
530 TimeArrayTimeZoneRule::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
540 UBool
541 TimeArrayTimeZoneRule::getNextStart(UDate base,
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
560 UBool
561 TimeArrayTimeZoneRule::getPreviousStart(UDate base,
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
580 UBool
581 TimeArrayTimeZoneRule::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
611 UDate
612 TimeArrayTimeZoneRule::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
622 U_NAMESPACE_END
623
624 #endif /* #if !UCONFIG_NO_FORMATTING */
625
626 //eof
627