2 *******************************************************************************
3 * Copyright (C) 2007-2008, International Business Machines Corporation and *
4 * others. All Rights Reserved. *
5 *******************************************************************************
8 #include "unicode/utypes.h"
10 #if !UCONFIG_NO_FORMATTING
12 #include "unicode/rbtz.h"
13 #include "unicode/gregocal.h"
21 * A struct representing a time zone transition
29 static UBool
compareRules(UVector
* rules1
, UVector
* rules2
) {
30 if (rules1
== NULL
&& rules2
== NULL
) {
32 } else if (rules1
== NULL
|| rules2
== NULL
) {
35 int32_t size
= rules1
->size();
36 if (size
!= rules2
->size()) {
39 for (int32_t i
= 0; i
< size
; i
++) {
40 TimeZoneRule
*r1
= (TimeZoneRule
*)rules1
->elementAt(i
);
41 TimeZoneRule
*r2
= (TimeZoneRule
*)rules2
->elementAt(i
);
49 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(RuleBasedTimeZone
)
51 RuleBasedTimeZone::RuleBasedTimeZone(const UnicodeString
& id
, InitialTimeZoneRule
* initialRule
)
52 : BasicTimeZone(id
), fInitialRule(initialRule
), fHistoricRules(NULL
), fFinalRules(NULL
),
53 fHistoricTransitions(NULL
), fUpToDate(FALSE
) {
56 RuleBasedTimeZone::RuleBasedTimeZone(const RuleBasedTimeZone
& source
)
57 : BasicTimeZone(source
), fInitialRule(source
.fInitialRule
->clone()),
58 fHistoricTransitions(NULL
), fUpToDate(FALSE
) {
59 fHistoricRules
= copyRules(source
.fHistoricRules
);
60 fFinalRules
= copyRules(source
.fFinalRules
);
61 if (source
.fUpToDate
) {
62 UErrorCode status
= U_ZERO_ERROR
;
67 RuleBasedTimeZone::~RuleBasedTimeZone() {
73 RuleBasedTimeZone::operator=(const RuleBasedTimeZone
& right
) {
75 BasicTimeZone::operator=(right
);
77 fInitialRule
= right
.fInitialRule
->clone();
78 fHistoricRules
= copyRules(right
.fHistoricRules
);
79 fFinalRules
= copyRules(right
.fFinalRules
);
87 RuleBasedTimeZone::operator==(const TimeZone
& that
) const {
91 if (getDynamicClassID() != that
.getDynamicClassID()
92 || BasicTimeZone::operator==(that
) == FALSE
) {
95 RuleBasedTimeZone
*rbtz
= (RuleBasedTimeZone
*)&that
;
96 if (*fInitialRule
!= *(rbtz
->fInitialRule
)) {
99 if (compareRules(fHistoricRules
, rbtz
->fHistoricRules
)
100 && compareRules(fFinalRules
, rbtz
->fFinalRules
)) {
107 RuleBasedTimeZone::operator!=(const TimeZone
& that
) const {
108 return !operator==(that
);
112 RuleBasedTimeZone::addTransitionRule(TimeZoneRule
* rule
, UErrorCode
& status
) {
113 if (U_FAILURE(status
)) {
116 if (rule
->getDynamicClassID() == AnnualTimeZoneRule::getStaticClassID()
117 && ((AnnualTimeZoneRule
*)rule
)->getEndYear() == AnnualTimeZoneRule::MAX_YEAR
) {
119 if (fFinalRules
== NULL
) {
120 fFinalRules
= new UVector(status
);
121 if (U_FAILURE(status
)) {
124 } else if (fFinalRules
->size() >= 2) {
125 // Cannot handle more than two final rules
126 status
= U_INVALID_STATE_ERROR
;
129 fFinalRules
->addElement((void*)rule
, status
);
132 if (fHistoricRules
== NULL
) {
133 fHistoricRules
= new UVector(status
);
134 if (U_FAILURE(status
)) {
138 fHistoricRules
->addElement((void*)rule
, status
);
140 // Mark dirty, so transitions are recalculated at next complete() call
145 RuleBasedTimeZone::complete(UErrorCode
& status
) {
146 if (U_FAILURE(status
)) {
152 // Make sure either no final rules or a pair of AnnualTimeZoneRules
154 if (fFinalRules
!= NULL
&& fFinalRules
->size() != 2) {
155 status
= U_INVALID_STATE_ERROR
;
160 // Create a TimezoneTransition and add to the list
161 if (fHistoricRules
!= NULL
|| fFinalRules
!= NULL
) {
162 TimeZoneRule
*curRule
= fInitialRule
;
163 UDate lastTransitionTime
= MIN_MILLIS
;
165 // Build the transition array which represents historical time zone
167 if (fHistoricRules
!= NULL
&& fHistoricRules
->size() > 0) {
169 int32_t historicCount
= fHistoricRules
->size();
170 done
= (UBool
*)uprv_malloc(sizeof(UBool
) * historicCount
);
172 status
= U_MEMORY_ALLOCATION_ERROR
;
175 for (i
= 0; i
< historicCount
; i
++) {
179 int32_t curStdOffset
= curRule
->getRawOffset();
180 int32_t curDstSavings
= curRule
->getDSTSavings();
181 UDate nextTransitionTime
= MAX_MILLIS
;
182 TimeZoneRule
*nextRule
= NULL
;
183 TimeZoneRule
*r
= NULL
;
186 UnicodeString curName
, name
;
187 curRule
->getName(curName
);
189 for (i
= 0; i
< historicCount
; i
++) {
193 r
= (TimeZoneRule
*)fHistoricRules
->elementAt(i
);
194 avail
= r
->getNextStart(lastTransitionTime
, curStdOffset
, curDstSavings
, false, tt
);
196 // No more transitions from this rule - skip this rule next time
200 if (*r
== *curRule
||
201 (name
== curName
&& r
->getRawOffset() == curRule
->getRawOffset()
202 && r
->getDSTSavings() == curRule
->getDSTSavings())) {
205 if (tt
< nextTransitionTime
) {
206 nextTransitionTime
= tt
;
212 if (nextRule
== NULL
) {
213 // Check if all historic rules are done
214 UBool bDoneAll
= TRUE
;
215 for (int32_t j
= 0; j
< historicCount
; j
++) {
226 if (fFinalRules
!= NULL
) {
227 // Check if one of final rules has earlier transition date
228 for (i
= 0; i
< 2 /* fFinalRules->size() */; i
++) {
229 TimeZoneRule
*fr
= (TimeZoneRule
*)fFinalRules
->elementAt(i
);
230 if (*fr
== *curRule
) {
233 r
= (TimeZoneRule
*)fFinalRules
->elementAt(i
);
234 avail
= r
->getNextStart(lastTransitionTime
, curStdOffset
, curDstSavings
, false, tt
);
236 if (tt
< nextTransitionTime
) {
237 nextTransitionTime
= tt
;
244 if (nextRule
== NULL
) {
249 if (fHistoricTransitions
== NULL
) {
250 fHistoricTransitions
= new UVector(status
);
251 if (U_FAILURE(status
)) {
255 Transition
*trst
= (Transition
*)uprv_malloc(sizeof(Transition
));
257 status
= U_MEMORY_ALLOCATION_ERROR
;
260 trst
->time
= nextTransitionTime
;
261 trst
->from
= curRule
;
263 fHistoricTransitions
->addElement(trst
, status
);
264 if (U_FAILURE(status
)) {
267 lastTransitionTime
= nextTransitionTime
;
271 if (fFinalRules
!= NULL
) {
272 if (fHistoricTransitions
== NULL
) {
273 fHistoricTransitions
= new UVector(status
);
274 if (U_FAILURE(status
)) {
278 // Append the first transition for each
279 TimeZoneRule
*rule0
= (TimeZoneRule
*)fFinalRules
->elementAt(0);
280 TimeZoneRule
*rule1
= (TimeZoneRule
*)fFinalRules
->elementAt(1);
282 UBool avail0
= rule0
->getNextStart(lastTransitionTime
, curRule
->getRawOffset(), curRule
->getDSTSavings(), false, tt0
);
283 UBool avail1
= rule1
->getNextStart(lastTransitionTime
, curRule
->getRawOffset(), curRule
->getDSTSavings(), false, tt1
);
284 if (!avail0
|| !avail1
) {
285 // Should not happen, because both rules are permanent
286 status
= U_INVALID_STATE_ERROR
;
289 Transition
*final0
= (Transition
*)uprv_malloc(sizeof(Transition
));
290 if (final0
== NULL
) {
291 status
= U_MEMORY_ALLOCATION_ERROR
;
294 Transition
*final1
= (Transition
*)uprv_malloc(sizeof(Transition
));
295 if (final1
== NULL
) {
297 status
= U_MEMORY_ALLOCATION_ERROR
;
302 final0
->from
= curRule
;
304 rule1
->getNextStart(tt0
, rule0
->getRawOffset(), rule0
->getDSTSavings(), false, final1
->time
);
305 final1
->from
= rule0
;
309 final0
->from
= curRule
;
311 rule0
->getNextStart(tt1
, rule1
->getRawOffset(), rule1
->getDSTSavings(), false, final1
->time
);
312 final1
->from
= rule1
;
315 fHistoricTransitions
->addElement(final0
, status
);
316 if (U_FAILURE(status
)) {
319 fHistoricTransitions
->addElement(final1
, status
);
320 if (U_FAILURE(status
)) {
340 RuleBasedTimeZone::clone(void) const {
341 return new RuleBasedTimeZone(*this);
345 RuleBasedTimeZone::getOffset(uint8_t era
, int32_t year
, int32_t month
, int32_t day
,
346 uint8_t dayOfWeek
, int32_t millis
, UErrorCode
& status
) const {
347 if (U_FAILURE(status
)) {
350 if (month
< UCAL_JANUARY
|| month
> UCAL_DECEMBER
) {
351 status
= U_ILLEGAL_ARGUMENT_ERROR
;
354 return getOffset(era
, year
, month
, day
, dayOfWeek
, millis
,
355 Grego::monthLength(year
, month
), status
);
360 RuleBasedTimeZone::getOffset(uint8_t era
, int32_t year
, int32_t month
, int32_t day
,
361 uint8_t /*dayOfWeek*/, int32_t millis
,
362 int32_t /*monthLength*/, UErrorCode
& status
) const {
363 // dayOfWeek and monthLength are unused
364 if (U_FAILURE(status
)) {
367 if (era
== GregorianCalendar::BC
) {
368 // Convert to extended year
371 int32_t rawOffset
, dstOffset
;
372 UDate time
= (UDate
)Grego::fieldsToDay(year
, month
, day
) * U_MILLIS_PER_DAY
+ millis
;
373 getOffsetInternal(time
, TRUE
, kDaylight
, kStandard
, rawOffset
, dstOffset
, status
);
374 if (U_FAILURE(status
)) {
377 return (rawOffset
+ dstOffset
);
381 RuleBasedTimeZone::getOffset(UDate date
, UBool local
, int32_t& rawOffset
,
382 int32_t& dstOffset
, UErrorCode
& status
) const {
383 getOffsetInternal(date
, local
, kFormer
, kLatter
, rawOffset
, dstOffset
, status
);
387 RuleBasedTimeZone::getOffsetFromLocal(UDate date
, int32_t nonExistingTimeOpt
, int32_t duplicatedTimeOpt
,
388 int32_t& rawOffset
, int32_t& dstOffset
, UErrorCode
& status
) /*const*/ {
389 getOffsetInternal(date
, TRUE
, nonExistingTimeOpt
, duplicatedTimeOpt
, rawOffset
, dstOffset
, status
);
394 * The internal getOffset implementation
397 RuleBasedTimeZone::getOffsetInternal(UDate date
, UBool local
,
398 int32_t NonExistingTimeOpt
, int32_t DuplicatedTimeOpt
,
399 int32_t& rawOffset
, int32_t& dstOffset
,
400 UErrorCode
& status
) const {
404 if (U_FAILURE(status
)) {
408 // Transitions are not yet resolved. We cannot do it here
409 // because this method is const. Thus, do nothing and return
411 status
= U_INVALID_STATE_ERROR
;
414 const TimeZoneRule
*rule
= NULL
;
415 if (fHistoricTransitions
== NULL
) {
418 UDate tstart
= getTransitionTime((Transition
*)fHistoricTransitions
->elementAt(0),
419 local
, NonExistingTimeOpt
, DuplicatedTimeOpt
);
423 int32_t idx
= fHistoricTransitions
->size() - 1;
424 UDate tend
= getTransitionTime((Transition
*)fHistoricTransitions
->elementAt(idx
),
425 local
, NonExistingTimeOpt
, DuplicatedTimeOpt
);
427 if (fFinalRules
!= NULL
) {
428 rule
= findRuleInFinal(date
, local
, NonExistingTimeOpt
, DuplicatedTimeOpt
);
430 // no final rule, use the last rule
431 rule
= ((Transition
*)fHistoricTransitions
->elementAt(idx
))->to
;
434 // Find a historical transition
436 if (date
>= getTransitionTime((Transition
*)fHistoricTransitions
->elementAt(idx
),
437 local
, NonExistingTimeOpt
, DuplicatedTimeOpt
)) {
442 rule
= ((Transition
*)fHistoricTransitions
->elementAt(idx
))->to
;
447 rawOffset
= rule
->getRawOffset();
448 dstOffset
= rule
->getDSTSavings();
453 RuleBasedTimeZone::setRawOffset(int32_t /*offsetMillis*/) {
454 // We don't support this operation at this moment.
459 RuleBasedTimeZone::getRawOffset(void) const {
460 // Note: This implementation returns standard GMT offset
461 // as of current time.
462 UErrorCode status
= U_ZERO_ERROR
;
464 getOffset(uprv_getUTCtime() * U_MILLIS_PER_SECOND
,
465 FALSE
, raw
, dst
, status
);
470 RuleBasedTimeZone::useDaylightTime(void) const {
471 // Note: This implementation returns true when
472 // daylight saving time is used as of now or
473 // after the next transition.
474 UErrorCode status
= U_ZERO_ERROR
;
475 UDate now
= uprv_getUTCtime() * U_MILLIS_PER_SECOND
;
477 getOffset(now
, FALSE
, raw
, dst
, status
);
481 // If DST is not used now, check if DST is used after the next transition
483 TimeZoneRule
*from
, *to
;
484 UBool avail
= findNext(now
, FALSE
, time
, from
, to
);
485 if (avail
&& to
->getDSTSavings() != 0) {
492 RuleBasedTimeZone::inDaylightTime(UDate date
, UErrorCode
& status
) const {
493 if (U_FAILURE(status
)) {
497 getOffset(date
, FALSE
, raw
, dst
, status
);
505 RuleBasedTimeZone::hasSameRules(const TimeZone
& other
) const {
506 if (this == &other
) {
509 if (getDynamicClassID() != other
.getDynamicClassID()) {
512 const RuleBasedTimeZone
& that
= (const RuleBasedTimeZone
&)other
;
513 if (*fInitialRule
!= *(that
.fInitialRule
)) {
516 if (compareRules(fHistoricRules
, that
.fHistoricRules
)
517 && compareRules(fFinalRules
, that
.fFinalRules
)) {
524 RuleBasedTimeZone::getNextTransition(UDate base
, UBool inclusive
, TimeZoneTransition
& result
) /*const*/ {
525 UErrorCode status
= U_ZERO_ERROR
;
527 if (U_FAILURE(status
)) {
530 UDate transitionTime
;
531 TimeZoneRule
*fromRule
, *toRule
;
532 UBool found
= findNext(base
, inclusive
, transitionTime
, fromRule
, toRule
);
534 result
.setTime(transitionTime
);
535 result
.setFrom((const TimeZoneRule
&)*fromRule
);
536 result
.setTo((const TimeZoneRule
&)*toRule
);
543 RuleBasedTimeZone::getPreviousTransition(UDate base
, UBool inclusive
, TimeZoneTransition
& result
) /*const*/ {
544 UErrorCode status
= U_ZERO_ERROR
;
546 if (U_FAILURE(status
)) {
549 UDate transitionTime
;
550 TimeZoneRule
*fromRule
, *toRule
;
551 UBool found
= findPrev(base
, inclusive
, transitionTime
, fromRule
, toRule
);
553 result
.setTime(transitionTime
);
554 result
.setFrom((const TimeZoneRule
&)*fromRule
);
555 result
.setTo((const TimeZoneRule
&)*toRule
);
562 RuleBasedTimeZone::countTransitionRules(UErrorCode
& /*status*/) /*const*/ {
564 if (fHistoricRules
!= NULL
) {
565 count
+= fHistoricRules
->size();
567 if (fFinalRules
!= NULL
) {
568 count
+= fFinalRules
->size();
574 RuleBasedTimeZone::getTimeZoneRules(const InitialTimeZoneRule
*& initial
,
575 const TimeZoneRule
* trsrules
[],
577 UErrorCode
& status
) /*const*/ {
578 if (U_FAILURE(status
)) {
582 initial
= fInitialRule
;
587 if (fHistoricRules
!= NULL
&& cnt
< trscount
) {
588 int32_t historicCount
= fHistoricRules
->size();
590 while (cnt
< trscount
&& idx
< historicCount
) {
591 trsrules
[cnt
++] = (const TimeZoneRule
*)fHistoricRules
->elementAt(idx
++);
594 if (fFinalRules
!= NULL
&& cnt
< trscount
) {
595 int32_t finalCount
= fFinalRules
->size();
597 while (cnt
< trscount
&& idx
< finalCount
) {
598 trsrules
[cnt
++] = (const TimeZoneRule
*)fFinalRules
->elementAt(idx
++);
601 // Set the result length
606 RuleBasedTimeZone::deleteRules(void) {
609 if (fHistoricRules
!= NULL
) {
610 while (!fHistoricRules
->isEmpty()) {
611 delete (TimeZoneRule
*)(fHistoricRules
->orphanElementAt(0));
613 delete fHistoricRules
;
614 fHistoricRules
= NULL
;
616 if (fFinalRules
!= NULL
) {
617 while (!fFinalRules
->isEmpty()) {
618 delete (AnnualTimeZoneRule
*)(fFinalRules
->orphanElementAt(0));
626 RuleBasedTimeZone::deleteTransitions(void) {
627 if (fHistoricTransitions
!= NULL
) {
628 while (!fHistoricTransitions
->isEmpty()) {
629 Transition
*trs
= (Transition
*)fHistoricTransitions
->orphanElementAt(0);
632 delete fHistoricTransitions
;
634 fHistoricTransitions
= NULL
;
638 RuleBasedTimeZone::copyRules(UVector
* source
) {
639 if (source
== NULL
) {
642 UErrorCode ec
= U_ZERO_ERROR
;
643 int32_t size
= source
->size();
644 UVector
*rules
= new UVector(size
, ec
);
649 for (i
= 0; i
< size
; i
++) {
650 rules
->addElement(((TimeZoneRule
*)source
->elementAt(i
))->clone(), ec
);
656 // In case of error, clean up
657 for (i
= 0; i
< rules
->size(); i
++) {
658 TimeZoneRule
*rule
= (TimeZoneRule
*)rules
->orphanElementAt(i
);
668 RuleBasedTimeZone::findRuleInFinal(UDate date
, UBool local
,
669 int32_t NonExistingTimeOpt
, int32_t DuplicatedTimeOpt
) const {
670 if (fFinalRules
== NULL
) {
674 AnnualTimeZoneRule
* fr0
= (AnnualTimeZoneRule
*)fFinalRules
->elementAt(0);
675 AnnualTimeZoneRule
* fr1
= (AnnualTimeZoneRule
*)fFinalRules
->elementAt(1);
676 if (fr0
== NULL
|| fr1
== NULL
) {
680 UDate start0
, start1
;
686 localDelta
= getLocalDelta(fr1
->getRawOffset(), fr1
->getDSTSavings(),
687 fr0
->getRawOffset(), fr0
->getDSTSavings(),
688 NonExistingTimeOpt
, DuplicatedTimeOpt
);
691 UBool avail0
= fr0
->getPreviousStart(base
, fr1
->getRawOffset(), fr1
->getDSTSavings(), TRUE
, start0
);
695 localDelta
= getLocalDelta(fr0
->getRawOffset(), fr0
->getDSTSavings(),
696 fr1
->getRawOffset(), fr1
->getDSTSavings(),
697 NonExistingTimeOpt
, DuplicatedTimeOpt
);
700 UBool avail1
= fr1
->getPreviousStart(base
, fr0
->getRawOffset(), fr0
->getDSTSavings(), TRUE
, start1
);
702 if (avail0
&& (!avail1
|| start0
> start1
)) {
711 RuleBasedTimeZone::findNext(UDate base
, UBool inclusive
, UDate
& transitionTime
,
712 TimeZoneRule
*& fromRule
, TimeZoneRule
*& toRule
) const {
713 if (fHistoricTransitions
== NULL
) {
716 UBool isFinal
= FALSE
;
719 Transition
*tzt
= (Transition
*)fHistoricTransitions
->elementAt(0);
720 UDate tt
= tzt
->time
;
721 if (tt
> base
|| (inclusive
&& tt
== base
)) {
725 int32_t idx
= fHistoricTransitions
->size() - 1;
726 tzt
= (Transition
*)fHistoricTransitions
->elementAt(idx
);
728 if (inclusive
&& tt
== base
) {
731 } else if (tt
<= base
) {
732 if (fFinalRules
!= NULL
) {
733 // Find a transion time with finalRules
734 TimeZoneRule
*r0
= (TimeZoneRule
*)fFinalRules
->elementAt(0);
735 TimeZoneRule
*r1
= (TimeZoneRule
*)fFinalRules
->elementAt(1);
736 UDate start0
, start1
;
737 UBool avail0
= r0
->getNextStart(base
, r1
->getRawOffset(), r1
->getDSTSavings(), inclusive
, start0
);
738 UBool avail1
= r1
->getNextStart(base
, r0
->getRawOffset(), r0
->getDSTSavings(), inclusive
, start1
);
739 // avail0/avail1 should be always TRUE
740 if (!avail0
&& !avail1
) {
743 if (!avail1
|| start0
< start1
) {
744 result
.time
= start0
;
748 result
.time
= start1
;
756 // Find a transition within the historic transitions
758 Transition
*prev
= tzt
;
760 tzt
= (Transition
*)fHistoricTransitions
->elementAt(idx
);
762 if (tt
< base
|| (!inclusive
&& tt
== base
)) {
768 result
.time
= prev
->time
;
769 result
.from
= prev
->from
;
770 result
.to
= prev
->to
;
775 // For now, this implementation ignore transitions with only zone name changes.
776 if (result
.from
->getRawOffset() == result
.to
->getRawOffset()
777 && result
.from
->getDSTSavings() == result
.to
->getDSTSavings()) {
781 // No offset changes. Try next one if not final
782 return findNext(result
.time
, FALSE
/* always exclusive */,
783 transitionTime
, fromRule
, toRule
);
786 transitionTime
= result
.time
;
787 fromRule
= result
.from
;
795 RuleBasedTimeZone::findPrev(UDate base
, UBool inclusive
, UDate
& transitionTime
,
796 TimeZoneRule
*& fromRule
, TimeZoneRule
*& toRule
) const {
797 if (fHistoricTransitions
== NULL
) {
802 Transition
*tzt
= (Transition
*)fHistoricTransitions
->elementAt(0);
803 UDate tt
= tzt
->time
;
804 if (inclusive
&& tt
== base
) {
807 } else if (tt
< base
) {
808 int32_t idx
= fHistoricTransitions
->size() - 1;
809 tzt
= (Transition
*)fHistoricTransitions
->elementAt(idx
);
811 if (inclusive
&& tt
== base
) {
814 } else if (tt
< base
) {
815 if (fFinalRules
!= NULL
) {
816 // Find a transion time with finalRules
817 TimeZoneRule
*r0
= (TimeZoneRule
*)fFinalRules
->elementAt(0);
818 TimeZoneRule
*r1
= (TimeZoneRule
*)fFinalRules
->elementAt(1);
819 UDate start0
, start1
;
820 UBool avail0
= r0
->getPreviousStart(base
, r1
->getRawOffset(), r1
->getDSTSavings(), inclusive
, start0
);
821 UBool avail1
= r1
->getPreviousStart(base
, r0
->getRawOffset(), r0
->getDSTSavings(), inclusive
, start1
);
822 // avail0/avail1 should be always TRUE
823 if (!avail0
&& !avail1
) {
826 if (!avail1
|| start0
> start1
) {
827 result
.time
= start0
;
831 result
.time
= start1
;
840 // Find a transition within the historic transitions
843 tzt
= (Transition
*)fHistoricTransitions
->elementAt(idx
);
845 if (tt
< base
|| (inclusive
&& tt
== base
)) {
855 // For now, this implementation ignore transitions with only zone name changes.
856 if (result
.from
->getRawOffset() == result
.to
->getRawOffset()
857 && result
.from
->getDSTSavings() == result
.to
->getDSTSavings()) {
858 // No offset changes. Try next one if not final
859 return findPrev(result
.time
, FALSE
/* always exclusive */,
860 transitionTime
, fromRule
, toRule
);
862 transitionTime
= result
.time
;
863 fromRule
= result
.from
;
871 RuleBasedTimeZone::getTransitionTime(Transition
* transition
, UBool local
,
872 int32_t NonExistingTimeOpt
, int32_t DuplicatedTimeOpt
) const {
873 UDate time
= transition
->time
;
875 time
+= getLocalDelta(transition
->from
->getRawOffset(), transition
->from
->getDSTSavings(),
876 transition
->to
->getRawOffset(), transition
->to
->getDSTSavings(),
877 NonExistingTimeOpt
, DuplicatedTimeOpt
);
883 RuleBasedTimeZone::getLocalDelta(int32_t rawBefore
, int32_t dstBefore
, int32_t rawAfter
, int32_t dstAfter
,
884 int32_t NonExistingTimeOpt
, int32_t DuplicatedTimeOpt
) const {
887 int32_t offsetBefore
= rawBefore
+ dstBefore
;
888 int32_t offsetAfter
= rawAfter
+ dstAfter
;
890 UBool dstToStd
= (dstBefore
!= 0) && (dstAfter
== 0);
891 UBool stdToDst
= (dstBefore
== 0) && (dstAfter
!= 0);
893 if (offsetAfter
- offsetBefore
>= 0) {
894 // Positive transition, which makes a non-existing local time range
895 if (((NonExistingTimeOpt
& kStdDstMask
) == kStandard
&& dstToStd
)
896 || ((NonExistingTimeOpt
& kStdDstMask
) == kDaylight
&& stdToDst
)) {
897 delta
= offsetBefore
;
898 } else if (((NonExistingTimeOpt
& kStdDstMask
) == kStandard
&& stdToDst
)
899 || ((NonExistingTimeOpt
& kStdDstMask
) == kDaylight
&& dstToStd
)) {
901 } else if ((NonExistingTimeOpt
& kFormerLatterMask
) == kLatter
) {
902 delta
= offsetBefore
;
904 // Interprets the time with rule before the transition,
905 // default for non-existing time range
909 // Negative transition, which makes a duplicated local time range
910 if (((DuplicatedTimeOpt
& kStdDstMask
) == kStandard
&& dstToStd
)
911 || ((DuplicatedTimeOpt
& kStdDstMask
) == kDaylight
&& stdToDst
)) {
913 } else if (((DuplicatedTimeOpt
& kStdDstMask
) == kStandard
&& stdToDst
)
914 || ((DuplicatedTimeOpt
& kStdDstMask
) == kDaylight
&& dstToStd
)) {
915 delta
= offsetBefore
;
916 } else if ((DuplicatedTimeOpt
& kFormerLatterMask
) == kFormer
) {
917 delta
= offsetBefore
;
919 // Interprets the time with rule after the transition,
920 // default for duplicated local time range
929 #endif /* #if !UCONFIG_NO_FORMATTING */