2 *******************************************************************************
3 * Copyright (C) 2007-2012, International Business Machines Corporation and
4 * others. All Rights Reserved.
5 *******************************************************************************
8 #include "utypeinfo.h" // for 'typeid' to work
10 #include "unicode/utypes.h"
12 #if !UCONFIG_NO_FORMATTING
14 #include "unicode/tzrule.h"
15 #include "unicode/ucal.h"
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);
33 TimeZoneRule::TimeZoneRule(const UnicodeString
& name
, int32_t rawOffset
, int32_t dstSavings
)
34 : UObject(), fName(name
), fRawOffset(rawOffset
), fDSTSavings(dstSavings
) {
37 TimeZoneRule::TimeZoneRule(const TimeZoneRule
& source
)
38 : UObject(source
), fName(source
.fName
), fRawOffset(source
.fRawOffset
), fDSTSavings(source
.fDSTSavings
) {
41 TimeZoneRule::~TimeZoneRule() {
45 TimeZoneRule::operator=(const TimeZoneRule
& right
) {
48 fRawOffset
= right
.fRawOffset
;
49 fDSTSavings
= right
.fDSTSavings
;
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
));
64 TimeZoneRule::operator!=(const TimeZoneRule
& that
) const {
65 return !operator==(that
);
69 TimeZoneRule::getName(UnicodeString
& name
) const {
75 TimeZoneRule::getRawOffset(void) const {
80 TimeZoneRule::getDSTSavings(void) const {
85 TimeZoneRule::isEquivalentTo(const TimeZoneRule
& other
) const {
86 return ((this == &other
) ||
87 (typeid(*this) == typeid(other
) &&
88 fRawOffset
== other
.fRawOffset
&&
89 fDSTSavings
== other
.fDSTSavings
));
93 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(InitialTimeZoneRule
)
95 InitialTimeZoneRule::InitialTimeZoneRule(const UnicodeString
& name
,
98 : TimeZoneRule(name
, rawOffset
, dstSavings
) {
101 InitialTimeZoneRule::InitialTimeZoneRule(const InitialTimeZoneRule
& source
)
102 : TimeZoneRule(source
) {
105 InitialTimeZoneRule::~InitialTimeZoneRule() {
109 InitialTimeZoneRule::clone(void) const {
110 return new InitialTimeZoneRule(*this);
114 InitialTimeZoneRule::operator=(const InitialTimeZoneRule
& right
) {
115 if (this != &right
) {
116 TimeZoneRule::operator=(right
);
122 InitialTimeZoneRule::operator==(const TimeZoneRule
& that
) const {
123 return ((this == &that
) ||
124 (typeid(*this) == typeid(that
) &&
125 TimeZoneRule::operator==(that
)));
129 InitialTimeZoneRule::operator!=(const TimeZoneRule
& that
) const {
130 return !operator==(that
);
134 InitialTimeZoneRule::isEquivalentTo(const TimeZoneRule
& other
) const {
135 if (this == &other
) {
138 if (typeid(*this) != typeid(other
) || TimeZoneRule::isEquivalentTo(other
) == FALSE
) {
145 InitialTimeZoneRule::getFirstStart(int32_t /*prevRawOffset*/,
146 int32_t /*prevDSTSavings*/,
147 UDate
& /*result*/) const {
152 InitialTimeZoneRule::getFinalStart(int32_t /*prevRawOffset*/,
153 int32_t /*prevDSTSavings*/,
154 UDate
& /*result*/) const {
159 InitialTimeZoneRule::getNextStart(UDate
/*base*/,
160 int32_t /*prevRawOffset*/,
161 int32_t /*prevDSTSavings*/,
163 UDate
& /*result*/) const {
168 InitialTimeZoneRule::getPreviousStart(UDate
/*base*/,
169 int32_t /*prevRawOffset*/,
170 int32_t /*prevDSTSavings*/,
172 UDate
& /*result*/) const {
177 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(AnnualTimeZoneRule
)
179 const int32_t AnnualTimeZoneRule::MAX_YEAR
= 0x7FFFFFFF; /* max signed int32 */
181 AnnualTimeZoneRule::AnnualTimeZoneRule(const UnicodeString
& name
,
184 const DateTimeRule
& dateTimeRule
,
187 : TimeZoneRule(name
, rawOffset
, dstSavings
), fDateTimeRule(new DateTimeRule(dateTimeRule
)),
188 fStartYear(startYear
), fEndYear(endYear
) {
191 AnnualTimeZoneRule::AnnualTimeZoneRule(const UnicodeString
& name
,
194 DateTimeRule
* dateTimeRule
,
197 : TimeZoneRule(name
, rawOffset
, dstSavings
), fDateTimeRule(dateTimeRule
),
198 fStartYear(startYear
), fEndYear(endYear
) {
201 AnnualTimeZoneRule::AnnualTimeZoneRule(const AnnualTimeZoneRule
& source
)
202 : TimeZoneRule(source
), fDateTimeRule(new DateTimeRule(*(source
.fDateTimeRule
))),
203 fStartYear(source
.fStartYear
), fEndYear(source
.fEndYear
) {
206 AnnualTimeZoneRule::~AnnualTimeZoneRule() {
207 delete fDateTimeRule
;
211 AnnualTimeZoneRule::clone(void) const {
212 return new AnnualTimeZoneRule(*this);
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
;
228 AnnualTimeZoneRule::operator==(const TimeZoneRule
& that
) const {
232 if (typeid(*this) != typeid(that
)) {
235 AnnualTimeZoneRule
*atzr
= (AnnualTimeZoneRule
*)&that
;
236 return (*fDateTimeRule
== *(atzr
->fDateTimeRule
) &&
237 fStartYear
== atzr
->fStartYear
&&
238 fEndYear
== atzr
->fEndYear
);
242 AnnualTimeZoneRule::operator!=(const TimeZoneRule
& that
) const {
243 return !operator==(that
);
247 AnnualTimeZoneRule::getRule() const {
248 return fDateTimeRule
;
252 AnnualTimeZoneRule::getStartYear() const {
257 AnnualTimeZoneRule::getEndYear() const {
262 AnnualTimeZoneRule::getStartInYear(int32_t year
,
263 int32_t prevRawOffset
,
264 int32_t prevDSTSavings
,
265 UDate
&result
) const {
266 if (year
< fStartYear
|| year
> fEndYear
) {
270 DateTimeRule::DateRuleType type
= fDateTimeRule
->getDateRuleType();
271 if (type
== DateTimeRule::DOM
) {
272 ruleDay
= Grego::fieldsToDay(year
, fDateTimeRule
->getRuleMonth(), fDateTimeRule
->getRuleDayOfMonth());
275 if (type
== DateTimeRule::DOW
) {
276 // Normalize DOW rule into DOW_GEQ_DOM or DOW_LEQ_DOM
277 int32_t weeks
= fDateTimeRule
->getRuleWeekInMonth();
279 ruleDay
= Grego::fieldsToDay(year
, fDateTimeRule
->getRuleMonth(), 1);
280 ruleDay
+= 7 * (weeks
- 1);
283 ruleDay
= Grego::fieldsToDay(year
, fDateTimeRule
->getRuleMonth(),
284 Grego::monthLength(year
, fDateTimeRule
->getRuleMonth()));
285 ruleDay
+= 7 * (weeks
+ 1);
288 int32_t month
= fDateTimeRule
->getRuleMonth();
289 int32_t dom
= fDateTimeRule
->getRuleDayOfMonth();
290 if (type
== DateTimeRule::DOW_LEQ_DOM
) {
293 if (month
== UCAL_FEBRUARY
&& dom
== 29 && !Grego::isLeapYear(year
)) {
297 ruleDay
= Grego::fieldsToDay(year
, month
, dom
);
299 int32_t dow
= Grego::dayOfWeek(ruleDay
);
300 int32_t delta
= fDateTimeRule
->getRuleDayOfWeek() - dow
;
302 delta
= delta
< 0 ? delta
+ 7 : delta
;
304 delta
= delta
> 0 ? delta
- 7 : delta
;
309 result
= ruleDay
*U_MILLIS_PER_DAY
+ fDateTimeRule
->getRuleMillisInDay();
310 if (fDateTimeRule
->getTimeRuleType() != DateTimeRule::UTC_TIME
) {
311 result
-= prevRawOffset
;
313 if (fDateTimeRule
->getTimeRuleType() == DateTimeRule::WALL_TIME
) {
314 result
-= prevDSTSavings
;
320 AnnualTimeZoneRule::isEquivalentTo(const TimeZoneRule
& other
) const {
321 if (this == &other
) {
324 if (typeid(*this) != typeid(other
) || TimeZoneRule::isEquivalentTo(other
) == FALSE
) {
327 AnnualTimeZoneRule
* that
= (AnnualTimeZoneRule
*)&other
;
328 return (*fDateTimeRule
== *(that
->fDateTimeRule
) &&
329 fStartYear
== that
->fStartYear
&&
330 fEndYear
== that
->fEndYear
);
334 AnnualTimeZoneRule::getFirstStart(int32_t prevRawOffset
,
335 int32_t prevDSTSavings
,
336 UDate
& result
) const {
337 return getStartInYear(fStartYear
, prevRawOffset
, prevDSTSavings
, result
);
341 AnnualTimeZoneRule::getFinalStart(int32_t prevRawOffset
,
342 int32_t prevDSTSavings
,
343 UDate
& result
) const {
344 if (fEndYear
== MAX_YEAR
) {
347 return getStartInYear(fEndYear
, prevRawOffset
, prevDSTSavings
, result
);
351 AnnualTimeZoneRule::getNextStart(UDate base
,
352 int32_t prevRawOffset
,
353 int32_t prevDSTSavings
,
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
);
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
);
375 AnnualTimeZoneRule::getPreviousStart(UDate base
,
376 int32_t prevRawOffset
,
377 int32_t prevDSTSavings
,
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
);
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
);
398 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(TimeArrayTimeZoneRule
)
400 TimeArrayTimeZoneRule::TimeArrayTimeZoneRule(const UnicodeString
& name
,
403 const UDate
* startTimes
,
404 int32_t numStartTimes
,
405 DateTimeRule::TimeRuleType timeRuleType
)
406 : TimeZoneRule(name
, rawOffset
, dstSavings
), fTimeRuleType(timeRuleType
),
408 UErrorCode status
= U_ZERO_ERROR
;
409 initStartTimes(startTimes
, numStartTimes
, status
);
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
);
422 TimeArrayTimeZoneRule::~TimeArrayTimeZoneRule() {
423 if (fStartTimes
!= NULL
&& fStartTimes
!= fLocalStartTimes
) {
424 uprv_free(fStartTimes
);
428 TimeArrayTimeZoneRule
*
429 TimeArrayTimeZoneRule::clone(void) const {
430 return new TimeArrayTimeZoneRule(*this);
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
);
441 fTimeRuleType
= right
.fTimeRuleType
;
447 TimeArrayTimeZoneRule::operator==(const TimeZoneRule
& that
) const {
451 if (typeid(*this) != typeid(that
) || TimeZoneRule::operator==(that
) == FALSE
) {
454 TimeArrayTimeZoneRule
*tatzr
= (TimeArrayTimeZoneRule
*)&that
;
455 if (fTimeRuleType
!= tatzr
->fTimeRuleType
||
456 fNumStartTimes
!= tatzr
->fNumStartTimes
) {
459 // Compare start times
461 for (int32_t i
= 0; i
< fNumStartTimes
; i
++) {
462 if (fStartTimes
[i
] != tatzr
->fStartTimes
[i
]) {
471 TimeArrayTimeZoneRule::operator!=(const TimeZoneRule
& that
) const {
472 return !operator==(that
);
475 DateTimeRule::TimeRuleType
476 TimeArrayTimeZoneRule::getTimeType(void) const {
477 return fTimeRuleType
;
481 TimeArrayTimeZoneRule::getStartTimeAt(int32_t index
, UDate
& result
) const {
482 if (index
>= fNumStartTimes
|| index
< 0) {
485 result
= fStartTimes
[index
];
490 TimeArrayTimeZoneRule::countStartTimes(void) const {
491 return fNumStartTimes
;
495 TimeArrayTimeZoneRule::isEquivalentTo(const TimeZoneRule
& other
) const {
496 if (this == &other
) {
499 if (typeid(*this) != typeid(other
) || TimeZoneRule::isEquivalentTo(other
) == FALSE
) {
502 TimeArrayTimeZoneRule
* that
= (TimeArrayTimeZoneRule
*)&other
;
503 if (fTimeRuleType
!= that
->fTimeRuleType
||
504 fNumStartTimes
!= that
->fNumStartTimes
) {
507 // Compare start times
509 for (int32_t i
= 0; i
< fNumStartTimes
; i
++) {
510 if (fStartTimes
[i
] != that
->fStartTimes
[i
]) {
519 TimeArrayTimeZoneRule::getFirstStart(int32_t prevRawOffset
,
520 int32_t prevDSTSavings
,
521 UDate
& result
) const {
522 if (fNumStartTimes
<= 0 || fStartTimes
== NULL
) {
525 result
= getUTC(fStartTimes
[0], prevRawOffset
, prevDSTSavings
);
530 TimeArrayTimeZoneRule::getFinalStart(int32_t prevRawOffset
,
531 int32_t prevDSTSavings
,
532 UDate
& result
) const {
533 if (fNumStartTimes
<= 0 || fStartTimes
== NULL
) {
536 result
= getUTC(fStartTimes
[fNumStartTimes
- 1], prevRawOffset
, prevDSTSavings
);
541 TimeArrayTimeZoneRule::getNextStart(UDate base
,
542 int32_t prevRawOffset
,
543 int32_t prevDSTSavings
,
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
)) {
554 if (i
== fNumStartTimes
- 1) {
561 TimeArrayTimeZoneRule::getPreviousStart(UDate base
,
562 int32_t prevRawOffset
,
563 int32_t prevDSTSavings
,
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
)) {
578 // ---- private methods ------
581 TimeArrayTimeZoneRule::initStartTimes(const UDate source
[], int32_t size
, UErrorCode
& status
) {
583 if (fStartTimes
!= NULL
&& fStartTimes
!= fLocalStartTimes
) {
584 uprv_free(fStartTimes
);
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
;
595 fStartTimes
= (UDate
*)fLocalStartTimes
;
597 uprv_memcpy(fStartTimes
, source
, sizeof(UDate
)*size
);
598 fNumStartTimes
= size
;
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
);
612 TimeArrayTimeZoneRule::getUTC(UDate time
, int32_t raw
, int32_t dst
) const {
613 if (fTimeRuleType
!= DateTimeRule::UTC_TIME
) {
616 if (fTimeRuleType
== DateTimeRule::WALL_TIME
) {
624 #endif /* #if !UCONFIG_NO_FORMATTING */