2 *******************************************************************************
3 * Copyright (C) 2007-2013, 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/rbtz.h"
15 #include "unicode/gregocal.h"
24 * A struct representing a time zone transition
32 static UBool
compareRules(UVector
* rules1
, UVector
* rules2
) {
33 if (rules1
== NULL
&& rules2
== NULL
) {
35 } else if (rules1
== NULL
|| rules2
== NULL
) {
38 int32_t size
= rules1
->size();
39 if (size
!= rules2
->size()) {
42 for (int32_t i
= 0; i
< size
; i
++) {
43 TimeZoneRule
*r1
= (TimeZoneRule
*)rules1
->elementAt(i
);
44 TimeZoneRule
*r2
= (TimeZoneRule
*)rules2
->elementAt(i
);
52 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(RuleBasedTimeZone
)
54 RuleBasedTimeZone::RuleBasedTimeZone(const UnicodeString
& id
, InitialTimeZoneRule
* initialRule
)
55 : BasicTimeZone(id
), fInitialRule(initialRule
), fHistoricRules(NULL
), fFinalRules(NULL
),
56 fHistoricTransitions(NULL
), fUpToDate(FALSE
) {
59 RuleBasedTimeZone::RuleBasedTimeZone(const RuleBasedTimeZone
& source
)
60 : BasicTimeZone(source
), fInitialRule(source
.fInitialRule
->clone()),
61 fHistoricTransitions(NULL
), fUpToDate(FALSE
) {
62 fHistoricRules
= copyRules(source
.fHistoricRules
);
63 fFinalRules
= copyRules(source
.fFinalRules
);
64 if (source
.fUpToDate
) {
65 UErrorCode status
= U_ZERO_ERROR
;
70 RuleBasedTimeZone::~RuleBasedTimeZone() {
76 RuleBasedTimeZone::operator=(const RuleBasedTimeZone
& right
) {
78 BasicTimeZone::operator=(right
);
80 fInitialRule
= right
.fInitialRule
->clone();
81 fHistoricRules
= copyRules(right
.fHistoricRules
);
82 fFinalRules
= copyRules(right
.fFinalRules
);
90 RuleBasedTimeZone::operator==(const TimeZone
& that
) const {
94 if (typeid(*this) != typeid(that
)
95 || BasicTimeZone::operator==(that
) == FALSE
) {
98 RuleBasedTimeZone
*rbtz
= (RuleBasedTimeZone
*)&that
;
99 if (*fInitialRule
!= *(rbtz
->fInitialRule
)) {
102 if (compareRules(fHistoricRules
, rbtz
->fHistoricRules
)
103 && compareRules(fFinalRules
, rbtz
->fFinalRules
)) {
110 RuleBasedTimeZone::operator!=(const TimeZone
& that
) const {
111 return !operator==(that
);
115 RuleBasedTimeZone::addTransitionRule(TimeZoneRule
* rule
, UErrorCode
& status
) {
116 if (U_FAILURE(status
)) {
119 AnnualTimeZoneRule
* atzrule
= dynamic_cast<AnnualTimeZoneRule
*>(rule
);
120 if (atzrule
!= NULL
&& atzrule
->getEndYear() == AnnualTimeZoneRule::MAX_YEAR
) {
122 if (fFinalRules
== NULL
) {
123 fFinalRules
= new UVector(status
);
124 if (U_FAILURE(status
)) {
127 } else if (fFinalRules
->size() >= 2) {
128 // Cannot handle more than two final rules
129 status
= U_INVALID_STATE_ERROR
;
132 fFinalRules
->addElement((void*)rule
, status
);
135 if (fHistoricRules
== NULL
) {
136 fHistoricRules
= new UVector(status
);
137 if (U_FAILURE(status
)) {
141 fHistoricRules
->addElement((void*)rule
, status
);
143 // Mark dirty, so transitions are recalculated at next complete() call
147 static UMutex gLock
= U_MUTEX_INITIALIZER
;
150 RuleBasedTimeZone::completeConst(UErrorCode
& status
) const {
151 if (U_FAILURE(status
)) {
155 UMTX_CHECK(&gLock
, fUpToDate
, updated
);
159 RuleBasedTimeZone
*ncThis
= const_cast<RuleBasedTimeZone
*>(this);
160 ncThis
->complete(status
);
167 RuleBasedTimeZone::complete(UErrorCode
& status
) {
168 if (U_FAILURE(status
)) {
174 // Make sure either no final rules or a pair of AnnualTimeZoneRules
176 if (fFinalRules
!= NULL
&& fFinalRules
->size() != 2) {
177 status
= U_INVALID_STATE_ERROR
;
182 // Create a TimezoneTransition and add to the list
183 if (fHistoricRules
!= NULL
|| fFinalRules
!= NULL
) {
184 TimeZoneRule
*curRule
= fInitialRule
;
185 UDate lastTransitionTime
= MIN_MILLIS
;
187 // Build the transition array which represents historical time zone
189 if (fHistoricRules
!= NULL
&& fHistoricRules
->size() > 0) {
191 int32_t historicCount
= fHistoricRules
->size();
192 done
= (UBool
*)uprv_malloc(sizeof(UBool
) * historicCount
);
194 status
= U_MEMORY_ALLOCATION_ERROR
;
197 for (i
= 0; i
< historicCount
; i
++) {
201 int32_t curStdOffset
= curRule
->getRawOffset();
202 int32_t curDstSavings
= curRule
->getDSTSavings();
203 UDate nextTransitionTime
= MAX_MILLIS
;
204 TimeZoneRule
*nextRule
= NULL
;
205 TimeZoneRule
*r
= NULL
;
208 UnicodeString curName
, name
;
209 curRule
->getName(curName
);
211 for (i
= 0; i
< historicCount
; i
++) {
215 r
= (TimeZoneRule
*)fHistoricRules
->elementAt(i
);
216 avail
= r
->getNextStart(lastTransitionTime
, curStdOffset
, curDstSavings
, false, tt
);
218 // No more transitions from this rule - skip this rule next time
222 if (*r
== *curRule
||
223 (name
== curName
&& r
->getRawOffset() == curRule
->getRawOffset()
224 && r
->getDSTSavings() == curRule
->getDSTSavings())) {
227 if (tt
< nextTransitionTime
) {
228 nextTransitionTime
= tt
;
234 if (nextRule
== NULL
) {
235 // Check if all historic rules are done
236 UBool bDoneAll
= TRUE
;
237 for (int32_t j
= 0; j
< historicCount
; j
++) {
248 if (fFinalRules
!= NULL
) {
249 // Check if one of final rules has earlier transition date
250 for (i
= 0; i
< 2 /* fFinalRules->size() */; i
++) {
251 TimeZoneRule
*fr
= (TimeZoneRule
*)fFinalRules
->elementAt(i
);
252 if (*fr
== *curRule
) {
255 r
= (TimeZoneRule
*)fFinalRules
->elementAt(i
);
256 avail
= r
->getNextStart(lastTransitionTime
, curStdOffset
, curDstSavings
, false, tt
);
258 if (tt
< nextTransitionTime
) {
259 nextTransitionTime
= tt
;
266 if (nextRule
== NULL
) {
271 if (fHistoricTransitions
== NULL
) {
272 fHistoricTransitions
= new UVector(status
);
273 if (U_FAILURE(status
)) {
277 Transition
*trst
= (Transition
*)uprv_malloc(sizeof(Transition
));
279 status
= U_MEMORY_ALLOCATION_ERROR
;
282 trst
->time
= nextTransitionTime
;
283 trst
->from
= curRule
;
285 fHistoricTransitions
->addElement(trst
, status
);
286 if (U_FAILURE(status
)) {
289 lastTransitionTime
= nextTransitionTime
;
293 if (fFinalRules
!= NULL
) {
294 if (fHistoricTransitions
== NULL
) {
295 fHistoricTransitions
= new UVector(status
);
296 if (U_FAILURE(status
)) {
300 // Append the first transition for each
301 TimeZoneRule
*rule0
= (TimeZoneRule
*)fFinalRules
->elementAt(0);
302 TimeZoneRule
*rule1
= (TimeZoneRule
*)fFinalRules
->elementAt(1);
304 UBool avail0
= rule0
->getNextStart(lastTransitionTime
, curRule
->getRawOffset(), curRule
->getDSTSavings(), false, tt0
);
305 UBool avail1
= rule1
->getNextStart(lastTransitionTime
, curRule
->getRawOffset(), curRule
->getDSTSavings(), false, tt1
);
306 if (!avail0
|| !avail1
) {
307 // Should not happen, because both rules are permanent
308 status
= U_INVALID_STATE_ERROR
;
311 Transition
*final0
= (Transition
*)uprv_malloc(sizeof(Transition
));
312 if (final0
== NULL
) {
313 status
= U_MEMORY_ALLOCATION_ERROR
;
316 Transition
*final1
= (Transition
*)uprv_malloc(sizeof(Transition
));
317 if (final1
== NULL
) {
319 status
= U_MEMORY_ALLOCATION_ERROR
;
324 final0
->from
= curRule
;
326 rule1
->getNextStart(tt0
, rule0
->getRawOffset(), rule0
->getDSTSavings(), false, final1
->time
);
327 final1
->from
= rule0
;
331 final0
->from
= curRule
;
333 rule0
->getNextStart(tt1
, rule1
->getRawOffset(), rule1
->getDSTSavings(), false, final1
->time
);
334 final1
->from
= rule1
;
337 fHistoricTransitions
->addElement(final0
, status
);
338 if (U_FAILURE(status
)) {
341 fHistoricTransitions
->addElement(final1
, status
);
342 if (U_FAILURE(status
)) {
362 RuleBasedTimeZone::clone(void) const {
363 return new RuleBasedTimeZone(*this);
367 RuleBasedTimeZone::getOffset(uint8_t era
, int32_t year
, int32_t month
, int32_t day
,
368 uint8_t dayOfWeek
, int32_t millis
, UErrorCode
& status
) const {
369 if (U_FAILURE(status
)) {
372 if (month
< UCAL_JANUARY
|| month
> UCAL_DECEMBER
) {
373 status
= U_ILLEGAL_ARGUMENT_ERROR
;
376 return getOffset(era
, year
, month
, day
, dayOfWeek
, millis
,
377 Grego::monthLength(year
, month
), status
);
382 RuleBasedTimeZone::getOffset(uint8_t era
, int32_t year
, int32_t month
, int32_t day
,
383 uint8_t /*dayOfWeek*/, int32_t millis
,
384 int32_t /*monthLength*/, UErrorCode
& status
) const {
385 // dayOfWeek and monthLength are unused
386 if (U_FAILURE(status
)) {
389 if (era
== GregorianCalendar::BC
) {
390 // Convert to extended year
393 int32_t rawOffset
, dstOffset
;
394 UDate time
= (UDate
)Grego::fieldsToDay(year
, month
, day
) * U_MILLIS_PER_DAY
+ millis
;
395 getOffsetInternal(time
, TRUE
, kDaylight
, kStandard
, rawOffset
, dstOffset
, status
);
396 if (U_FAILURE(status
)) {
399 return (rawOffset
+ dstOffset
);
403 RuleBasedTimeZone::getOffset(UDate date
, UBool local
, int32_t& rawOffset
,
404 int32_t& dstOffset
, UErrorCode
& status
) const {
405 getOffsetInternal(date
, local
, kFormer
, kLatter
, rawOffset
, dstOffset
, status
);
409 RuleBasedTimeZone::getOffsetFromLocal(UDate date
, int32_t nonExistingTimeOpt
, int32_t duplicatedTimeOpt
,
410 int32_t& rawOffset
, int32_t& dstOffset
, UErrorCode
& status
) const {
411 getOffsetInternal(date
, TRUE
, nonExistingTimeOpt
, duplicatedTimeOpt
, rawOffset
, dstOffset
, status
);
416 * The internal getOffset implementation
419 RuleBasedTimeZone::getOffsetInternal(UDate date
, UBool local
,
420 int32_t NonExistingTimeOpt
, int32_t DuplicatedTimeOpt
,
421 int32_t& rawOffset
, int32_t& dstOffset
,
422 UErrorCode
& status
) const {
426 if (U_FAILURE(status
)) {
430 // Transitions are not yet resolved. We cannot do it here
431 // because this method is const. Thus, do nothing and return
433 status
= U_INVALID_STATE_ERROR
;
436 const TimeZoneRule
*rule
= NULL
;
437 if (fHistoricTransitions
== NULL
) {
440 UDate tstart
= getTransitionTime((Transition
*)fHistoricTransitions
->elementAt(0),
441 local
, NonExistingTimeOpt
, DuplicatedTimeOpt
);
445 int32_t idx
= fHistoricTransitions
->size() - 1;
446 UDate tend
= getTransitionTime((Transition
*)fHistoricTransitions
->elementAt(idx
),
447 local
, NonExistingTimeOpt
, DuplicatedTimeOpt
);
449 if (fFinalRules
!= NULL
) {
450 rule
= findRuleInFinal(date
, local
, NonExistingTimeOpt
, DuplicatedTimeOpt
);
453 // no final rules or the given time is before the first transition
454 // specified by the final rules -> use the last rule
455 rule
= ((Transition
*)fHistoricTransitions
->elementAt(idx
))->to
;
458 // Find a historical transition
460 if (date
>= getTransitionTime((Transition
*)fHistoricTransitions
->elementAt(idx
),
461 local
, NonExistingTimeOpt
, DuplicatedTimeOpt
)) {
466 rule
= ((Transition
*)fHistoricTransitions
->elementAt(idx
))->to
;
471 rawOffset
= rule
->getRawOffset();
472 dstOffset
= rule
->getDSTSavings();
477 RuleBasedTimeZone::setRawOffset(int32_t /*offsetMillis*/) {
478 // We don't support this operation at this moment.
483 RuleBasedTimeZone::getRawOffset(void) const {
484 // Note: This implementation returns standard GMT offset
485 // as of current time.
486 UErrorCode status
= U_ZERO_ERROR
;
488 getOffset(uprv_getUTCtime() * U_MILLIS_PER_SECOND
,
489 FALSE
, raw
, dst
, status
);
494 RuleBasedTimeZone::useDaylightTime(void) const {
495 // Note: This implementation returns true when
496 // daylight saving time is used as of now or
497 // after the next transition.
498 UErrorCode status
= U_ZERO_ERROR
;
499 UDate now
= uprv_getUTCtime() * U_MILLIS_PER_SECOND
;
501 getOffset(now
, FALSE
, raw
, dst
, status
);
505 // If DST is not used now, check if DST is used after the next transition
507 TimeZoneRule
*from
, *to
;
508 UBool avail
= findNext(now
, FALSE
, time
, from
, to
);
509 if (avail
&& to
->getDSTSavings() != 0) {
516 RuleBasedTimeZone::inDaylightTime(UDate date
, UErrorCode
& status
) const {
517 if (U_FAILURE(status
)) {
521 getOffset(date
, FALSE
, raw
, dst
, status
);
529 RuleBasedTimeZone::hasSameRules(const TimeZone
& other
) const {
530 if (this == &other
) {
533 if (typeid(*this) != typeid(other
)) {
536 const RuleBasedTimeZone
& that
= (const RuleBasedTimeZone
&)other
;
537 if (*fInitialRule
!= *(that
.fInitialRule
)) {
540 if (compareRules(fHistoricRules
, that
.fHistoricRules
)
541 && compareRules(fFinalRules
, that
.fFinalRules
)) {
548 RuleBasedTimeZone::getNextTransition(UDate base
, UBool inclusive
, TimeZoneTransition
& result
) const {
549 UErrorCode status
= U_ZERO_ERROR
;
550 completeConst(status
);
551 if (U_FAILURE(status
)) {
554 UDate transitionTime
;
555 TimeZoneRule
*fromRule
, *toRule
;
556 UBool found
= findNext(base
, inclusive
, transitionTime
, fromRule
, toRule
);
558 result
.setTime(transitionTime
);
559 result
.setFrom((const TimeZoneRule
&)*fromRule
);
560 result
.setTo((const TimeZoneRule
&)*toRule
);
567 RuleBasedTimeZone::getPreviousTransition(UDate base
, UBool inclusive
, TimeZoneTransition
& result
) const {
568 UErrorCode status
= U_ZERO_ERROR
;
569 completeConst(status
);
570 if (U_FAILURE(status
)) {
573 UDate transitionTime
;
574 TimeZoneRule
*fromRule
, *toRule
;
575 UBool found
= findPrev(base
, inclusive
, transitionTime
, fromRule
, toRule
);
577 result
.setTime(transitionTime
);
578 result
.setFrom((const TimeZoneRule
&)*fromRule
);
579 result
.setTo((const TimeZoneRule
&)*toRule
);
586 RuleBasedTimeZone::countTransitionRules(UErrorCode
& /*status*/) const {
588 if (fHistoricRules
!= NULL
) {
589 count
+= fHistoricRules
->size();
591 if (fFinalRules
!= NULL
) {
592 count
+= fFinalRules
->size();
598 RuleBasedTimeZone::getTimeZoneRules(const InitialTimeZoneRule
*& initial
,
599 const TimeZoneRule
* trsrules
[],
601 UErrorCode
& status
) const {
602 if (U_FAILURE(status
)) {
606 initial
= fInitialRule
;
611 if (fHistoricRules
!= NULL
&& cnt
< trscount
) {
612 int32_t historicCount
= fHistoricRules
->size();
614 while (cnt
< trscount
&& idx
< historicCount
) {
615 trsrules
[cnt
++] = (const TimeZoneRule
*)fHistoricRules
->elementAt(idx
++);
618 if (fFinalRules
!= NULL
&& cnt
< trscount
) {
619 int32_t finalCount
= fFinalRules
->size();
621 while (cnt
< trscount
&& idx
< finalCount
) {
622 trsrules
[cnt
++] = (const TimeZoneRule
*)fFinalRules
->elementAt(idx
++);
625 // Set the result length
630 RuleBasedTimeZone::deleteRules(void) {
633 if (fHistoricRules
!= NULL
) {
634 while (!fHistoricRules
->isEmpty()) {
635 delete (TimeZoneRule
*)(fHistoricRules
->orphanElementAt(0));
637 delete fHistoricRules
;
638 fHistoricRules
= NULL
;
640 if (fFinalRules
!= NULL
) {
641 while (!fFinalRules
->isEmpty()) {
642 delete (AnnualTimeZoneRule
*)(fFinalRules
->orphanElementAt(0));
650 RuleBasedTimeZone::deleteTransitions(void) {
651 if (fHistoricTransitions
!= NULL
) {
652 while (!fHistoricTransitions
->isEmpty()) {
653 Transition
*trs
= (Transition
*)fHistoricTransitions
->orphanElementAt(0);
656 delete fHistoricTransitions
;
658 fHistoricTransitions
= NULL
;
662 RuleBasedTimeZone::copyRules(UVector
* source
) {
663 if (source
== NULL
) {
666 UErrorCode ec
= U_ZERO_ERROR
;
667 int32_t size
= source
->size();
668 UVector
*rules
= new UVector(size
, ec
);
673 for (i
= 0; i
< size
; i
++) {
674 rules
->addElement(((TimeZoneRule
*)source
->elementAt(i
))->clone(), ec
);
680 // In case of error, clean up
681 for (i
= 0; i
< rules
->size(); i
++) {
682 TimeZoneRule
*rule
= (TimeZoneRule
*)rules
->orphanElementAt(i
);
692 RuleBasedTimeZone::findRuleInFinal(UDate date
, UBool local
,
693 int32_t NonExistingTimeOpt
, int32_t DuplicatedTimeOpt
) const {
694 if (fFinalRules
== NULL
) {
698 AnnualTimeZoneRule
* fr0
= (AnnualTimeZoneRule
*)fFinalRules
->elementAt(0);
699 AnnualTimeZoneRule
* fr1
= (AnnualTimeZoneRule
*)fFinalRules
->elementAt(1);
700 if (fr0
== NULL
|| fr1
== NULL
) {
704 UDate start0
, start1
;
710 localDelta
= getLocalDelta(fr1
->getRawOffset(), fr1
->getDSTSavings(),
711 fr0
->getRawOffset(), fr0
->getDSTSavings(),
712 NonExistingTimeOpt
, DuplicatedTimeOpt
);
715 UBool avail0
= fr0
->getPreviousStart(base
, fr1
->getRawOffset(), fr1
->getDSTSavings(), TRUE
, start0
);
719 localDelta
= getLocalDelta(fr0
->getRawOffset(), fr0
->getDSTSavings(),
720 fr1
->getRawOffset(), fr1
->getDSTSavings(),
721 NonExistingTimeOpt
, DuplicatedTimeOpt
);
724 UBool avail1
= fr1
->getPreviousStart(base
, fr0
->getRawOffset(), fr0
->getDSTSavings(), TRUE
, start1
);
726 if (!avail0
|| !avail1
) {
732 // Both rules take effect after the given time
736 return (start0
> start1
) ? fr0
: fr1
;
740 RuleBasedTimeZone::findNext(UDate base
, UBool inclusive
, UDate
& transitionTime
,
741 TimeZoneRule
*& fromRule
, TimeZoneRule
*& toRule
) const {
742 if (fHistoricTransitions
== NULL
) {
745 UBool isFinal
= FALSE
;
748 Transition
*tzt
= (Transition
*)fHistoricTransitions
->elementAt(0);
749 UDate tt
= tzt
->time
;
750 if (tt
> base
|| (inclusive
&& tt
== base
)) {
754 int32_t idx
= fHistoricTransitions
->size() - 1;
755 tzt
= (Transition
*)fHistoricTransitions
->elementAt(idx
);
757 if (inclusive
&& tt
== base
) {
760 } else if (tt
<= base
) {
761 if (fFinalRules
!= NULL
) {
762 // Find a transion time with finalRules
763 TimeZoneRule
*r0
= (TimeZoneRule
*)fFinalRules
->elementAt(0);
764 TimeZoneRule
*r1
= (TimeZoneRule
*)fFinalRules
->elementAt(1);
765 UDate start0
, start1
;
766 UBool avail0
= r0
->getNextStart(base
, r1
->getRawOffset(), r1
->getDSTSavings(), inclusive
, start0
);
767 UBool avail1
= r1
->getNextStart(base
, r0
->getRawOffset(), r0
->getDSTSavings(), inclusive
, start1
);
768 // avail0/avail1 should be always TRUE
769 if (!avail0
&& !avail1
) {
772 if (!avail1
|| start0
< start1
) {
773 result
.time
= start0
;
777 result
.time
= start1
;
785 // Find a transition within the historic transitions
787 Transition
*prev
= tzt
;
789 tzt
= (Transition
*)fHistoricTransitions
->elementAt(idx
);
791 if (tt
< base
|| (!inclusive
&& tt
== base
)) {
797 result
.time
= prev
->time
;
798 result
.from
= prev
->from
;
799 result
.to
= prev
->to
;
804 // For now, this implementation ignore transitions with only zone name changes.
805 if (result
.from
->getRawOffset() == result
.to
->getRawOffset()
806 && result
.from
->getDSTSavings() == result
.to
->getDSTSavings()) {
810 // No offset changes. Try next one if not final
811 return findNext(result
.time
, FALSE
/* always exclusive */,
812 transitionTime
, fromRule
, toRule
);
815 transitionTime
= result
.time
;
816 fromRule
= result
.from
;
824 RuleBasedTimeZone::findPrev(UDate base
, UBool inclusive
, UDate
& transitionTime
,
825 TimeZoneRule
*& fromRule
, TimeZoneRule
*& toRule
) const {
826 if (fHistoricTransitions
== NULL
) {
831 Transition
*tzt
= (Transition
*)fHistoricTransitions
->elementAt(0);
832 UDate tt
= tzt
->time
;
833 if (inclusive
&& tt
== base
) {
836 } else if (tt
< base
) {
837 int32_t idx
= fHistoricTransitions
->size() - 1;
838 tzt
= (Transition
*)fHistoricTransitions
->elementAt(idx
);
840 if (inclusive
&& tt
== base
) {
843 } else if (tt
< base
) {
844 if (fFinalRules
!= NULL
) {
845 // Find a transion time with finalRules
846 TimeZoneRule
*r0
= (TimeZoneRule
*)fFinalRules
->elementAt(0);
847 TimeZoneRule
*r1
= (TimeZoneRule
*)fFinalRules
->elementAt(1);
848 UDate start0
, start1
;
849 UBool avail0
= r0
->getPreviousStart(base
, r1
->getRawOffset(), r1
->getDSTSavings(), inclusive
, start0
);
850 UBool avail1
= r1
->getPreviousStart(base
, r0
->getRawOffset(), r0
->getDSTSavings(), inclusive
, start1
);
851 // avail0/avail1 should be always TRUE
852 if (!avail0
&& !avail1
) {
855 if (!avail1
|| start0
> start1
) {
856 result
.time
= start0
;
860 result
.time
= start1
;
869 // Find a transition within the historic transitions
872 tzt
= (Transition
*)fHistoricTransitions
->elementAt(idx
);
874 if (tt
< base
|| (inclusive
&& tt
== base
)) {
884 // For now, this implementation ignore transitions with only zone name changes.
885 if (result
.from
->getRawOffset() == result
.to
->getRawOffset()
886 && result
.from
->getDSTSavings() == result
.to
->getDSTSavings()) {
887 // No offset changes. Try next one if not final
888 return findPrev(result
.time
, FALSE
/* always exclusive */,
889 transitionTime
, fromRule
, toRule
);
891 transitionTime
= result
.time
;
892 fromRule
= result
.from
;
900 RuleBasedTimeZone::getTransitionTime(Transition
* transition
, UBool local
,
901 int32_t NonExistingTimeOpt
, int32_t DuplicatedTimeOpt
) const {
902 UDate time
= transition
->time
;
904 time
+= getLocalDelta(transition
->from
->getRawOffset(), transition
->from
->getDSTSavings(),
905 transition
->to
->getRawOffset(), transition
->to
->getDSTSavings(),
906 NonExistingTimeOpt
, DuplicatedTimeOpt
);
912 RuleBasedTimeZone::getLocalDelta(int32_t rawBefore
, int32_t dstBefore
, int32_t rawAfter
, int32_t dstAfter
,
913 int32_t NonExistingTimeOpt
, int32_t DuplicatedTimeOpt
) const {
916 int32_t offsetBefore
= rawBefore
+ dstBefore
;
917 int32_t offsetAfter
= rawAfter
+ dstAfter
;
919 UBool dstToStd
= (dstBefore
!= 0) && (dstAfter
== 0);
920 UBool stdToDst
= (dstBefore
== 0) && (dstAfter
!= 0);
922 if (offsetAfter
- offsetBefore
>= 0) {
923 // Positive transition, which makes a non-existing local time range
924 if (((NonExistingTimeOpt
& kStdDstMask
) == kStandard
&& dstToStd
)
925 || ((NonExistingTimeOpt
& kStdDstMask
) == kDaylight
&& stdToDst
)) {
926 delta
= offsetBefore
;
927 } else if (((NonExistingTimeOpt
& kStdDstMask
) == kStandard
&& stdToDst
)
928 || ((NonExistingTimeOpt
& kStdDstMask
) == kDaylight
&& dstToStd
)) {
930 } else if ((NonExistingTimeOpt
& kFormerLatterMask
) == kLatter
) {
931 delta
= offsetBefore
;
933 // Interprets the time with rule before the transition,
934 // default for non-existing time range
938 // Negative transition, which makes a duplicated local time range
939 if (((DuplicatedTimeOpt
& kStdDstMask
) == kStandard
&& dstToStd
)
940 || ((DuplicatedTimeOpt
& kStdDstMask
) == kDaylight
&& stdToDst
)) {
942 } else if (((DuplicatedTimeOpt
& kStdDstMask
) == kStandard
&& stdToDst
)
943 || ((DuplicatedTimeOpt
& kStdDstMask
) == kDaylight
&& dstToStd
)) {
944 delta
= offsetBefore
;
945 } else if ((DuplicatedTimeOpt
& kFormerLatterMask
) == kFormer
) {
946 delta
= offsetBefore
;
948 // Interprets the time with rule after the transition,
949 // default for duplicated local time range
958 #endif /* #if !UCONFIG_NO_FORMATTING */