2 *******************************************************************************
3 * Copyright (C) 2007-2010, International Business Machines Corporation and
4 * others. All Rights Reserved.
5 *******************************************************************************
8 #include <typeinfo> // for 'typeid' to work
10 #include "unicode/utypes.h"
12 #if !UCONFIG_NO_FORMATTING
14 #include "unicode/rbtz.h"
15 #include "unicode/gregocal.h"
23 * A struct representing a time zone transition
31 static UBool
compareRules(UVector
* rules1
, UVector
* rules2
) {
32 if (rules1
== NULL
&& rules2
== NULL
) {
34 } else if (rules1
== NULL
|| rules2
== NULL
) {
37 int32_t size
= rules1
->size();
38 if (size
!= rules2
->size()) {
41 for (int32_t i
= 0; i
< size
; i
++) {
42 TimeZoneRule
*r1
= (TimeZoneRule
*)rules1
->elementAt(i
);
43 TimeZoneRule
*r2
= (TimeZoneRule
*)rules2
->elementAt(i
);
51 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(RuleBasedTimeZone
)
53 RuleBasedTimeZone::RuleBasedTimeZone(const UnicodeString
& id
, InitialTimeZoneRule
* initialRule
)
54 : BasicTimeZone(id
), fInitialRule(initialRule
), fHistoricRules(NULL
), fFinalRules(NULL
),
55 fHistoricTransitions(NULL
), fUpToDate(FALSE
) {
58 RuleBasedTimeZone::RuleBasedTimeZone(const RuleBasedTimeZone
& source
)
59 : BasicTimeZone(source
), fInitialRule(source
.fInitialRule
->clone()),
60 fHistoricTransitions(NULL
), fUpToDate(FALSE
) {
61 fHistoricRules
= copyRules(source
.fHistoricRules
);
62 fFinalRules
= copyRules(source
.fFinalRules
);
63 if (source
.fUpToDate
) {
64 UErrorCode status
= U_ZERO_ERROR
;
69 RuleBasedTimeZone::~RuleBasedTimeZone() {
75 RuleBasedTimeZone::operator=(const RuleBasedTimeZone
& right
) {
77 BasicTimeZone::operator=(right
);
79 fInitialRule
= right
.fInitialRule
->clone();
80 fHistoricRules
= copyRules(right
.fHistoricRules
);
81 fFinalRules
= copyRules(right
.fFinalRules
);
89 RuleBasedTimeZone::operator==(const TimeZone
& that
) const {
93 if (typeid(*this) != typeid(that
)
94 || BasicTimeZone::operator==(that
) == FALSE
) {
97 RuleBasedTimeZone
*rbtz
= (RuleBasedTimeZone
*)&that
;
98 if (*fInitialRule
!= *(rbtz
->fInitialRule
)) {
101 if (compareRules(fHistoricRules
, rbtz
->fHistoricRules
)
102 && compareRules(fFinalRules
, rbtz
->fFinalRules
)) {
109 RuleBasedTimeZone::operator!=(const TimeZone
& that
) const {
110 return !operator==(that
);
114 RuleBasedTimeZone::addTransitionRule(TimeZoneRule
* rule
, UErrorCode
& status
) {
115 if (U_FAILURE(status
)) {
118 AnnualTimeZoneRule
* atzrule
= dynamic_cast<AnnualTimeZoneRule
*>(rule
);
119 if (atzrule
!= NULL
&& atzrule
->getEndYear() == AnnualTimeZoneRule::MAX_YEAR
) {
121 if (fFinalRules
== NULL
) {
122 fFinalRules
= new UVector(status
);
123 if (U_FAILURE(status
)) {
126 } else if (fFinalRules
->size() >= 2) {
127 // Cannot handle more than two final rules
128 status
= U_INVALID_STATE_ERROR
;
131 fFinalRules
->addElement((void*)rule
, status
);
134 if (fHistoricRules
== NULL
) {
135 fHistoricRules
= new UVector(status
);
136 if (U_FAILURE(status
)) {
140 fHistoricRules
->addElement((void*)rule
, status
);
142 // Mark dirty, so transitions are recalculated at next complete() call
147 RuleBasedTimeZone::complete(UErrorCode
& status
) {
148 if (U_FAILURE(status
)) {
154 // Make sure either no final rules or a pair of AnnualTimeZoneRules
156 if (fFinalRules
!= NULL
&& fFinalRules
->size() != 2) {
157 status
= U_INVALID_STATE_ERROR
;
162 // Create a TimezoneTransition and add to the list
163 if (fHistoricRules
!= NULL
|| fFinalRules
!= NULL
) {
164 TimeZoneRule
*curRule
= fInitialRule
;
165 UDate lastTransitionTime
= MIN_MILLIS
;
167 // Build the transition array which represents historical time zone
169 if (fHistoricRules
!= NULL
&& fHistoricRules
->size() > 0) {
171 int32_t historicCount
= fHistoricRules
->size();
172 done
= (UBool
*)uprv_malloc(sizeof(UBool
) * historicCount
);
174 status
= U_MEMORY_ALLOCATION_ERROR
;
177 for (i
= 0; i
< historicCount
; i
++) {
181 int32_t curStdOffset
= curRule
->getRawOffset();
182 int32_t curDstSavings
= curRule
->getDSTSavings();
183 UDate nextTransitionTime
= MAX_MILLIS
;
184 TimeZoneRule
*nextRule
= NULL
;
185 TimeZoneRule
*r
= NULL
;
188 UnicodeString curName
, name
;
189 curRule
->getName(curName
);
191 for (i
= 0; i
< historicCount
; i
++) {
195 r
= (TimeZoneRule
*)fHistoricRules
->elementAt(i
);
196 avail
= r
->getNextStart(lastTransitionTime
, curStdOffset
, curDstSavings
, false, tt
);
198 // No more transitions from this rule - skip this rule next time
202 if (*r
== *curRule
||
203 (name
== curName
&& r
->getRawOffset() == curRule
->getRawOffset()
204 && r
->getDSTSavings() == curRule
->getDSTSavings())) {
207 if (tt
< nextTransitionTime
) {
208 nextTransitionTime
= tt
;
214 if (nextRule
== NULL
) {
215 // Check if all historic rules are done
216 UBool bDoneAll
= TRUE
;
217 for (int32_t j
= 0; j
< historicCount
; j
++) {
228 if (fFinalRules
!= NULL
) {
229 // Check if one of final rules has earlier transition date
230 for (i
= 0; i
< 2 /* fFinalRules->size() */; i
++) {
231 TimeZoneRule
*fr
= (TimeZoneRule
*)fFinalRules
->elementAt(i
);
232 if (*fr
== *curRule
) {
235 r
= (TimeZoneRule
*)fFinalRules
->elementAt(i
);
236 avail
= r
->getNextStart(lastTransitionTime
, curStdOffset
, curDstSavings
, false, tt
);
238 if (tt
< nextTransitionTime
) {
239 nextTransitionTime
= tt
;
246 if (nextRule
== NULL
) {
251 if (fHistoricTransitions
== NULL
) {
252 fHistoricTransitions
= new UVector(status
);
253 if (U_FAILURE(status
)) {
257 Transition
*trst
= (Transition
*)uprv_malloc(sizeof(Transition
));
259 status
= U_MEMORY_ALLOCATION_ERROR
;
262 trst
->time
= nextTransitionTime
;
263 trst
->from
= curRule
;
265 fHistoricTransitions
->addElement(trst
, status
);
266 if (U_FAILURE(status
)) {
269 lastTransitionTime
= nextTransitionTime
;
273 if (fFinalRules
!= NULL
) {
274 if (fHistoricTransitions
== NULL
) {
275 fHistoricTransitions
= new UVector(status
);
276 if (U_FAILURE(status
)) {
280 // Append the first transition for each
281 TimeZoneRule
*rule0
= (TimeZoneRule
*)fFinalRules
->elementAt(0);
282 TimeZoneRule
*rule1
= (TimeZoneRule
*)fFinalRules
->elementAt(1);
284 UBool avail0
= rule0
->getNextStart(lastTransitionTime
, curRule
->getRawOffset(), curRule
->getDSTSavings(), false, tt0
);
285 UBool avail1
= rule1
->getNextStart(lastTransitionTime
, curRule
->getRawOffset(), curRule
->getDSTSavings(), false, tt1
);
286 if (!avail0
|| !avail1
) {
287 // Should not happen, because both rules are permanent
288 status
= U_INVALID_STATE_ERROR
;
291 Transition
*final0
= (Transition
*)uprv_malloc(sizeof(Transition
));
292 if (final0
== NULL
) {
293 status
= U_MEMORY_ALLOCATION_ERROR
;
296 Transition
*final1
= (Transition
*)uprv_malloc(sizeof(Transition
));
297 if (final1
== NULL
) {
299 status
= U_MEMORY_ALLOCATION_ERROR
;
304 final0
->from
= curRule
;
306 rule1
->getNextStart(tt0
, rule0
->getRawOffset(), rule0
->getDSTSavings(), false, final1
->time
);
307 final1
->from
= rule0
;
311 final0
->from
= curRule
;
313 rule0
->getNextStart(tt1
, rule1
->getRawOffset(), rule1
->getDSTSavings(), false, final1
->time
);
314 final1
->from
= rule1
;
317 fHistoricTransitions
->addElement(final0
, status
);
318 if (U_FAILURE(status
)) {
321 fHistoricTransitions
->addElement(final1
, status
);
322 if (U_FAILURE(status
)) {
342 RuleBasedTimeZone::clone(void) const {
343 return new RuleBasedTimeZone(*this);
347 RuleBasedTimeZone::getOffset(uint8_t era
, int32_t year
, int32_t month
, int32_t day
,
348 uint8_t dayOfWeek
, int32_t millis
, UErrorCode
& status
) const {
349 if (U_FAILURE(status
)) {
352 if (month
< UCAL_JANUARY
|| month
> UCAL_DECEMBER
) {
353 status
= U_ILLEGAL_ARGUMENT_ERROR
;
356 return getOffset(era
, year
, month
, day
, dayOfWeek
, millis
,
357 Grego::monthLength(year
, month
), status
);
362 RuleBasedTimeZone::getOffset(uint8_t era
, int32_t year
, int32_t month
, int32_t day
,
363 uint8_t /*dayOfWeek*/, int32_t millis
,
364 int32_t /*monthLength*/, UErrorCode
& status
) const {
365 // dayOfWeek and monthLength are unused
366 if (U_FAILURE(status
)) {
369 if (era
== GregorianCalendar::BC
) {
370 // Convert to extended year
373 int32_t rawOffset
, dstOffset
;
374 UDate time
= (UDate
)Grego::fieldsToDay(year
, month
, day
) * U_MILLIS_PER_DAY
+ millis
;
375 getOffsetInternal(time
, TRUE
, kDaylight
, kStandard
, rawOffset
, dstOffset
, status
);
376 if (U_FAILURE(status
)) {
379 return (rawOffset
+ dstOffset
);
383 RuleBasedTimeZone::getOffset(UDate date
, UBool local
, int32_t& rawOffset
,
384 int32_t& dstOffset
, UErrorCode
& status
) const {
385 getOffsetInternal(date
, local
, kFormer
, kLatter
, rawOffset
, dstOffset
, status
);
389 RuleBasedTimeZone::getOffsetFromLocal(UDate date
, int32_t nonExistingTimeOpt
, int32_t duplicatedTimeOpt
,
390 int32_t& rawOffset
, int32_t& dstOffset
, UErrorCode
& status
) /*const*/ {
391 getOffsetInternal(date
, TRUE
, nonExistingTimeOpt
, duplicatedTimeOpt
, rawOffset
, dstOffset
, status
);
396 * The internal getOffset implementation
399 RuleBasedTimeZone::getOffsetInternal(UDate date
, UBool local
,
400 int32_t NonExistingTimeOpt
, int32_t DuplicatedTimeOpt
,
401 int32_t& rawOffset
, int32_t& dstOffset
,
402 UErrorCode
& status
) const {
406 if (U_FAILURE(status
)) {
410 // Transitions are not yet resolved. We cannot do it here
411 // because this method is const. Thus, do nothing and return
413 status
= U_INVALID_STATE_ERROR
;
416 const TimeZoneRule
*rule
= NULL
;
417 if (fHistoricTransitions
== NULL
) {
420 UDate tstart
= getTransitionTime((Transition
*)fHistoricTransitions
->elementAt(0),
421 local
, NonExistingTimeOpt
, DuplicatedTimeOpt
);
425 int32_t idx
= fHistoricTransitions
->size() - 1;
426 UDate tend
= getTransitionTime((Transition
*)fHistoricTransitions
->elementAt(idx
),
427 local
, NonExistingTimeOpt
, DuplicatedTimeOpt
);
429 if (fFinalRules
!= NULL
) {
430 rule
= findRuleInFinal(date
, local
, NonExistingTimeOpt
, DuplicatedTimeOpt
);
432 // no final rule, use the last rule
433 rule
= ((Transition
*)fHistoricTransitions
->elementAt(idx
))->to
;
436 // Find a historical transition
438 if (date
>= getTransitionTime((Transition
*)fHistoricTransitions
->elementAt(idx
),
439 local
, NonExistingTimeOpt
, DuplicatedTimeOpt
)) {
444 rule
= ((Transition
*)fHistoricTransitions
->elementAt(idx
))->to
;
449 rawOffset
= rule
->getRawOffset();
450 dstOffset
= rule
->getDSTSavings();
455 RuleBasedTimeZone::setRawOffset(int32_t /*offsetMillis*/) {
456 // We don't support this operation at this moment.
461 RuleBasedTimeZone::getRawOffset(void) const {
462 // Note: This implementation returns standard GMT offset
463 // as of current time.
464 UErrorCode status
= U_ZERO_ERROR
;
466 getOffset(uprv_getUTCtime() * U_MILLIS_PER_SECOND
,
467 FALSE
, raw
, dst
, status
);
472 RuleBasedTimeZone::useDaylightTime(void) const {
473 // Note: This implementation returns true when
474 // daylight saving time is used as of now or
475 // after the next transition.
476 UErrorCode status
= U_ZERO_ERROR
;
477 UDate now
= uprv_getUTCtime() * U_MILLIS_PER_SECOND
;
479 getOffset(now
, FALSE
, raw
, dst
, status
);
483 // If DST is not used now, check if DST is used after the next transition
485 TimeZoneRule
*from
, *to
;
486 UBool avail
= findNext(now
, FALSE
, time
, from
, to
);
487 if (avail
&& to
->getDSTSavings() != 0) {
494 RuleBasedTimeZone::inDaylightTime(UDate date
, UErrorCode
& status
) const {
495 if (U_FAILURE(status
)) {
499 getOffset(date
, FALSE
, raw
, dst
, status
);
507 RuleBasedTimeZone::hasSameRules(const TimeZone
& other
) const {
508 if (this == &other
) {
511 if (typeid(*this) != typeid(other
)) {
514 const RuleBasedTimeZone
& that
= (const RuleBasedTimeZone
&)other
;
515 if (*fInitialRule
!= *(that
.fInitialRule
)) {
518 if (compareRules(fHistoricRules
, that
.fHistoricRules
)
519 && compareRules(fFinalRules
, that
.fFinalRules
)) {
526 RuleBasedTimeZone::getNextTransition(UDate base
, UBool inclusive
, TimeZoneTransition
& result
) /*const*/ {
527 UErrorCode status
= U_ZERO_ERROR
;
529 if (U_FAILURE(status
)) {
532 UDate transitionTime
;
533 TimeZoneRule
*fromRule
, *toRule
;
534 UBool found
= findNext(base
, inclusive
, transitionTime
, fromRule
, toRule
);
536 result
.setTime(transitionTime
);
537 result
.setFrom((const TimeZoneRule
&)*fromRule
);
538 result
.setTo((const TimeZoneRule
&)*toRule
);
545 RuleBasedTimeZone::getPreviousTransition(UDate base
, UBool inclusive
, TimeZoneTransition
& result
) /*const*/ {
546 UErrorCode status
= U_ZERO_ERROR
;
548 if (U_FAILURE(status
)) {
551 UDate transitionTime
;
552 TimeZoneRule
*fromRule
, *toRule
;
553 UBool found
= findPrev(base
, inclusive
, transitionTime
, fromRule
, toRule
);
555 result
.setTime(transitionTime
);
556 result
.setFrom((const TimeZoneRule
&)*fromRule
);
557 result
.setTo((const TimeZoneRule
&)*toRule
);
564 RuleBasedTimeZone::countTransitionRules(UErrorCode
& /*status*/) /*const*/ {
566 if (fHistoricRules
!= NULL
) {
567 count
+= fHistoricRules
->size();
569 if (fFinalRules
!= NULL
) {
570 count
+= fFinalRules
->size();
576 RuleBasedTimeZone::getTimeZoneRules(const InitialTimeZoneRule
*& initial
,
577 const TimeZoneRule
* trsrules
[],
579 UErrorCode
& status
) /*const*/ {
580 if (U_FAILURE(status
)) {
584 initial
= fInitialRule
;
589 if (fHistoricRules
!= NULL
&& cnt
< trscount
) {
590 int32_t historicCount
= fHistoricRules
->size();
592 while (cnt
< trscount
&& idx
< historicCount
) {
593 trsrules
[cnt
++] = (const TimeZoneRule
*)fHistoricRules
->elementAt(idx
++);
596 if (fFinalRules
!= NULL
&& cnt
< trscount
) {
597 int32_t finalCount
= fFinalRules
->size();
599 while (cnt
< trscount
&& idx
< finalCount
) {
600 trsrules
[cnt
++] = (const TimeZoneRule
*)fFinalRules
->elementAt(idx
++);
603 // Set the result length
608 RuleBasedTimeZone::deleteRules(void) {
611 if (fHistoricRules
!= NULL
) {
612 while (!fHistoricRules
->isEmpty()) {
613 delete (TimeZoneRule
*)(fHistoricRules
->orphanElementAt(0));
615 delete fHistoricRules
;
616 fHistoricRules
= NULL
;
618 if (fFinalRules
!= NULL
) {
619 while (!fFinalRules
->isEmpty()) {
620 delete (AnnualTimeZoneRule
*)(fFinalRules
->orphanElementAt(0));
628 RuleBasedTimeZone::deleteTransitions(void) {
629 if (fHistoricTransitions
!= NULL
) {
630 while (!fHistoricTransitions
->isEmpty()) {
631 Transition
*trs
= (Transition
*)fHistoricTransitions
->orphanElementAt(0);
634 delete fHistoricTransitions
;
636 fHistoricTransitions
= NULL
;
640 RuleBasedTimeZone::copyRules(UVector
* source
) {
641 if (source
== NULL
) {
644 UErrorCode ec
= U_ZERO_ERROR
;
645 int32_t size
= source
->size();
646 UVector
*rules
= new UVector(size
, ec
);
651 for (i
= 0; i
< size
; i
++) {
652 rules
->addElement(((TimeZoneRule
*)source
->elementAt(i
))->clone(), ec
);
658 // In case of error, clean up
659 for (i
= 0; i
< rules
->size(); i
++) {
660 TimeZoneRule
*rule
= (TimeZoneRule
*)rules
->orphanElementAt(i
);
670 RuleBasedTimeZone::findRuleInFinal(UDate date
, UBool local
,
671 int32_t NonExistingTimeOpt
, int32_t DuplicatedTimeOpt
) const {
672 if (fFinalRules
== NULL
) {
676 AnnualTimeZoneRule
* fr0
= (AnnualTimeZoneRule
*)fFinalRules
->elementAt(0);
677 AnnualTimeZoneRule
* fr1
= (AnnualTimeZoneRule
*)fFinalRules
->elementAt(1);
678 if (fr0
== NULL
|| fr1
== NULL
) {
682 UDate start0
, start1
;
688 localDelta
= getLocalDelta(fr1
->getRawOffset(), fr1
->getDSTSavings(),
689 fr0
->getRawOffset(), fr0
->getDSTSavings(),
690 NonExistingTimeOpt
, DuplicatedTimeOpt
);
693 UBool avail0
= fr0
->getPreviousStart(base
, fr1
->getRawOffset(), fr1
->getDSTSavings(), TRUE
, start0
);
697 localDelta
= getLocalDelta(fr0
->getRawOffset(), fr0
->getDSTSavings(),
698 fr1
->getRawOffset(), fr1
->getDSTSavings(),
699 NonExistingTimeOpt
, DuplicatedTimeOpt
);
702 UBool avail1
= fr1
->getPreviousStart(base
, fr0
->getRawOffset(), fr0
->getDSTSavings(), TRUE
, start1
);
704 if (avail0
&& (!avail1
|| start0
> start1
)) {
713 RuleBasedTimeZone::findNext(UDate base
, UBool inclusive
, UDate
& transitionTime
,
714 TimeZoneRule
*& fromRule
, TimeZoneRule
*& toRule
) const {
715 if (fHistoricTransitions
== NULL
) {
718 UBool isFinal
= FALSE
;
721 Transition
*tzt
= (Transition
*)fHistoricTransitions
->elementAt(0);
722 UDate tt
= tzt
->time
;
723 if (tt
> base
|| (inclusive
&& tt
== base
)) {
727 int32_t idx
= fHistoricTransitions
->size() - 1;
728 tzt
= (Transition
*)fHistoricTransitions
->elementAt(idx
);
730 if (inclusive
&& tt
== base
) {
733 } else if (tt
<= base
) {
734 if (fFinalRules
!= NULL
) {
735 // Find a transion time with finalRules
736 TimeZoneRule
*r0
= (TimeZoneRule
*)fFinalRules
->elementAt(0);
737 TimeZoneRule
*r1
= (TimeZoneRule
*)fFinalRules
->elementAt(1);
738 UDate start0
, start1
;
739 UBool avail0
= r0
->getNextStart(base
, r1
->getRawOffset(), r1
->getDSTSavings(), inclusive
, start0
);
740 UBool avail1
= r1
->getNextStart(base
, r0
->getRawOffset(), r0
->getDSTSavings(), inclusive
, start1
);
741 // avail0/avail1 should be always TRUE
742 if (!avail0
&& !avail1
) {
745 if (!avail1
|| start0
< start1
) {
746 result
.time
= start0
;
750 result
.time
= start1
;
758 // Find a transition within the historic transitions
760 Transition
*prev
= tzt
;
762 tzt
= (Transition
*)fHistoricTransitions
->elementAt(idx
);
764 if (tt
< base
|| (!inclusive
&& tt
== base
)) {
770 result
.time
= prev
->time
;
771 result
.from
= prev
->from
;
772 result
.to
= prev
->to
;
777 // For now, this implementation ignore transitions with only zone name changes.
778 if (result
.from
->getRawOffset() == result
.to
->getRawOffset()
779 && result
.from
->getDSTSavings() == result
.to
->getDSTSavings()) {
783 // No offset changes. Try next one if not final
784 return findNext(result
.time
, FALSE
/* always exclusive */,
785 transitionTime
, fromRule
, toRule
);
788 transitionTime
= result
.time
;
789 fromRule
= result
.from
;
797 RuleBasedTimeZone::findPrev(UDate base
, UBool inclusive
, UDate
& transitionTime
,
798 TimeZoneRule
*& fromRule
, TimeZoneRule
*& toRule
) const {
799 if (fHistoricTransitions
== NULL
) {
804 Transition
*tzt
= (Transition
*)fHistoricTransitions
->elementAt(0);
805 UDate tt
= tzt
->time
;
806 if (inclusive
&& tt
== base
) {
809 } else if (tt
< base
) {
810 int32_t idx
= fHistoricTransitions
->size() - 1;
811 tzt
= (Transition
*)fHistoricTransitions
->elementAt(idx
);
813 if (inclusive
&& tt
== base
) {
816 } else if (tt
< base
) {
817 if (fFinalRules
!= NULL
) {
818 // Find a transion time with finalRules
819 TimeZoneRule
*r0
= (TimeZoneRule
*)fFinalRules
->elementAt(0);
820 TimeZoneRule
*r1
= (TimeZoneRule
*)fFinalRules
->elementAt(1);
821 UDate start0
, start1
;
822 UBool avail0
= r0
->getPreviousStart(base
, r1
->getRawOffset(), r1
->getDSTSavings(), inclusive
, start0
);
823 UBool avail1
= r1
->getPreviousStart(base
, r0
->getRawOffset(), r0
->getDSTSavings(), inclusive
, start1
);
824 // avail0/avail1 should be always TRUE
825 if (!avail0
&& !avail1
) {
828 if (!avail1
|| start0
> start1
) {
829 result
.time
= start0
;
833 result
.time
= start1
;
842 // Find a transition within the historic transitions
845 tzt
= (Transition
*)fHistoricTransitions
->elementAt(idx
);
847 if (tt
< base
|| (inclusive
&& tt
== base
)) {
857 // For now, this implementation ignore transitions with only zone name changes.
858 if (result
.from
->getRawOffset() == result
.to
->getRawOffset()
859 && result
.from
->getDSTSavings() == result
.to
->getDSTSavings()) {
860 // No offset changes. Try next one if not final
861 return findPrev(result
.time
, FALSE
/* always exclusive */,
862 transitionTime
, fromRule
, toRule
);
864 transitionTime
= result
.time
;
865 fromRule
= result
.from
;
873 RuleBasedTimeZone::getTransitionTime(Transition
* transition
, UBool local
,
874 int32_t NonExistingTimeOpt
, int32_t DuplicatedTimeOpt
) const {
875 UDate time
= transition
->time
;
877 time
+= getLocalDelta(transition
->from
->getRawOffset(), transition
->from
->getDSTSavings(),
878 transition
->to
->getRawOffset(), transition
->to
->getDSTSavings(),
879 NonExistingTimeOpt
, DuplicatedTimeOpt
);
885 RuleBasedTimeZone::getLocalDelta(int32_t rawBefore
, int32_t dstBefore
, int32_t rawAfter
, int32_t dstAfter
,
886 int32_t NonExistingTimeOpt
, int32_t DuplicatedTimeOpt
) const {
889 int32_t offsetBefore
= rawBefore
+ dstBefore
;
890 int32_t offsetAfter
= rawAfter
+ dstAfter
;
892 UBool dstToStd
= (dstBefore
!= 0) && (dstAfter
== 0);
893 UBool stdToDst
= (dstBefore
== 0) && (dstAfter
!= 0);
895 if (offsetAfter
- offsetBefore
>= 0) {
896 // Positive transition, which makes a non-existing local time range
897 if (((NonExistingTimeOpt
& kStdDstMask
) == kStandard
&& dstToStd
)
898 || ((NonExistingTimeOpt
& kStdDstMask
) == kDaylight
&& stdToDst
)) {
899 delta
= offsetBefore
;
900 } else if (((NonExistingTimeOpt
& kStdDstMask
) == kStandard
&& stdToDst
)
901 || ((NonExistingTimeOpt
& kStdDstMask
) == kDaylight
&& dstToStd
)) {
903 } else if ((NonExistingTimeOpt
& kFormerLatterMask
) == kLatter
) {
904 delta
= offsetBefore
;
906 // Interprets the time with rule before the transition,
907 // default for non-existing time range
911 // Negative transition, which makes a duplicated local time range
912 if (((DuplicatedTimeOpt
& kStdDstMask
) == kStandard
&& dstToStd
)
913 || ((DuplicatedTimeOpt
& kStdDstMask
) == kDaylight
&& stdToDst
)) {
915 } else if (((DuplicatedTimeOpt
& kStdDstMask
) == kStandard
&& stdToDst
)
916 || ((DuplicatedTimeOpt
& kStdDstMask
) == kDaylight
&& dstToStd
)) {
917 delta
= offsetBefore
;
918 } else if ((DuplicatedTimeOpt
& kFormerLatterMask
) == kFormer
) {
919 delta
= offsetBefore
;
921 // Interprets the time with rule after the transition,
922 // default for duplicated local time range
931 #endif /* #if !UCONFIG_NO_FORMATTING */