2 *******************************************************************************
3 * Copyright (C) 2007, International Business Machines Corporation and *
4 * others. All Rights Reserved. *
5 *******************************************************************************
8 #include "unicode/utypes.h"
10 #if !UCONFIG_NO_FORMATTING
12 #include "unicode/tzrule.h"
13 #include "unicode/ucal.h"
19 // UComparator function for sorting start times
20 static int32_t U_CALLCONV
21 compareDates(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);
31 TimeZoneRule::TimeZoneRule(const UnicodeString
& name
, int32_t rawOffset
, int32_t dstSavings
)
32 : UObject(), fName(name
), fRawOffset(rawOffset
), fDSTSavings(dstSavings
) {
35 TimeZoneRule::TimeZoneRule(const TimeZoneRule
& source
)
36 : UObject(source
), fName(source
.fName
), fRawOffset(source
.fRawOffset
), fDSTSavings(source
.fDSTSavings
) {
39 TimeZoneRule::~TimeZoneRule() {
43 TimeZoneRule::operator=(const TimeZoneRule
& right
) {
46 fRawOffset
= right
.fRawOffset
;
47 fDSTSavings
= right
.fDSTSavings
;
53 TimeZoneRule::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
));
62 TimeZoneRule::operator!=(const TimeZoneRule
& that
) const {
63 return !operator==(that
);
67 TimeZoneRule::getName(UnicodeString
& name
) const {
73 TimeZoneRule::getRawOffset(void) const {
78 TimeZoneRule::getDSTSavings(void) const {
83 TimeZoneRule::isEquivalentTo(const TimeZoneRule
& other
) const {
84 return ((this == &other
) ||
85 (getDynamicClassID() == other
.getDynamicClassID() &&
86 fRawOffset
== other
.fRawOffset
&&
87 fDSTSavings
== other
.fDSTSavings
));
91 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(InitialTimeZoneRule
)
93 InitialTimeZoneRule::InitialTimeZoneRule(const UnicodeString
& name
,
96 : TimeZoneRule(name
, rawOffset
, dstSavings
) {
99 InitialTimeZoneRule::InitialTimeZoneRule(const InitialTimeZoneRule
& source
)
100 : TimeZoneRule(source
) {
103 InitialTimeZoneRule::~InitialTimeZoneRule() {
107 InitialTimeZoneRule::clone(void) const {
108 return new InitialTimeZoneRule(*this);
112 InitialTimeZoneRule::operator=(const InitialTimeZoneRule
& right
) {
113 if (this != &right
) {
114 TimeZoneRule::operator=(right
);
120 InitialTimeZoneRule::operator==(const TimeZoneRule
& that
) const {
121 return ((this == &that
) ||
122 (getDynamicClassID() == that
.getDynamicClassID() &&
123 TimeZoneRule::operator==(that
)));
127 InitialTimeZoneRule::operator!=(const TimeZoneRule
& that
) const {
128 return !operator==(that
);
132 InitialTimeZoneRule::isEquivalentTo(const TimeZoneRule
& other
) const {
133 if (this == &other
) {
136 if (getDynamicClassID() != other
.getDynamicClassID() ||
137 TimeZoneRule::isEquivalentTo(other
) == FALSE
) {
144 InitialTimeZoneRule::getFirstStart(int32_t /*prevRawOffset*/,
145 int32_t /*prevDSTSavings*/,
146 UDate
& /*result*/) const {
151 InitialTimeZoneRule::getFinalStart(int32_t /*prevRawOffset*/,
152 int32_t /*prevDSTSavings*/,
153 UDate
& /*result*/) const {
158 InitialTimeZoneRule::getNextStart(const UDate
/*base*/,
159 int32_t /*prevRawOffset*/,
160 int32_t /*prevDSTSavings*/,
162 UDate
& /*result*/) const {
167 InitialTimeZoneRule::getPreviousStart(const UDate
/*base*/,
168 int32_t /*prevRawOffset*/,
169 int32_t /*prevDSTSavings*/,
171 UDate
& /*result*/) const {
176 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(AnnualTimeZoneRule
)
178 const int32_t AnnualTimeZoneRule::MAX_YEAR
= 0x7FFFFFFF; /* max signed int32 */
180 AnnualTimeZoneRule::AnnualTimeZoneRule(const UnicodeString
& name
,
183 const DateTimeRule
& dateTimeRule
,
186 : TimeZoneRule(name
, rawOffset
, dstSavings
), fDateTimeRule(new DateTimeRule(dateTimeRule
)),
187 fStartYear(startYear
), fEndYear(endYear
) {
190 AnnualTimeZoneRule::AnnualTimeZoneRule(const UnicodeString
& name
,
193 DateTimeRule
* dateTimeRule
,
196 : TimeZoneRule(name
, rawOffset
, dstSavings
), fDateTimeRule(dateTimeRule
),
197 fStartYear(startYear
), fEndYear(endYear
) {
200 AnnualTimeZoneRule::AnnualTimeZoneRule(const AnnualTimeZoneRule
& source
)
201 : TimeZoneRule(source
), fDateTimeRule(new DateTimeRule(*(source
.fDateTimeRule
))),
202 fStartYear(source
.fStartYear
), fEndYear(source
.fEndYear
) {
205 AnnualTimeZoneRule::~AnnualTimeZoneRule() {
206 delete fDateTimeRule
;
210 AnnualTimeZoneRule::clone(void) const {
211 return new AnnualTimeZoneRule(*this);
215 AnnualTimeZoneRule::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
;
227 AnnualTimeZoneRule::operator==(const TimeZoneRule
& that
) const {
231 if (getDynamicClassID() != that
.getDynamicClassID()) {
234 AnnualTimeZoneRule
*atzr
= (AnnualTimeZoneRule
*)&that
;
235 return (*fDateTimeRule
== *(atzr
->fDateTimeRule
) &&
236 fStartYear
== atzr
->fStartYear
&&
237 fEndYear
== atzr
->fEndYear
);
241 AnnualTimeZoneRule::operator!=(const TimeZoneRule
& that
) const {
242 return !operator==(that
);
246 AnnualTimeZoneRule::getRule() const {
247 return fDateTimeRule
;
251 AnnualTimeZoneRule::getStartYear() const {
256 AnnualTimeZoneRule::getEndYear() const {
261 AnnualTimeZoneRule::getStartInYear(int32_t year
,
262 int32_t prevRawOffset
,
263 int32_t prevDSTSavings
,
264 UDate
&result
) const {
265 if (year
< fStartYear
|| year
> fEndYear
) {
269 DateTimeRule::DateRuleType type
= fDateTimeRule
->getDateRuleType();
270 if (type
== DateTimeRule::DOM
) {
271 ruleDay
= Grego::fieldsToDay(year
, fDateTimeRule
->getRuleMonth(), fDateTimeRule
->getRuleDayOfMonth());
274 if (type
== DateTimeRule::DOW
) {
275 // Normalize DOW rule into DOW_GEQ_DOM or DOW_LEQ_DOM
276 int32_t weeks
= fDateTimeRule
->getRuleWeekInMonth();
278 ruleDay
= Grego::fieldsToDay(year
, fDateTimeRule
->getRuleMonth(), 1);
279 ruleDay
+= 7 * (weeks
- 1);
282 ruleDay
= Grego::fieldsToDay(year
, fDateTimeRule
->getRuleMonth(),
283 Grego::monthLength(year
, fDateTimeRule
->getRuleMonth()));
284 ruleDay
+= 7 * (weeks
+ 1);
287 int32_t month
= fDateTimeRule
->getRuleMonth();
288 int32_t dom
= fDateTimeRule
->getRuleDayOfMonth();
289 if (type
== DateTimeRule::DOW_LEQ_DOM
) {
292 if (month
== UCAL_FEBRUARY
&& dom
== 29 && !Grego::isLeapYear(year
)) {
296 ruleDay
= Grego::fieldsToDay(year
, month
, dom
);
298 int32_t dow
= Grego::dayOfWeek(ruleDay
);
299 int32_t delta
= fDateTimeRule
->getRuleDayOfWeek() - dow
;
301 delta
= delta
< 0 ? delta
+ 7 : delta
;
303 delta
= delta
> 0 ? delta
- 7 : delta
;
308 result
= ruleDay
*U_MILLIS_PER_DAY
+ fDateTimeRule
->getRuleMillisInDay();
309 if (fDateTimeRule
->getTimeRuleType() != DateTimeRule::UTC_TIME
) {
310 result
-= prevRawOffset
;
312 if (fDateTimeRule
->getTimeRuleType() == DateTimeRule::WALL_TIME
) {
313 result
-= prevDSTSavings
;
319 AnnualTimeZoneRule::isEquivalentTo(const TimeZoneRule
& other
) const {
320 if (this == &other
) {
323 if (getDynamicClassID() != other
.getDynamicClassID() ||
324 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(const 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(const 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 (getDynamicClassID() != that
.getDynamicClassID()
452 || TimeZoneRule::operator==(that
) == FALSE
) {
455 TimeArrayTimeZoneRule
*tatzr
= (TimeArrayTimeZoneRule
*)&that
;
456 if (fTimeRuleType
!= tatzr
->fTimeRuleType
||
457 fNumStartTimes
!= tatzr
->fNumStartTimes
) {
460 // Compare start times
462 for (int32_t i
= 0; i
< fNumStartTimes
; i
++) {
463 if (fStartTimes
[i
] != tatzr
->fStartTimes
[i
]) {
472 TimeArrayTimeZoneRule::operator!=(const TimeZoneRule
& that
) const {
473 return !operator==(that
);
476 DateTimeRule::TimeRuleType
477 TimeArrayTimeZoneRule::getTimeType(void) const {
478 return fTimeRuleType
;
482 TimeArrayTimeZoneRule::getStartTimeAt(int32_t index
, UDate
& result
) const {
483 if (index
>= fNumStartTimes
|| index
< 0) {
486 result
= fStartTimes
[index
];
491 TimeArrayTimeZoneRule::countStartTimes(void) const {
492 return fNumStartTimes
;
496 TimeArrayTimeZoneRule::isEquivalentTo(const TimeZoneRule
& other
) const {
497 if (this == &other
) {
500 if (getDynamicClassID() != other
.getDynamicClassID()
501 || TimeZoneRule::isEquivalentTo(other
) == FALSE
) {
504 TimeArrayTimeZoneRule
* that
= (TimeArrayTimeZoneRule
*)&other
;
505 if (fTimeRuleType
!= that
->fTimeRuleType
||
506 fNumStartTimes
!= that
->fNumStartTimes
) {
509 // Compare start times
511 for (int32_t i
= 0; i
< fNumStartTimes
; i
++) {
512 if (fStartTimes
[i
] != that
->fStartTimes
[i
]) {
521 TimeArrayTimeZoneRule::getFirstStart(int32_t prevRawOffset
,
522 int32_t prevDSTSavings
,
523 UDate
& result
) const {
524 if (fNumStartTimes
<= 0 || fStartTimes
== NULL
) {
527 result
= getUTC(fStartTimes
[0], prevRawOffset
, prevDSTSavings
);
532 TimeArrayTimeZoneRule::getFinalStart(int32_t prevRawOffset
,
533 int32_t prevDSTSavings
,
534 UDate
& result
) const {
535 if (fNumStartTimes
<= 0 || fStartTimes
== NULL
) {
538 result
= getUTC(fStartTimes
[fNumStartTimes
- 1], prevRawOffset
, prevDSTSavings
);
543 TimeArrayTimeZoneRule::getNextStart(const UDate base
,
544 int32_t prevRawOffset
,
545 int32_t prevDSTSavings
,
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
)) {
556 if (i
== fNumStartTimes
- 1) {
563 TimeArrayTimeZoneRule::getPreviousStart(const UDate base
,
564 int32_t prevRawOffset
,
565 int32_t prevDSTSavings
,
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
)) {
580 // ---- private methods ------
583 TimeArrayTimeZoneRule::initStartTimes(const UDate source
[], int32_t size
, UErrorCode
& status
) {
585 if (fStartTimes
!= NULL
&& fStartTimes
!= fLocalStartTimes
) {
586 uprv_free(fStartTimes
);
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
;
597 fStartTimes
= (UDate
*)fLocalStartTimes
;
599 uprv_memcpy(fStartTimes
, source
, sizeof(UDate
)*size
);
600 fNumStartTimes
= size
;
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
);
614 TimeArrayTimeZoneRule::getUTC(UDate time
, int32_t raw
, int32_t dst
) const {
615 if (fTimeRuleType
!= DateTimeRule::UTC_TIME
) {
618 if (fTimeRuleType
== DateTimeRule::WALL_TIME
) {
626 #endif /* #if !UCONFIG_NO_FORMATTING */