]> git.saurik.com Git - apple/icu.git/blame - icuSources/i18n/tzrule.cpp
ICU-400.37.tar.gz
[apple/icu.git] / icuSources / i18n / tzrule.cpp
CommitLineData
46f4442e
A
1/*
2*******************************************************************************
3* Copyright (C) 2007, International Business Machines Corporation and *
4* others. All Rights Reserved. *
5*******************************************************************************
6*/
7
8#include "unicode/utypes.h"
9
10#if !UCONFIG_NO_FORMATTING
11
12#include "unicode/tzrule.h"
13#include "unicode/ucal.h"
14#include "gregoimp.h"
15#include "cmemory.h"
16#include "uarrsort.h"
17
18U_CDECL_BEGIN
19// UComparator function for sorting start times
20static int32_t U_CALLCONV
21compareDates(const void * /*context*/, const void *left, const void *right) {
22 UDate l = *((UDate*)left);
23 UDate r = *((UDate*)right);
24 int32_t res = l < r ? -1 : (l == r ? 0 : 1);
25 return res;
26}
27U_CDECL_END
28
29U_NAMESPACE_BEGIN
30
31TimeZoneRule::TimeZoneRule(const UnicodeString& name, int32_t rawOffset, int32_t dstSavings)
32: UObject(), fName(name), fRawOffset(rawOffset), fDSTSavings(dstSavings) {
33}
34
35TimeZoneRule::TimeZoneRule(const TimeZoneRule& source)
36: UObject(source), fName(source.fName), fRawOffset(source.fRawOffset), fDSTSavings(source.fDSTSavings) {
37}
38
39TimeZoneRule::~TimeZoneRule() {
40}
41
42TimeZoneRule&
43TimeZoneRule::operator=(const TimeZoneRule& right) {
44 if (this != &right) {
45 fName = right.fName;
46 fRawOffset = right.fRawOffset;
47 fDSTSavings = right.fDSTSavings;
48 }
49 return *this;
50}
51
52UBool
53TimeZoneRule::operator==(const TimeZoneRule& that) const {
54 return ((this == &that) ||
55 (getDynamicClassID() == that.getDynamicClassID() &&
56 fName == that.fName &&
57 fRawOffset == that.fRawOffset &&
58 fDSTSavings == that.fDSTSavings));
59}
60
61UBool
62TimeZoneRule::operator!=(const TimeZoneRule& that) const {
63 return !operator==(that);
64}
65
66UnicodeString&
67TimeZoneRule::getName(UnicodeString& name) const {
68 name = fName;
69 return name;
70}
71
72int32_t
73TimeZoneRule::getRawOffset(void) const {
74 return fRawOffset;
75}
76
77int32_t
78TimeZoneRule::getDSTSavings(void) const {
79 return fDSTSavings;
80}
81
82UBool
83TimeZoneRule::isEquivalentTo(const TimeZoneRule& other) const {
84 return ((this == &other) ||
85 (getDynamicClassID() == other.getDynamicClassID() &&
86 fRawOffset == other.fRawOffset &&
87 fDSTSavings == other.fDSTSavings));
88}
89
90
91UOBJECT_DEFINE_RTTI_IMPLEMENTATION(InitialTimeZoneRule)
92
93InitialTimeZoneRule::InitialTimeZoneRule(const UnicodeString& name,
94 int32_t rawOffset,
95 int32_t dstSavings)
96: TimeZoneRule(name, rawOffset, dstSavings) {
97}
98
99InitialTimeZoneRule::InitialTimeZoneRule(const InitialTimeZoneRule& source)
100: TimeZoneRule(source) {
101}
102
103InitialTimeZoneRule::~InitialTimeZoneRule() {
104}
105
106InitialTimeZoneRule*
107InitialTimeZoneRule::clone(void) const {
108 return new InitialTimeZoneRule(*this);
109}
110
111InitialTimeZoneRule&
112InitialTimeZoneRule::operator=(const InitialTimeZoneRule& right) {
113 if (this != &right) {
114 TimeZoneRule::operator=(right);
115 }
116 return *this;
117}
118
119UBool
120InitialTimeZoneRule::operator==(const TimeZoneRule& that) const {
121 return ((this == &that) ||
122 (getDynamicClassID() == that.getDynamicClassID() &&
123 TimeZoneRule::operator==(that)));
124}
125
126UBool
127InitialTimeZoneRule::operator!=(const TimeZoneRule& that) const {
128 return !operator==(that);
129}
130
131UBool
132InitialTimeZoneRule::isEquivalentTo(const TimeZoneRule& other) const {
133 if (this == &other) {
134 return TRUE;
135 }
136 if (getDynamicClassID() != other.getDynamicClassID() ||
137 TimeZoneRule::isEquivalentTo(other) == FALSE) {
138 return FALSE;
139 }
140 return TRUE;
141}
142
143UBool
144InitialTimeZoneRule::getFirstStart(int32_t /*prevRawOffset*/,
145 int32_t /*prevDSTSavings*/,
146 UDate& /*result*/) const {
147 return FALSE;
148}
149
150UBool
151InitialTimeZoneRule::getFinalStart(int32_t /*prevRawOffset*/,
152 int32_t /*prevDSTSavings*/,
153 UDate& /*result*/) const {
154 return FALSE;
155}
156
157UBool
158InitialTimeZoneRule::getNextStart(const UDate /*base*/,
159 int32_t /*prevRawOffset*/,
160 int32_t /*prevDSTSavings*/,
161 UBool /*inclusive*/,
162 UDate& /*result*/) const {
163 return FALSE;
164}
165
166UBool
167InitialTimeZoneRule::getPreviousStart(const UDate /*base*/,
168 int32_t /*prevRawOffset*/,
169 int32_t /*prevDSTSavings*/,
170 UBool /*inclusive*/,
171 UDate& /*result*/) const {
172 return FALSE;
173}
174
175
176UOBJECT_DEFINE_RTTI_IMPLEMENTATION(AnnualTimeZoneRule)
177
178const int32_t AnnualTimeZoneRule::MAX_YEAR = 0x7FFFFFFF; /* max signed int32 */
179
180AnnualTimeZoneRule::AnnualTimeZoneRule(const UnicodeString& name,
181 int32_t rawOffset,
182 int32_t dstSavings,
183 const DateTimeRule& dateTimeRule,
184 int32_t startYear,
185 int32_t endYear)
186: TimeZoneRule(name, rawOffset, dstSavings), fDateTimeRule(new DateTimeRule(dateTimeRule)),
187 fStartYear(startYear), fEndYear(endYear) {
188}
189
190AnnualTimeZoneRule::AnnualTimeZoneRule(const UnicodeString& name,
191 int32_t rawOffset,
192 int32_t dstSavings,
193 DateTimeRule* dateTimeRule,
194 int32_t startYear,
195 int32_t endYear)
196: TimeZoneRule(name, rawOffset, dstSavings), fDateTimeRule(dateTimeRule),
197 fStartYear(startYear), fEndYear(endYear) {
198}
199
200AnnualTimeZoneRule::AnnualTimeZoneRule(const AnnualTimeZoneRule& source)
201: TimeZoneRule(source), fDateTimeRule(new DateTimeRule(*(source.fDateTimeRule))),
202 fStartYear(source.fStartYear), fEndYear(source.fEndYear) {
203}
204
205AnnualTimeZoneRule::~AnnualTimeZoneRule() {
206 delete fDateTimeRule;
207}
208
209AnnualTimeZoneRule*
210AnnualTimeZoneRule::clone(void) const {
211 return new AnnualTimeZoneRule(*this);
212}
213
214AnnualTimeZoneRule&
215AnnualTimeZoneRule::operator=(const AnnualTimeZoneRule& right) {
216 if (this != &right) {
217 TimeZoneRule::operator=(right);
218 delete fDateTimeRule;
219 fDateTimeRule = right.fDateTimeRule->clone();
220 fStartYear = right.fStartYear;
221 fEndYear = right.fEndYear;
222 }
223 return *this;
224}
225
226UBool
227AnnualTimeZoneRule::operator==(const TimeZoneRule& that) const {
228 if (this == &that) {
229 return TRUE;
230 }
231 if (getDynamicClassID() != that.getDynamicClassID()) {
232 return FALSE;
233 }
234 AnnualTimeZoneRule *atzr = (AnnualTimeZoneRule*)&that;
235 return (*fDateTimeRule == *(atzr->fDateTimeRule) &&
236 fStartYear == atzr->fStartYear &&
237 fEndYear == atzr->fEndYear);
238}
239
240UBool
241AnnualTimeZoneRule::operator!=(const TimeZoneRule& that) const {
242 return !operator==(that);
243}
244
245const DateTimeRule*
246AnnualTimeZoneRule::getRule() const {
247 return fDateTimeRule;
248}
249
250int32_t
251AnnualTimeZoneRule::getStartYear() const {
252 return fStartYear;
253}
254
255int32_t
256AnnualTimeZoneRule::getEndYear() const {
257 return fEndYear;
258}
259
260UBool
261AnnualTimeZoneRule::getStartInYear(int32_t year,
262 int32_t prevRawOffset,
263 int32_t prevDSTSavings,
264 UDate &result) const {
265 if (year < fStartYear || year > fEndYear) {
266 return FALSE;
267 }
268 double ruleDay;
269 DateTimeRule::DateRuleType type = fDateTimeRule->getDateRuleType();
270 if (type == DateTimeRule::DOM) {
271 ruleDay = Grego::fieldsToDay(year, fDateTimeRule->getRuleMonth(), fDateTimeRule->getRuleDayOfMonth());
272 } else {
273 UBool after = TRUE;
274 if (type == DateTimeRule::DOW) {
275 // Normalize DOW rule into DOW_GEQ_DOM or DOW_LEQ_DOM
276 int32_t weeks = fDateTimeRule->getRuleWeekInMonth();
277 if (weeks > 0) {
278 ruleDay = Grego::fieldsToDay(year, fDateTimeRule->getRuleMonth(), 1);
279 ruleDay += 7 * (weeks - 1);
280 } else {
281 after = FALSE;
282 ruleDay = Grego::fieldsToDay(year, fDateTimeRule->getRuleMonth(),
283 Grego::monthLength(year, fDateTimeRule->getRuleMonth()));
284 ruleDay += 7 * (weeks + 1);
285 }
286 } else {
287 int32_t month = fDateTimeRule->getRuleMonth();
288 int32_t dom = fDateTimeRule->getRuleDayOfMonth();
289 if (type == DateTimeRule::DOW_LEQ_DOM) {
290 after = FALSE;
291 // Handle Feb <=29
292 if (month == UCAL_FEBRUARY && dom == 29 && !Grego::isLeapYear(year)) {
293 dom--;
294 }
295 }
296 ruleDay = Grego::fieldsToDay(year, month, dom);
297 }
298 int32_t dow = Grego::dayOfWeek(ruleDay);
299 int32_t delta = fDateTimeRule->getRuleDayOfWeek() - dow;
300 if (after) {
301 delta = delta < 0 ? delta + 7 : delta;
302 } else {
303 delta = delta > 0 ? delta - 7 : delta;
304 }
305 ruleDay += delta;
306 }
307
308 result = ruleDay*U_MILLIS_PER_DAY + fDateTimeRule->getRuleMillisInDay();
309 if (fDateTimeRule->getTimeRuleType() != DateTimeRule::UTC_TIME) {
310 result -= prevRawOffset;
311 }
312 if (fDateTimeRule->getTimeRuleType() == DateTimeRule::WALL_TIME) {
313 result -= prevDSTSavings;
314 }
315 return TRUE;
316}
317
318UBool
319AnnualTimeZoneRule::isEquivalentTo(const TimeZoneRule& other) const {
320 if (this == &other) {
321 return TRUE;
322 }
323 if (getDynamicClassID() != other.getDynamicClassID() ||
324 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
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
351AnnualTimeZoneRule::getNextStart(const 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
374UBool
375AnnualTimeZoneRule::getPreviousStart(const 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
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 }
451 if (getDynamicClassID() != that.getDynamicClassID()
452 || TimeZoneRule::operator==(that) == FALSE) {
453 return FALSE;
454 }
455 TimeArrayTimeZoneRule *tatzr = (TimeArrayTimeZoneRule*)&that;
456 if (fTimeRuleType != tatzr->fTimeRuleType ||
457 fNumStartTimes != tatzr->fNumStartTimes) {
458 return FALSE;
459 }
460 // Compare start times
461 UBool res = TRUE;
462 for (int32_t i = 0; i < fNumStartTimes; i++) {
463 if (fStartTimes[i] != tatzr->fStartTimes[i]) {
464 res = FALSE;
465 break;
466 }
467 }
468 return res;
469}
470
471UBool
472TimeArrayTimeZoneRule::operator!=(const TimeZoneRule& that) const {
473 return !operator==(that);
474}
475
476DateTimeRule::TimeRuleType
477TimeArrayTimeZoneRule::getTimeType(void) const {
478 return fTimeRuleType;
479}
480
481UBool
482TimeArrayTimeZoneRule::getStartTimeAt(int32_t index, UDate& result) const {
483 if (index >= fNumStartTimes || index < 0) {
484 return FALSE;
485 }
486 result = fStartTimes[index];
487 return TRUE;
488}
489
490int32_t
491TimeArrayTimeZoneRule::countStartTimes(void) const {
492 return fNumStartTimes;
493}
494
495UBool
496TimeArrayTimeZoneRule::isEquivalentTo(const TimeZoneRule& other) const {
497 if (this == &other) {
498 return TRUE;
499 }
500 if (getDynamicClassID() != other.getDynamicClassID()
501 || 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
520UBool
521TimeArrayTimeZoneRule::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
531UBool
532TimeArrayTimeZoneRule::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
542UBool
543TimeArrayTimeZoneRule::getNextStart(const 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
562UBool
563TimeArrayTimeZoneRule::getPreviousStart(const 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
582UBool
583TimeArrayTimeZoneRule::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
613UDate
614TimeArrayTimeZoneRule::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
624U_NAMESPACE_END
625
626#endif /* #if !UCONFIG_NO_FORMATTING */
627
628//eof
629