LCOV - code coverage report
Current view: top level - intl/icu/source/i18n - rbtz.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 559 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 36 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : // © 2016 and later: Unicode, Inc. and others.
       2             : // License & terms of use: http://www.unicode.org/copyright.html
       3             : /*
       4             : *******************************************************************************
       5             : * Copyright (C) 2007-2013, International Business Machines Corporation and
       6             : * others. All Rights Reserved.
       7             : *******************************************************************************
       8             : */
       9             : 
      10             : #include "utypeinfo.h"  // for 'typeid' to work
      11             : 
      12             : #include "unicode/utypes.h"
      13             : 
      14             : #if !UCONFIG_NO_FORMATTING
      15             : 
      16             : #include "unicode/rbtz.h"
      17             : #include "unicode/gregocal.h"
      18             : #include "uvector.h"
      19             : #include "gregoimp.h"
      20             : #include "cmemory.h"
      21             : #include "umutex.h"
      22             : 
      23             : U_NAMESPACE_BEGIN
      24             : 
      25             : /**
      26             :  * A struct representing a time zone transition
      27             :  */
      28             : struct Transition {
      29             :     UDate time;
      30             :     TimeZoneRule* from;
      31             :     TimeZoneRule* to;
      32             : };
      33             : 
      34           0 : static UBool compareRules(UVector* rules1, UVector* rules2) {
      35           0 :     if (rules1 == NULL && rules2 == NULL) {
      36           0 :         return TRUE;
      37           0 :     } else if (rules1 == NULL || rules2 == NULL) {
      38           0 :         return FALSE;
      39             :     }
      40           0 :     int32_t size = rules1->size();
      41           0 :     if (size != rules2->size()) {
      42           0 :         return FALSE;
      43             :     }
      44           0 :     for (int32_t i = 0; i < size; i++) {
      45           0 :         TimeZoneRule *r1 = (TimeZoneRule*)rules1->elementAt(i);
      46           0 :         TimeZoneRule *r2 = (TimeZoneRule*)rules2->elementAt(i);
      47           0 :         if (*r1 != *r2) {
      48           0 :             return FALSE;
      49             :         }
      50             :     }
      51           0 :     return TRUE;
      52             : }
      53             : 
      54           0 : UOBJECT_DEFINE_RTTI_IMPLEMENTATION(RuleBasedTimeZone)
      55             : 
      56           0 : RuleBasedTimeZone::RuleBasedTimeZone(const UnicodeString& id, InitialTimeZoneRule* initialRule)
      57             : : BasicTimeZone(id), fInitialRule(initialRule), fHistoricRules(NULL), fFinalRules(NULL),
      58           0 :   fHistoricTransitions(NULL), fUpToDate(FALSE) {
      59           0 : }
      60             : 
      61           0 : RuleBasedTimeZone::RuleBasedTimeZone(const RuleBasedTimeZone& source)
      62           0 : : BasicTimeZone(source), fInitialRule(source.fInitialRule->clone()),
      63           0 :   fHistoricTransitions(NULL), fUpToDate(FALSE) {
      64           0 :     fHistoricRules = copyRules(source.fHistoricRules);
      65           0 :     fFinalRules = copyRules(source.fFinalRules);
      66           0 :     if (source.fUpToDate) {
      67           0 :         UErrorCode status = U_ZERO_ERROR;
      68           0 :         complete(status);
      69             :     }
      70           0 : }
      71             : 
      72           0 : RuleBasedTimeZone::~RuleBasedTimeZone() {
      73           0 :     deleteTransitions();
      74           0 :     deleteRules();
      75           0 : }
      76             : 
      77             : RuleBasedTimeZone&
      78           0 : RuleBasedTimeZone::operator=(const RuleBasedTimeZone& right) {
      79           0 :     if (*this != right) {
      80           0 :         BasicTimeZone::operator=(right);
      81           0 :         deleteRules();
      82           0 :         fInitialRule = right.fInitialRule->clone();
      83           0 :         fHistoricRules = copyRules(right.fHistoricRules);
      84           0 :         fFinalRules = copyRules(right.fFinalRules);
      85           0 :         deleteTransitions();
      86           0 :         fUpToDate = FALSE;
      87             :     }
      88           0 :     return *this;
      89             : }
      90             : 
      91             : UBool
      92           0 : RuleBasedTimeZone::operator==(const TimeZone& that) const {
      93           0 :     if (this == &that) {
      94           0 :         return TRUE;
      95             :     }
      96           0 :     if (typeid(*this) != typeid(that)
      97           0 :         || BasicTimeZone::operator==(that) == FALSE) {
      98           0 :         return FALSE;
      99             :     }
     100           0 :     RuleBasedTimeZone *rbtz = (RuleBasedTimeZone*)&that;
     101           0 :     if (*fInitialRule != *(rbtz->fInitialRule)) {
     102           0 :         return FALSE;
     103             :     }
     104           0 :     if (compareRules(fHistoricRules, rbtz->fHistoricRules)
     105           0 :         && compareRules(fFinalRules, rbtz->fFinalRules)) {
     106           0 :         return TRUE;
     107             :     }
     108           0 :     return FALSE;
     109             : }
     110             : 
     111             : UBool
     112           0 : RuleBasedTimeZone::operator!=(const TimeZone& that) const {
     113           0 :     return !operator==(that);
     114             : }
     115             : 
     116             : void
     117           0 : RuleBasedTimeZone::addTransitionRule(TimeZoneRule* rule, UErrorCode& status) {
     118           0 :     if (U_FAILURE(status)) {
     119           0 :         return;
     120             :     }
     121           0 :     AnnualTimeZoneRule* atzrule = dynamic_cast<AnnualTimeZoneRule*>(rule);
     122           0 :     if (atzrule != NULL && atzrule->getEndYear() == AnnualTimeZoneRule::MAX_YEAR) {
     123             :         // A final rule
     124           0 :         if (fFinalRules == NULL) {
     125           0 :             fFinalRules = new UVector(status);
     126           0 :             if (U_FAILURE(status)) {
     127           0 :                 return;
     128             :             }
     129           0 :         } else if (fFinalRules->size() >= 2) {
     130             :             // Cannot handle more than two final rules
     131           0 :             status = U_INVALID_STATE_ERROR;
     132           0 :             return;
     133             :         }
     134           0 :         fFinalRules->addElement((void*)rule, status);
     135             :     } else {
     136             :         // Non-final rule
     137           0 :         if (fHistoricRules == NULL) {
     138           0 :             fHistoricRules = new UVector(status);
     139           0 :             if (U_FAILURE(status)) {
     140           0 :                 return;
     141             :             }
     142             :         }
     143           0 :         fHistoricRules->addElement((void*)rule, status);
     144             :     }
     145             :     // Mark dirty, so transitions are recalculated at next complete() call
     146           0 :     fUpToDate = FALSE;
     147             : }
     148             : 
     149             : static UMutex gLock = U_MUTEX_INITIALIZER;
     150             : 
     151             : void
     152           0 : RuleBasedTimeZone::completeConst(UErrorCode& status) const {
     153           0 :     if (U_FAILURE(status)) {
     154           0 :         return;
     155             :     }
     156           0 :     umtx_lock(&gLock);
     157           0 :     if (!fUpToDate) {
     158           0 :         RuleBasedTimeZone *ncThis = const_cast<RuleBasedTimeZone*>(this);
     159           0 :         ncThis->complete(status);
     160             :     }
     161           0 :     umtx_unlock(&gLock);
     162             : }
     163             : 
     164             : void
     165           0 : RuleBasedTimeZone::complete(UErrorCode& status) {
     166           0 :     if (U_FAILURE(status)) {
     167           0 :         return;
     168             :     }
     169           0 :     if (fUpToDate) {
     170           0 :         return;
     171             :     }
     172             :     // Make sure either no final rules or a pair of AnnualTimeZoneRules
     173             :     // are available.
     174           0 :     if (fFinalRules != NULL && fFinalRules->size() != 2) {
     175           0 :         status = U_INVALID_STATE_ERROR;
     176           0 :         return;
     177             :     }
     178             : 
     179           0 :     UBool *done = NULL;
     180             :     // Create a TimezoneTransition and add to the list
     181           0 :     if (fHistoricRules != NULL || fFinalRules != NULL) {
     182           0 :         TimeZoneRule *curRule = fInitialRule;
     183           0 :         UDate lastTransitionTime = MIN_MILLIS;
     184             : 
     185             :         // Build the transition array which represents historical time zone
     186             :         // transitions.
     187           0 :         if (fHistoricRules != NULL && fHistoricRules->size() > 0) {
     188             :             int32_t i;
     189           0 :             int32_t historicCount = fHistoricRules->size();
     190           0 :             done = (UBool*)uprv_malloc(sizeof(UBool) * historicCount);
     191           0 :             if (done == NULL) {
     192           0 :                 status = U_MEMORY_ALLOCATION_ERROR;
     193           0 :                 goto cleanup;
     194             :             }
     195           0 :             for (i = 0; i < historicCount; i++) {
     196           0 :                 done[i] = FALSE;
     197             :             }
     198             :             while (TRUE) {
     199           0 :                 int32_t curStdOffset = curRule->getRawOffset();
     200           0 :                 int32_t curDstSavings = curRule->getDSTSavings();
     201           0 :                 UDate nextTransitionTime = MAX_MILLIS;
     202           0 :                 TimeZoneRule *nextRule = NULL;
     203           0 :                 TimeZoneRule *r = NULL;
     204             :                 UBool avail;
     205             :                 UDate tt;
     206           0 :                 UnicodeString curName, name;
     207           0 :                 curRule->getName(curName);
     208             : 
     209           0 :                 for (i = 0; i < historicCount; i++) {
     210           0 :                     if (done[i]) {
     211           0 :                         continue;
     212             :                     }
     213           0 :                     r = (TimeZoneRule*)fHistoricRules->elementAt(i);
     214           0 :                     avail = r->getNextStart(lastTransitionTime, curStdOffset, curDstSavings, false, tt);
     215           0 :                     if (!avail) {
     216             :                         // No more transitions from this rule - skip this rule next time
     217           0 :                         done[i] = TRUE;
     218             :                     } else {
     219           0 :                         r->getName(name);
     220           0 :                         if (*r == *curRule ||
     221           0 :                             (name == curName && r->getRawOffset() == curRule->getRawOffset()
     222           0 :                             && r->getDSTSavings() == curRule->getDSTSavings())) {
     223           0 :                             continue;
     224             :                         }
     225           0 :                         if (tt < nextTransitionTime) {
     226           0 :                             nextTransitionTime = tt;
     227           0 :                             nextRule = r;
     228             :                         }
     229             :                     }
     230             :                 }
     231             : 
     232           0 :                 if (nextRule ==  NULL) {
     233             :                     // Check if all historic rules are done
     234           0 :                     UBool bDoneAll = TRUE;
     235           0 :                     for (int32_t j = 0; j < historicCount; j++) {
     236           0 :                         if (!done[j]) {
     237           0 :                             bDoneAll = FALSE;
     238           0 :                             break;
     239             :                         }
     240             :                     }
     241           0 :                     if (bDoneAll) {
     242           0 :                         break;
     243             :                     }
     244             :                 }
     245             : 
     246           0 :                 if (fFinalRules != NULL) {
     247             :                     // Check if one of final rules has earlier transition date
     248           0 :                     for (i = 0; i < 2 /* fFinalRules->size() */; i++) {
     249           0 :                         TimeZoneRule *fr = (TimeZoneRule*)fFinalRules->elementAt(i);
     250           0 :                         if (*fr == *curRule) {
     251           0 :                             continue;
     252             :                         }
     253           0 :                         r = (TimeZoneRule*)fFinalRules->elementAt(i);
     254           0 :                         avail = r->getNextStart(lastTransitionTime, curStdOffset, curDstSavings, false, tt);
     255           0 :                         if (avail) {
     256           0 :                             if (tt < nextTransitionTime) {
     257           0 :                                 nextTransitionTime = tt;
     258           0 :                                 nextRule = r;
     259             :                             }
     260             :                         }
     261             :                     }
     262             :                 }
     263             : 
     264           0 :                 if (nextRule == NULL) {
     265             :                     // Nothing more
     266           0 :                     break;
     267             :                 }
     268             : 
     269           0 :                 if (fHistoricTransitions == NULL) {
     270           0 :                     fHistoricTransitions = new UVector(status);
     271           0 :                     if (U_FAILURE(status)) {
     272           0 :                         goto cleanup;
     273             :                     }
     274             :                 }
     275           0 :                 Transition *trst = (Transition*)uprv_malloc(sizeof(Transition));
     276           0 :                 if (trst == NULL) {
     277           0 :                     status = U_MEMORY_ALLOCATION_ERROR;
     278           0 :                     goto cleanup;
     279             :                 }
     280           0 :                 trst->time = nextTransitionTime;
     281           0 :                 trst->from = curRule;
     282           0 :                 trst->to = nextRule;
     283           0 :                 fHistoricTransitions->addElement(trst, status);
     284           0 :                 if (U_FAILURE(status)) {
     285           0 :                     goto cleanup;
     286             :                 }
     287           0 :                 lastTransitionTime = nextTransitionTime;
     288           0 :                 curRule = nextRule;
     289           0 :             }
     290             :         }
     291           0 :         if (fFinalRules != NULL) {
     292           0 :             if (fHistoricTransitions == NULL) {
     293           0 :                 fHistoricTransitions = new UVector(status);
     294           0 :                 if (U_FAILURE(status)) {
     295           0 :                     goto cleanup;
     296             :                 }
     297             :             }
     298             :             // Append the first transition for each
     299           0 :             TimeZoneRule *rule0 = (TimeZoneRule*)fFinalRules->elementAt(0);
     300           0 :             TimeZoneRule *rule1 = (TimeZoneRule*)fFinalRules->elementAt(1);
     301             :             UDate tt0, tt1;
     302           0 :             UBool avail0 = rule0->getNextStart(lastTransitionTime, curRule->getRawOffset(), curRule->getDSTSavings(), false, tt0);
     303           0 :             UBool avail1 = rule1->getNextStart(lastTransitionTime, curRule->getRawOffset(), curRule->getDSTSavings(), false, tt1);
     304           0 :             if (!avail0 || !avail1) {
     305             :                 // Should not happen, because both rules are permanent
     306           0 :                 status = U_INVALID_STATE_ERROR;
     307           0 :                 goto cleanup;
     308             :             }
     309           0 :             Transition *final0 = (Transition*)uprv_malloc(sizeof(Transition));
     310           0 :             if (final0 == NULL) {
     311           0 :                 status = U_MEMORY_ALLOCATION_ERROR;
     312           0 :                 goto cleanup;
     313             :             }
     314           0 :             Transition *final1 = (Transition*)uprv_malloc(sizeof(Transition));
     315           0 :             if (final1 == NULL) {
     316           0 :                 uprv_free(final0);
     317           0 :                 status = U_MEMORY_ALLOCATION_ERROR;
     318           0 :                 goto cleanup;
     319             :             }
     320           0 :             if (tt0 < tt1) {
     321           0 :                 final0->time = tt0;
     322           0 :                 final0->from = curRule;
     323           0 :                 final0->to = rule0;
     324           0 :                 rule1->getNextStart(tt0, rule0->getRawOffset(), rule0->getDSTSavings(), false, final1->time);
     325           0 :                 final1->from = rule0;
     326           0 :                 final1->to = rule1;
     327             :             } else {
     328           0 :                 final0->time = tt1;
     329           0 :                 final0->from = curRule;
     330           0 :                 final0->to = rule1;
     331           0 :                 rule0->getNextStart(tt1, rule1->getRawOffset(), rule1->getDSTSavings(), false, final1->time);
     332           0 :                 final1->from = rule1;
     333           0 :                 final1->to = rule0;
     334             :             }
     335           0 :             fHistoricTransitions->addElement(final0, status);
     336           0 :             if (U_FAILURE(status)) {
     337           0 :                 goto cleanup;
     338             :             }
     339           0 :             fHistoricTransitions->addElement(final1, status);
     340           0 :             if (U_FAILURE(status)) {
     341           0 :                 goto cleanup;
     342             :             }
     343             :         }
     344             :     }
     345           0 :     fUpToDate = TRUE;
     346           0 :     if (done != NULL) {
     347           0 :         uprv_free(done);
     348             :     }
     349           0 :     return;
     350             : 
     351             : cleanup:
     352           0 :     deleteTransitions();
     353           0 :     if (done != NULL) {
     354           0 :         uprv_free(done);
     355             :     }
     356           0 :     fUpToDate = FALSE;
     357             : }
     358             : 
     359             : TimeZone*
     360           0 : RuleBasedTimeZone::clone(void) const {
     361           0 :     return new RuleBasedTimeZone(*this);
     362             : }
     363             : 
     364             : int32_t
     365           0 : RuleBasedTimeZone::getOffset(uint8_t era, int32_t year, int32_t month, int32_t day,
     366             :                              uint8_t dayOfWeek, int32_t millis, UErrorCode& status) const {
     367           0 :     if (U_FAILURE(status)) {
     368           0 :         return 0;
     369             :     }
     370           0 :     if (month < UCAL_JANUARY || month > UCAL_DECEMBER) {
     371           0 :         status = U_ILLEGAL_ARGUMENT_ERROR;
     372           0 :         return 0;
     373             :     } else {
     374           0 :         return getOffset(era, year, month, day, dayOfWeek, millis,
     375           0 :                          Grego::monthLength(year, month), status);
     376             :     }
     377             : }
     378             : 
     379             : int32_t
     380           0 : RuleBasedTimeZone::getOffset(uint8_t era, int32_t year, int32_t month, int32_t day,
     381             :                              uint8_t /*dayOfWeek*/, int32_t millis,
     382             :                              int32_t /*monthLength*/, UErrorCode& status) const {
     383             :     // dayOfWeek and monthLength are unused
     384           0 :     if (U_FAILURE(status)) {
     385           0 :         return 0;
     386             :     }
     387           0 :     if (era == GregorianCalendar::BC) {
     388             :         // Convert to extended year
     389           0 :         year = 1 - year;
     390             :     }
     391             :     int32_t rawOffset, dstOffset;
     392           0 :     UDate time = (UDate)Grego::fieldsToDay(year, month, day) * U_MILLIS_PER_DAY + millis;
     393           0 :     getOffsetInternal(time, TRUE, kDaylight, kStandard, rawOffset, dstOffset, status);
     394           0 :     if (U_FAILURE(status)) {
     395           0 :         return 0;
     396             :     }
     397           0 :     return (rawOffset + dstOffset);
     398             : }
     399             : 
     400             : void
     401           0 : RuleBasedTimeZone::getOffset(UDate date, UBool local, int32_t& rawOffset,
     402             :                              int32_t& dstOffset, UErrorCode& status) const {
     403           0 :     getOffsetInternal(date, local, kFormer, kLatter, rawOffset, dstOffset, status);
     404           0 : }
     405             : 
     406             : void
     407           0 : RuleBasedTimeZone::getOffsetFromLocal(UDate date, int32_t nonExistingTimeOpt, int32_t duplicatedTimeOpt,
     408             :                                       int32_t& rawOffset, int32_t& dstOffset, UErrorCode& status) const {
     409           0 :     getOffsetInternal(date, TRUE, nonExistingTimeOpt, duplicatedTimeOpt, rawOffset, dstOffset, status);
     410           0 : }
     411             : 
     412             : 
     413             : /*
     414             :  * The internal getOffset implementation
     415             :  */
     416             : void
     417           0 : RuleBasedTimeZone::getOffsetInternal(UDate date, UBool local,
     418             :                                      int32_t NonExistingTimeOpt, int32_t DuplicatedTimeOpt,
     419             :                                      int32_t& rawOffset, int32_t& dstOffset,
     420             :                                      UErrorCode& status) const {
     421           0 :     rawOffset = 0;
     422           0 :     dstOffset = 0;
     423             : 
     424           0 :     if (U_FAILURE(status)) {
     425           0 :         return;
     426             :     }
     427           0 :     if (!fUpToDate) {
     428             :         // Transitions are not yet resolved.  We cannot do it here
     429             :         // because this method is const.  Thus, do nothing and return
     430             :         // error status.
     431           0 :         status = U_INVALID_STATE_ERROR;
     432           0 :         return;
     433             :     }
     434           0 :     const TimeZoneRule *rule = NULL;
     435           0 :     if (fHistoricTransitions == NULL) {
     436           0 :         rule = fInitialRule;
     437             :     } else {
     438           0 :         UDate tstart = getTransitionTime((Transition*)fHistoricTransitions->elementAt(0),
     439           0 :             local, NonExistingTimeOpt, DuplicatedTimeOpt);
     440           0 :         if (date < tstart) {
     441           0 :             rule = fInitialRule;
     442             :         } else {
     443           0 :             int32_t idx = fHistoricTransitions->size() - 1;
     444           0 :             UDate tend = getTransitionTime((Transition*)fHistoricTransitions->elementAt(idx),
     445           0 :                 local, NonExistingTimeOpt, DuplicatedTimeOpt);
     446           0 :             if (date > tend) {
     447           0 :                 if (fFinalRules != NULL) {
     448           0 :                     rule = findRuleInFinal(date, local, NonExistingTimeOpt, DuplicatedTimeOpt);
     449             :                 }
     450           0 :                 if (rule == NULL) {
     451             :                     // no final rules or the given time is before the first transition
     452             :                     // specified by the final rules -> use the last rule 
     453           0 :                     rule = ((Transition*)fHistoricTransitions->elementAt(idx))->to;
     454             :                 }
     455             :             } else {
     456             :                 // Find a historical transition
     457           0 :                 while (idx >= 0) {
     458           0 :                     if (date >= getTransitionTime((Transition*)fHistoricTransitions->elementAt(idx),
     459             :                         local, NonExistingTimeOpt, DuplicatedTimeOpt)) {
     460           0 :                         break;
     461             :                     }
     462           0 :                     idx--;
     463             :                 }
     464           0 :                 rule = ((Transition*)fHistoricTransitions->elementAt(idx))->to;
     465             :             }
     466             :         }
     467             :     }
     468           0 :     if (rule != NULL) {
     469           0 :         rawOffset = rule->getRawOffset();
     470           0 :         dstOffset = rule->getDSTSavings();
     471             :     }
     472             : }
     473             : 
     474             : void
     475           0 : RuleBasedTimeZone::setRawOffset(int32_t /*offsetMillis*/) {
     476             :     // We don't support this operation at this moment.
     477             :     // Nothing to do!
     478           0 : }
     479             : 
     480             : int32_t
     481           0 : RuleBasedTimeZone::getRawOffset(void) const {
     482             :     // Note: This implementation returns standard GMT offset
     483             :     // as of current time.
     484           0 :     UErrorCode status = U_ZERO_ERROR;
     485             :     int32_t raw, dst;
     486           0 :     getOffset(uprv_getUTCtime() * U_MILLIS_PER_SECOND,
     487           0 :         FALSE, raw, dst, status);
     488           0 :     return raw;
     489             : }
     490             : 
     491             : UBool
     492           0 : RuleBasedTimeZone::useDaylightTime(void) const {
     493             :     // Note: This implementation returns true when
     494             :     // daylight saving time is used as of now or
     495             :     // after the next transition.
     496           0 :     UErrorCode status = U_ZERO_ERROR;
     497           0 :     UDate now = uprv_getUTCtime() * U_MILLIS_PER_SECOND;
     498             :     int32_t raw, dst;
     499           0 :     getOffset(now, FALSE, raw, dst, status);
     500           0 :     if (dst != 0) {
     501           0 :         return TRUE;
     502             :     }
     503             :     // If DST is not used now, check if DST is used after the next transition
     504             :     UDate time;
     505             :     TimeZoneRule *from, *to;
     506           0 :     UBool avail = findNext(now, FALSE, time, from, to);
     507           0 :     if (avail && to->getDSTSavings() != 0) {
     508           0 :         return TRUE;
     509             :     }
     510           0 :     return FALSE;
     511             : }
     512             : 
     513             : UBool
     514           0 : RuleBasedTimeZone::inDaylightTime(UDate date, UErrorCode& status) const {
     515           0 :     if (U_FAILURE(status)) {
     516           0 :         return FALSE;
     517             :     }
     518             :     int32_t raw, dst;
     519           0 :     getOffset(date, FALSE, raw, dst, status);
     520           0 :     if (dst != 0) {
     521           0 :         return TRUE;
     522             :     }
     523           0 :     return FALSE;
     524             : }
     525             : 
     526             : UBool
     527           0 : RuleBasedTimeZone::hasSameRules(const TimeZone& other) const {
     528           0 :     if (this == &other) {
     529           0 :         return TRUE;
     530             :     }
     531           0 :     if (typeid(*this) != typeid(other)) {
     532           0 :         return FALSE;
     533             :     }
     534           0 :     const RuleBasedTimeZone& that = (const RuleBasedTimeZone&)other;
     535           0 :     if (*fInitialRule != *(that.fInitialRule)) {
     536           0 :         return FALSE;
     537             :     }
     538           0 :     if (compareRules(fHistoricRules, that.fHistoricRules)
     539           0 :         && compareRules(fFinalRules, that.fFinalRules)) {
     540           0 :         return TRUE;
     541             :     }
     542           0 :     return FALSE;
     543             : }
     544             : 
     545             : UBool
     546           0 : RuleBasedTimeZone::getNextTransition(UDate base, UBool inclusive, TimeZoneTransition& result) const {
     547           0 :     UErrorCode status = U_ZERO_ERROR;
     548           0 :     completeConst(status);
     549           0 :     if (U_FAILURE(status)) {
     550           0 :         return FALSE;
     551             :     }
     552             :     UDate transitionTime;
     553             :     TimeZoneRule *fromRule, *toRule;
     554           0 :     UBool found = findNext(base, inclusive, transitionTime, fromRule, toRule);
     555           0 :     if (found) {
     556           0 :         result.setTime(transitionTime);
     557           0 :         result.setFrom((const TimeZoneRule&)*fromRule);
     558           0 :         result.setTo((const TimeZoneRule&)*toRule);
     559           0 :         return TRUE;
     560             :     }
     561           0 :     return FALSE;
     562             : }
     563             : 
     564             : UBool
     565           0 : RuleBasedTimeZone::getPreviousTransition(UDate base, UBool inclusive, TimeZoneTransition& result) const {
     566           0 :     UErrorCode status = U_ZERO_ERROR;
     567           0 :     completeConst(status);
     568           0 :     if (U_FAILURE(status)) {
     569           0 :         return FALSE;
     570             :     }
     571             :     UDate transitionTime;
     572             :     TimeZoneRule *fromRule, *toRule;
     573           0 :     UBool found = findPrev(base, inclusive, transitionTime, fromRule, toRule);
     574           0 :     if (found) {
     575           0 :         result.setTime(transitionTime);
     576           0 :         result.setFrom((const TimeZoneRule&)*fromRule);
     577           0 :         result.setTo((const TimeZoneRule&)*toRule);
     578           0 :         return TRUE;
     579             :     }
     580           0 :     return FALSE;
     581             : }
     582             : 
     583             : int32_t
     584           0 : RuleBasedTimeZone::countTransitionRules(UErrorCode& /*status*/) const {
     585           0 :     int32_t count = 0;
     586           0 :     if (fHistoricRules != NULL) {
     587           0 :         count += fHistoricRules->size();
     588             :     }
     589           0 :     if (fFinalRules != NULL) {
     590           0 :         count += fFinalRules->size();
     591             :     }
     592           0 :     return count;
     593             : }
     594             : 
     595             : void
     596           0 : RuleBasedTimeZone::getTimeZoneRules(const InitialTimeZoneRule*& initial,
     597             :                                     const TimeZoneRule* trsrules[],
     598             :                                     int32_t& trscount,
     599             :                                     UErrorCode& status) const {
     600           0 :     if (U_FAILURE(status)) {
     601           0 :         return;
     602             :     }
     603             :     // Initial rule
     604           0 :     initial = fInitialRule;
     605             : 
     606             :     // Transition rules
     607           0 :     int32_t cnt = 0;
     608             :     int32_t idx;
     609           0 :     if (fHistoricRules != NULL && cnt < trscount) {
     610           0 :         int32_t historicCount = fHistoricRules->size();
     611           0 :         idx = 0;
     612           0 :         while (cnt < trscount && idx < historicCount) {
     613           0 :             trsrules[cnt++] = (const TimeZoneRule*)fHistoricRules->elementAt(idx++);
     614             :         }
     615             :     }
     616           0 :     if (fFinalRules != NULL && cnt < trscount) {
     617           0 :         int32_t finalCount = fFinalRules->size();
     618           0 :         idx = 0;
     619           0 :         while (cnt < trscount && idx < finalCount) {
     620           0 :             trsrules[cnt++] = (const TimeZoneRule*)fFinalRules->elementAt(idx++);
     621             :         }
     622             :     }
     623             :     // Set the result length
     624           0 :     trscount = cnt;
     625             : }
     626             : 
     627             : void
     628           0 : RuleBasedTimeZone::deleteRules(void) {
     629           0 :     delete fInitialRule;
     630           0 :     fInitialRule = NULL;
     631           0 :     if (fHistoricRules != NULL) {
     632           0 :         while (!fHistoricRules->isEmpty()) {
     633           0 :             delete (TimeZoneRule*)(fHistoricRules->orphanElementAt(0));
     634             :         }
     635           0 :         delete fHistoricRules;
     636           0 :         fHistoricRules = NULL;
     637             :     }
     638           0 :     if (fFinalRules != NULL) {
     639           0 :         while (!fFinalRules->isEmpty()) {
     640           0 :             delete (AnnualTimeZoneRule*)(fFinalRules->orphanElementAt(0));
     641             :         }
     642           0 :         delete fFinalRules;
     643           0 :         fFinalRules = NULL;
     644             :     }
     645           0 : }
     646             : 
     647             : void
     648           0 : RuleBasedTimeZone::deleteTransitions(void) {
     649           0 :     if (fHistoricTransitions != NULL) {
     650           0 :         while (!fHistoricTransitions->isEmpty()) {
     651           0 :             Transition *trs = (Transition*)fHistoricTransitions->orphanElementAt(0);
     652           0 :             uprv_free(trs);
     653             :         }
     654           0 :         delete fHistoricTransitions;
     655             :     }
     656           0 :     fHistoricTransitions = NULL;
     657           0 : }
     658             : 
     659             : UVector*
     660           0 : RuleBasedTimeZone::copyRules(UVector* source) {
     661           0 :     if (source == NULL) {
     662           0 :         return NULL;
     663             :     }
     664           0 :     UErrorCode ec = U_ZERO_ERROR;
     665           0 :     int32_t size = source->size();
     666           0 :     UVector *rules = new UVector(size, ec);
     667           0 :     if (U_FAILURE(ec)) {
     668           0 :         return NULL;
     669             :     }
     670             :     int32_t i;
     671           0 :     for (i = 0; i < size; i++) {
     672           0 :         rules->addElement(((TimeZoneRule*)source->elementAt(i))->clone(), ec);
     673           0 :         if (U_FAILURE(ec)) {
     674           0 :             break;
     675             :         }
     676             :     }
     677           0 :     if (U_FAILURE(ec)) {
     678             :         // In case of error, clean up
     679           0 :         for (i = 0; i < rules->size(); i++) {
     680           0 :             TimeZoneRule *rule = (TimeZoneRule*)rules->orphanElementAt(i);
     681           0 :             delete rule;
     682             :         }
     683           0 :         delete rules;
     684           0 :         return NULL;
     685             :     }
     686           0 :     return rules;
     687             : }
     688             : 
     689             : TimeZoneRule*
     690           0 : RuleBasedTimeZone::findRuleInFinal(UDate date, UBool local,
     691             :                                    int32_t NonExistingTimeOpt, int32_t DuplicatedTimeOpt) const {
     692           0 :     if (fFinalRules == NULL) {
     693           0 :         return NULL;
     694             :     }
     695             : 
     696           0 :     AnnualTimeZoneRule* fr0 = (AnnualTimeZoneRule*)fFinalRules->elementAt(0);
     697           0 :     AnnualTimeZoneRule* fr1 = (AnnualTimeZoneRule*)fFinalRules->elementAt(1);
     698           0 :     if (fr0 == NULL || fr1 == NULL) {
     699           0 :         return NULL;
     700             :     }
     701             : 
     702             :     UDate start0, start1;
     703             :     UDate base;
     704             :     int32_t localDelta;
     705             : 
     706           0 :     base = date;
     707           0 :     if (local) {
     708           0 :         localDelta = getLocalDelta(fr1->getRawOffset(), fr1->getDSTSavings(),
     709             :                                    fr0->getRawOffset(), fr0->getDSTSavings(),
     710           0 :                                    NonExistingTimeOpt, DuplicatedTimeOpt);
     711           0 :         base -= localDelta;
     712             :     }
     713           0 :     UBool avail0 = fr0->getPreviousStart(base, fr1->getRawOffset(), fr1->getDSTSavings(), TRUE, start0);
     714             : 
     715           0 :     base = date;
     716           0 :     if (local) {
     717           0 :         localDelta = getLocalDelta(fr0->getRawOffset(), fr0->getDSTSavings(),
     718             :                                    fr1->getRawOffset(), fr1->getDSTSavings(),
     719           0 :                                    NonExistingTimeOpt, DuplicatedTimeOpt);
     720           0 :         base -= localDelta;
     721             :     }
     722           0 :     UBool avail1 = fr1->getPreviousStart(base, fr0->getRawOffset(), fr0->getDSTSavings(), TRUE, start1);
     723             : 
     724           0 :     if (!avail0 || !avail1) {
     725           0 :         if (avail0) {
     726           0 :             return fr0;
     727           0 :         } else if (avail1) {
     728           0 :             return fr1;
     729             :         }
     730             :         // Both rules take effect after the given time
     731           0 :         return NULL;
     732             :     }
     733             : 
     734           0 :     return (start0 > start1) ? fr0 : fr1;
     735             : }
     736             : 
     737             : UBool
     738           0 : RuleBasedTimeZone::findNext(UDate base, UBool inclusive, UDate& transitionTime,
     739             :                             TimeZoneRule*& fromRule, TimeZoneRule*& toRule) const {
     740           0 :     if (fHistoricTransitions == NULL) {
     741           0 :         return FALSE;
     742             :     }
     743           0 :     UBool isFinal = FALSE;
     744           0 :     UBool found = FALSE;
     745             :     Transition result;
     746           0 :     Transition *tzt = (Transition*)fHistoricTransitions->elementAt(0);
     747           0 :     UDate tt = tzt->time;
     748           0 :     if (tt > base || (inclusive && tt == base)) {
     749           0 :         result = *tzt;
     750           0 :         found = TRUE;
     751             :     } else {
     752           0 :         int32_t idx = fHistoricTransitions->size() - 1;        
     753           0 :         tzt = (Transition*)fHistoricTransitions->elementAt(idx);
     754           0 :         tt = tzt->time;
     755           0 :         if (inclusive && tt == base) {
     756           0 :             result = *tzt;
     757           0 :             found = TRUE;
     758           0 :         } else if (tt <= base) {
     759           0 :             if (fFinalRules != NULL) {
     760             :                 // Find a transion time with finalRules
     761           0 :                 TimeZoneRule *r0 = (TimeZoneRule*)fFinalRules->elementAt(0);
     762           0 :                 TimeZoneRule *r1 = (TimeZoneRule*)fFinalRules->elementAt(1);
     763             :                 UDate start0, start1;
     764           0 :                 UBool avail0 = r0->getNextStart(base, r1->getRawOffset(), r1->getDSTSavings(), inclusive, start0);
     765           0 :                 UBool avail1 = r1->getNextStart(base, r0->getRawOffset(), r0->getDSTSavings(), inclusive, start1);
     766             :                 //  avail0/avail1 should be always TRUE
     767           0 :                 if (!avail0 && !avail1) {
     768           0 :                     return FALSE;
     769             :                 }
     770           0 :                 if (!avail1 || start0 < start1) {
     771           0 :                     result.time = start0;
     772           0 :                     result.from = r1;
     773           0 :                     result.to = r0;
     774             :                 } else {
     775           0 :                     result.time = start1;
     776           0 :                     result.from = r0;
     777           0 :                     result.to = r1;
     778             :                 }
     779           0 :                 isFinal = TRUE;
     780           0 :                 found = TRUE;
     781             :             }
     782             :         } else {
     783             :             // Find a transition within the historic transitions
     784           0 :             idx--;
     785           0 :             Transition *prev = tzt;
     786           0 :             while (idx > 0) {
     787           0 :                 tzt = (Transition*)fHistoricTransitions->elementAt(idx);
     788           0 :                 tt = tzt->time;
     789           0 :                 if (tt < base || (!inclusive && tt == base)) {
     790             :                     break;
     791             :                 }
     792           0 :                 idx--;
     793           0 :                 prev = tzt;
     794             :             }
     795           0 :             result.time = prev->time;
     796           0 :             result.from = prev->from;
     797           0 :             result.to = prev->to;
     798           0 :             found = TRUE;
     799             :         }
     800             :     }
     801           0 :     if (found) {
     802             :         // For now, this implementation ignore transitions with only zone name changes.
     803           0 :         if (result.from->getRawOffset() == result.to->getRawOffset()
     804           0 :             && result.from->getDSTSavings() == result.to->getDSTSavings()) {
     805           0 :             if (isFinal) {
     806           0 :                 return FALSE;
     807             :             } else {
     808             :                 // No offset changes.  Try next one if not final
     809           0 :                 return findNext(result.time, FALSE /* always exclusive */,
     810           0 :                     transitionTime, fromRule, toRule);
     811             :             }
     812             :         }
     813           0 :         transitionTime = result.time;
     814           0 :         fromRule = result.from;
     815           0 :         toRule = result.to;
     816           0 :         return TRUE;
     817             :     }
     818           0 :     return FALSE;
     819             : }
     820             : 
     821             : UBool
     822           0 : RuleBasedTimeZone::findPrev(UDate base, UBool inclusive, UDate& transitionTime,
     823             :                             TimeZoneRule*& fromRule, TimeZoneRule*& toRule) const {
     824           0 :     if (fHistoricTransitions == NULL) {
     825           0 :         return FALSE;
     826             :     }
     827           0 :     UBool found = FALSE;
     828             :     Transition result;
     829           0 :     Transition *tzt = (Transition*)fHistoricTransitions->elementAt(0);
     830           0 :     UDate tt = tzt->time;
     831           0 :     if (inclusive && tt == base) {
     832           0 :         result = *tzt;
     833           0 :         found = TRUE;
     834           0 :     } else if (tt < base) {
     835           0 :         int32_t idx = fHistoricTransitions->size() - 1;        
     836           0 :         tzt = (Transition*)fHistoricTransitions->elementAt(idx);
     837           0 :         tt = tzt->time;
     838           0 :         if (inclusive && tt == base) {
     839           0 :             result = *tzt;
     840           0 :             found = TRUE;
     841           0 :         } else if (tt < base) {
     842           0 :             if (fFinalRules != NULL) {
     843             :                 // Find a transion time with finalRules
     844           0 :                 TimeZoneRule *r0 = (TimeZoneRule*)fFinalRules->elementAt(0);
     845           0 :                 TimeZoneRule *r1 = (TimeZoneRule*)fFinalRules->elementAt(1);
     846             :                 UDate start0, start1;
     847           0 :                 UBool avail0 = r0->getPreviousStart(base, r1->getRawOffset(), r1->getDSTSavings(), inclusive, start0);
     848           0 :                 UBool avail1 = r1->getPreviousStart(base, r0->getRawOffset(), r0->getDSTSavings(), inclusive, start1);
     849             :                 //  avail0/avail1 should be always TRUE
     850           0 :                 if (!avail0 && !avail1) {
     851           0 :                     return FALSE;
     852             :                 }
     853           0 :                 if (!avail1 || start0 > start1) {
     854           0 :                     result.time = start0;
     855           0 :                     result.from = r1;
     856           0 :                     result.to = r0;
     857             :                 } else {
     858           0 :                     result.time = start1;
     859           0 :                     result.from = r0;
     860           0 :                     result.to = r1;
     861             :                 }
     862             :             } else {
     863           0 :                 result = *tzt;
     864             :             }
     865           0 :             found = TRUE;
     866             :         } else {
     867             :             // Find a transition within the historic transitions
     868           0 :             idx--;
     869           0 :             while (idx >= 0) {
     870           0 :                 tzt = (Transition*)fHistoricTransitions->elementAt(idx);
     871           0 :                 tt = tzt->time;
     872           0 :                 if (tt < base || (inclusive && tt == base)) {
     873             :                     break;
     874             :                 }
     875           0 :                 idx--;
     876             :             }
     877           0 :             result = *tzt;
     878           0 :             found = TRUE;
     879             :         }
     880             :     }
     881           0 :     if (found) {
     882             :         // For now, this implementation ignore transitions with only zone name changes.
     883           0 :         if (result.from->getRawOffset() == result.to->getRawOffset()
     884           0 :             && result.from->getDSTSavings() == result.to->getDSTSavings()) {
     885             :             // No offset changes.  Try next one if not final
     886           0 :             return findPrev(result.time, FALSE /* always exclusive */,
     887           0 :                 transitionTime, fromRule, toRule);
     888             :         }
     889           0 :         transitionTime = result.time;
     890           0 :         fromRule = result.from;
     891           0 :         toRule = result.to;
     892           0 :         return TRUE;
     893             :     }
     894           0 :     return FALSE;
     895             : }
     896             : 
     897             : UDate
     898           0 : RuleBasedTimeZone::getTransitionTime(Transition* transition, UBool local,
     899             :                                      int32_t NonExistingTimeOpt, int32_t DuplicatedTimeOpt) const {
     900           0 :     UDate time = transition->time;
     901           0 :     if (local) {
     902           0 :         time += getLocalDelta(transition->from->getRawOffset(), transition->from->getDSTSavings(),
     903           0 :                               transition->to->getRawOffset(), transition->to->getDSTSavings(),
     904           0 :                               NonExistingTimeOpt, DuplicatedTimeOpt);
     905             :     }
     906           0 :     return time;
     907             : }
     908             : 
     909             : int32_t
     910           0 : RuleBasedTimeZone::getLocalDelta(int32_t rawBefore, int32_t dstBefore, int32_t rawAfter, int32_t dstAfter,
     911             :                              int32_t NonExistingTimeOpt, int32_t DuplicatedTimeOpt) const {
     912           0 :     int32_t delta = 0;
     913             : 
     914           0 :     int32_t offsetBefore = rawBefore + dstBefore;
     915           0 :     int32_t offsetAfter = rawAfter + dstAfter;
     916             : 
     917           0 :     UBool dstToStd = (dstBefore != 0) && (dstAfter == 0);
     918           0 :     UBool stdToDst = (dstBefore == 0) && (dstAfter != 0);
     919             : 
     920           0 :     if (offsetAfter - offsetBefore >= 0) {
     921             :         // Positive transition, which makes a non-existing local time range
     922           0 :         if (((NonExistingTimeOpt & kStdDstMask) == kStandard && dstToStd)
     923           0 :                 || ((NonExistingTimeOpt & kStdDstMask) == kDaylight && stdToDst)) {
     924           0 :             delta = offsetBefore;
     925           0 :         } else if (((NonExistingTimeOpt & kStdDstMask) == kStandard && stdToDst)
     926           0 :                 || ((NonExistingTimeOpt & kStdDstMask) == kDaylight && dstToStd)) {
     927           0 :             delta = offsetAfter;
     928           0 :         } else if ((NonExistingTimeOpt & kFormerLatterMask) == kLatter) {
     929           0 :             delta = offsetBefore;
     930             :         } else {
     931             :             // Interprets the time with rule before the transition,
     932             :             // default for non-existing time range
     933           0 :             delta = offsetAfter;
     934             :         }
     935             :     } else {
     936             :         // Negative transition, which makes a duplicated local time range
     937           0 :         if (((DuplicatedTimeOpt & kStdDstMask) == kStandard && dstToStd)
     938           0 :                 || ((DuplicatedTimeOpt & kStdDstMask) == kDaylight && stdToDst)) {
     939           0 :             delta = offsetAfter;
     940           0 :         } else if (((DuplicatedTimeOpt & kStdDstMask) == kStandard && stdToDst)
     941           0 :                 || ((DuplicatedTimeOpt & kStdDstMask) == kDaylight && dstToStd)) {
     942           0 :             delta = offsetBefore;
     943           0 :         } else if ((DuplicatedTimeOpt & kFormerLatterMask) == kFormer) {
     944           0 :             delta = offsetBefore;
     945             :         } else {
     946             :             // Interprets the time with rule after the transition,
     947             :             // default for duplicated local time range
     948           0 :             delta = offsetAfter;
     949             :         }
     950             :     }
     951           0 :     return delta;
     952             : }
     953             : 
     954             : U_NAMESPACE_END
     955             : 
     956             : #endif /* #if !UCONFIG_NO_FORMATTING */
     957             : 
     958             : //eof
     959             : 

Generated by: LCOV version 1.13