LCOV - code coverage report
Current view: top level - intl/icu/source/i18n - olsontz.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 536 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 32 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) 2003-2013, International Business Machines
       6             : * Corporation and others.  All Rights Reserved.
       7             : **********************************************************************
       8             : * Author: Alan Liu
       9             : * Created: July 21 2003
      10             : * Since: ICU 2.8
      11             : **********************************************************************
      12             : */
      13             : 
      14             : #include "utypeinfo.h"  // for 'typeid' to work
      15             : 
      16             : #include "olsontz.h"
      17             : 
      18             : #if !UCONFIG_NO_FORMATTING
      19             : 
      20             : #include "unicode/ures.h"
      21             : #include "unicode/simpletz.h"
      22             : #include "unicode/gregocal.h"
      23             : #include "gregoimp.h"
      24             : #include "cmemory.h"
      25             : #include "uassert.h"
      26             : #include "uvector.h"
      27             : #include <float.h> // DBL_MAX
      28             : #include "uresimp.h" // struct UResourceBundle
      29             : #include "zonemeta.h"
      30             : #include "umutex.h"
      31             : 
      32             : #ifdef U_DEBUG_TZ
      33             : # include <stdio.h>
      34             : # include "uresimp.h" // for debugging
      35             : 
      36             : static void debug_tz_loc(const char *f, int32_t l)
      37             : {
      38             :   fprintf(stderr, "%s:%d: ", f, l);
      39             : }
      40             : 
      41             : static void debug_tz_msg(const char *pat, ...)
      42             : {
      43             :   va_list ap;
      44             :   va_start(ap, pat);
      45             :   vfprintf(stderr, pat, ap);
      46             :   fflush(stderr);
      47             : }
      48             : // must use double parens, i.e.:  U_DEBUG_TZ_MSG(("four is: %d",4));
      49             : #define U_DEBUG_TZ_MSG(x) {debug_tz_loc(__FILE__,__LINE__);debug_tz_msg x;}
      50             : #else
      51             : #define U_DEBUG_TZ_MSG(x)
      52             : #endif
      53             : 
      54           0 : static UBool arrayEqual(const void *a1, const void *a2, int32_t size) {
      55           0 :     if (a1 == NULL && a2 == NULL) {
      56           0 :         return TRUE;
      57             :     }
      58           0 :     if ((a1 != NULL && a2 == NULL) || (a1 == NULL && a2 != NULL)) {
      59           0 :         return FALSE;
      60             :     }
      61           0 :     if (a1 == a2) {
      62           0 :         return TRUE;
      63             :     }
      64             : 
      65           0 :     return (uprv_memcmp(a1, a2, size) == 0);
      66             : }
      67             : 
      68             : U_NAMESPACE_BEGIN
      69             : 
      70             : #define kTRANS          "trans"
      71             : #define kTRANSPRE32     "transPre32"
      72             : #define kTRANSPOST32    "transPost32"
      73             : #define kTYPEOFFSETS    "typeOffsets"
      74             : #define kTYPEMAP        "typeMap"
      75             : #define kLINKS          "links"
      76             : #define kFINALRULE      "finalRule"
      77             : #define kFINALRAW       "finalRaw"
      78             : #define kFINALYEAR      "finalYear"
      79             : 
      80             : #define SECONDS_PER_DAY (24*60*60)
      81             : 
      82             : static const int32_t ZEROS[] = {0,0};
      83             : 
      84           0 : UOBJECT_DEFINE_RTTI_IMPLEMENTATION(OlsonTimeZone)
      85             : 
      86             : /**
      87             :  * Default constructor.  Creates a time zone with an empty ID and
      88             :  * a fixed GMT offset of zero.
      89             :  */
      90             : /*OlsonTimeZone::OlsonTimeZone() : finalYear(INT32_MAX), finalMillis(DBL_MAX), finalZone(0), transitionRulesInitialized(FALSE) {
      91             :     clearTransitionRules();
      92             :     constructEmpty();
      93             : }*/
      94             : 
      95             : /**
      96             :  * Construct a GMT+0 zone with no transitions.  This is done when a
      97             :  * constructor fails so the resultant object is well-behaved.
      98             :  */
      99           0 : void OlsonTimeZone::constructEmpty() {
     100           0 :     canonicalID = NULL;
     101             : 
     102           0 :     transitionCountPre32 = transitionCount32 = transitionCountPost32 = 0;
     103           0 :     transitionTimesPre32 = transitionTimes32 = transitionTimesPost32 = NULL;
     104             : 
     105           0 :     typeMapData = NULL;
     106             : 
     107           0 :     typeCount = 1;
     108           0 :     typeOffsets = ZEROS;
     109             : 
     110           0 :     finalZone = NULL;
     111           0 : }
     112             : 
     113             : /**
     114             :  * Construct from a resource bundle
     115             :  * @param top the top-level zoneinfo resource bundle.  This is used
     116             :  * to lookup the rule that `res' may refer to, if there is one.
     117             :  * @param res the resource bundle of the zone to be constructed
     118             :  * @param ec input-output error code
     119             :  */
     120           0 : OlsonTimeZone::OlsonTimeZone(const UResourceBundle* top,
     121             :                              const UResourceBundle* res,
     122             :                              const UnicodeString& tzid,
     123           0 :                              UErrorCode& ec) :
     124           0 :   BasicTimeZone(tzid), finalZone(NULL)
     125             : {
     126           0 :     clearTransitionRules();
     127             :     U_DEBUG_TZ_MSG(("OlsonTimeZone(%s)\n", ures_getKey((UResourceBundle*)res)));
     128           0 :     if ((top == NULL || res == NULL) && U_SUCCESS(ec)) {
     129           0 :         ec = U_ILLEGAL_ARGUMENT_ERROR;
     130             :     }
     131           0 :     if (U_SUCCESS(ec)) {
     132             :         // TODO -- clean up -- Doesn't work if res points to an alias
     133             :         //        // TODO remove nonconst casts below when ures_* API is fixed
     134             :         //        setID(ures_getKey((UResourceBundle*) res)); // cast away const
     135             : 
     136             :         int32_t len;
     137             :         UResourceBundle r;
     138           0 :         ures_initStackObject(&r);
     139             : 
     140             :         // Pre-32bit second transitions
     141           0 :         ures_getByKey(res, kTRANSPRE32, &r, &ec);
     142           0 :         transitionTimesPre32 = ures_getIntVector(&r, &len, &ec);
     143           0 :         transitionCountPre32 = len >> 1;
     144           0 :         if (ec == U_MISSING_RESOURCE_ERROR) {
     145             :             // No pre-32bit transitions
     146           0 :             transitionTimesPre32 = NULL;
     147           0 :             transitionCountPre32 = 0;
     148           0 :             ec = U_ZERO_ERROR;
     149           0 :         } else if (U_SUCCESS(ec) && (len < 0 || len > 0x7FFF || (len & 1) != 0) /* len must be even */) {
     150           0 :             ec = U_INVALID_FORMAT_ERROR;
     151             :         }
     152             : 
     153             :         // 32bit second transitions
     154           0 :         ures_getByKey(res, kTRANS, &r, &ec);
     155           0 :         transitionTimes32 = ures_getIntVector(&r, &len, &ec);
     156           0 :         transitionCount32 = len;
     157           0 :         if (ec == U_MISSING_RESOURCE_ERROR) {
     158             :             // No 32bit transitions
     159           0 :             transitionTimes32 = NULL;
     160           0 :             transitionCount32 = 0;
     161           0 :             ec = U_ZERO_ERROR;
     162           0 :         } else if (U_SUCCESS(ec) && (len < 0 || len > 0x7FFF)) {
     163           0 :             ec = U_INVALID_FORMAT_ERROR;
     164             :         }
     165             : 
     166             :         // Post-32bit second transitions
     167           0 :         ures_getByKey(res, kTRANSPOST32, &r, &ec);
     168           0 :         transitionTimesPost32 = ures_getIntVector(&r, &len, &ec);
     169           0 :         transitionCountPost32 = len >> 1;
     170           0 :         if (ec == U_MISSING_RESOURCE_ERROR) {
     171             :             // No pre-32bit transitions
     172           0 :             transitionTimesPost32 = NULL;
     173           0 :             transitionCountPost32 = 0;
     174           0 :             ec = U_ZERO_ERROR;
     175           0 :         } else if (U_SUCCESS(ec) && (len < 0 || len > 0x7FFF || (len & 1) != 0) /* len must be even */) {
     176           0 :             ec = U_INVALID_FORMAT_ERROR;
     177             :         }
     178             : 
     179             :         // Type offsets list must be of even size, with size >= 2
     180           0 :         ures_getByKey(res, kTYPEOFFSETS, &r, &ec);
     181           0 :         typeOffsets = ures_getIntVector(&r, &len, &ec);
     182           0 :         if (U_SUCCESS(ec) && (len < 2 || len > 0x7FFE || (len & 1) != 0)) {
     183           0 :             ec = U_INVALID_FORMAT_ERROR;
     184             :         }
     185           0 :         typeCount = (int16_t) len >> 1;
     186             : 
     187             :         // Type map data must be of the same size as the transition count
     188           0 :         typeMapData =  NULL;
     189           0 :         if (transitionCount() > 0) {
     190           0 :             ures_getByKey(res, kTYPEMAP, &r, &ec);
     191           0 :             typeMapData = ures_getBinary(&r, &len, &ec);
     192           0 :             if (ec == U_MISSING_RESOURCE_ERROR) {
     193             :                 // no type mapping data
     194           0 :                 ec = U_INVALID_FORMAT_ERROR;
     195           0 :             } else if (U_SUCCESS(ec) && len != transitionCount()) {
     196           0 :                 ec = U_INVALID_FORMAT_ERROR;
     197             :             }
     198             :         }
     199             : 
     200             :         // Process final rule and data, if any
     201           0 :         const UChar *ruleIdUStr = ures_getStringByKey(res, kFINALRULE, &len, &ec);
     202           0 :         ures_getByKey(res, kFINALRAW, &r, &ec);
     203           0 :         int32_t ruleRaw = ures_getInt(&r, &ec);
     204           0 :         ures_getByKey(res, kFINALYEAR, &r, &ec);
     205           0 :         int32_t ruleYear = ures_getInt(&r, &ec);
     206           0 :         if (U_SUCCESS(ec)) {
     207           0 :             UnicodeString ruleID(TRUE, ruleIdUStr, len);
     208           0 :             UResourceBundle *rule = TimeZone::loadRule(top, ruleID, NULL, ec);
     209           0 :             const int32_t *ruleData = ures_getIntVector(rule, &len, &ec); 
     210           0 :             if (U_SUCCESS(ec) && len == 11) {
     211           0 :                 UnicodeString emptyStr;
     212           0 :                 finalZone = new SimpleTimeZone(
     213             :                     ruleRaw * U_MILLIS_PER_SECOND,
     214             :                     emptyStr,
     215           0 :                     (int8_t)ruleData[0], (int8_t)ruleData[1], (int8_t)ruleData[2],
     216           0 :                     ruleData[3] * U_MILLIS_PER_SECOND,
     217           0 :                     (SimpleTimeZone::TimeMode) ruleData[4],
     218           0 :                     (int8_t)ruleData[5], (int8_t)ruleData[6], (int8_t)ruleData[7],
     219           0 :                     ruleData[8] * U_MILLIS_PER_SECOND,
     220           0 :                     (SimpleTimeZone::TimeMode) ruleData[9],
     221           0 :                     ruleData[10] * U_MILLIS_PER_SECOND, ec);
     222           0 :                 if (finalZone == NULL) {
     223           0 :                     ec = U_MEMORY_ALLOCATION_ERROR;
     224             :                 } else {
     225           0 :                     finalStartYear = ruleYear;
     226             : 
     227             :                     // Note: Setting finalStartYear to the finalZone is problematic.  When a date is around
     228             :                     // year boundary, SimpleTimeZone may return false result when DST is observed at the 
     229             :                     // beginning of year.  We could apply safe margin (day or two), but when one of recurrent
     230             :                     // rules falls around year boundary, it could return false result.  Without setting the
     231             :                     // start year, finalZone works fine around the year boundary of the start year.
     232             : 
     233             :                     // finalZone->setStartYear(finalStartYear);
     234             : 
     235             : 
     236             :                     // Compute the millis for Jan 1, 0:00 GMT of the finalYear
     237             : 
     238             :                     // Note: finalStartMillis is used for detecting either if
     239             :                     // historic transition data or finalZone to be used.  In an
     240             :                     // extreme edge case - for example, two transitions fall into
     241             :                     // small windows of time around the year boundary, this may
     242             :                     // result incorrect offset computation.  But I think it will
     243             :                     // never happen practically.  Yoshito - Feb 20, 2010
     244           0 :                     finalStartMillis = Grego::fieldsToDay(finalStartYear, 0, 1) * U_MILLIS_PER_DAY;
     245             :                 }
     246             :             } else {
     247           0 :                 ec = U_INVALID_FORMAT_ERROR;
     248             :             }
     249           0 :             ures_close(rule);
     250           0 :         } else if (ec == U_MISSING_RESOURCE_ERROR) {
     251             :             // No final zone
     252           0 :             ec = U_ZERO_ERROR;
     253             :         }
     254           0 :         ures_close(&r);
     255             : 
     256             :         // initialize canonical ID
     257           0 :         canonicalID = ZoneMeta::getCanonicalCLDRID(tzid, ec);
     258             :     }
     259             : 
     260           0 :     if (U_FAILURE(ec)) {
     261           0 :         constructEmpty();
     262             :     }
     263           0 : }
     264             : 
     265             : /**
     266             :  * Copy constructor
     267             :  */
     268           0 : OlsonTimeZone::OlsonTimeZone(const OlsonTimeZone& other) :
     269           0 :     BasicTimeZone(other), finalZone(0) {
     270           0 :     *this = other;
     271           0 : }
     272             : 
     273             : /**
     274             :  * Assignment operator
     275             :  */
     276           0 : OlsonTimeZone& OlsonTimeZone::operator=(const OlsonTimeZone& other) {
     277           0 :     canonicalID = other.canonicalID;
     278             : 
     279           0 :     transitionTimesPre32 = other.transitionTimesPre32;
     280           0 :     transitionTimes32 = other.transitionTimes32;
     281           0 :     transitionTimesPost32 = other.transitionTimesPost32;
     282             : 
     283           0 :     transitionCountPre32 = other.transitionCountPre32;
     284           0 :     transitionCount32 = other.transitionCount32;
     285           0 :     transitionCountPost32 = other.transitionCountPost32;
     286             : 
     287           0 :     typeCount = other.typeCount;
     288           0 :     typeOffsets = other.typeOffsets;
     289           0 :     typeMapData = other.typeMapData;
     290             : 
     291           0 :     delete finalZone;
     292           0 :     finalZone = (other.finalZone != 0) ?
     293           0 :         (SimpleTimeZone*) other.finalZone->clone() : 0;
     294             : 
     295           0 :     finalStartYear = other.finalStartYear;
     296           0 :     finalStartMillis = other.finalStartMillis;
     297             : 
     298           0 :     clearTransitionRules();
     299             : 
     300           0 :     return *this;
     301             : }
     302             : 
     303             : /**
     304             :  * Destructor
     305             :  */
     306           0 : OlsonTimeZone::~OlsonTimeZone() {
     307           0 :     deleteTransitionRules();
     308           0 :     delete finalZone;
     309           0 : }
     310             : 
     311             : /**
     312             :  * Returns true if the two TimeZone objects are equal.
     313             :  */
     314           0 : UBool OlsonTimeZone::operator==(const TimeZone& other) const {
     315           0 :     return ((this == &other) ||
     316           0 :             (typeid(*this) == typeid(other) &&
     317           0 :             TimeZone::operator==(other) &&
     318           0 :             hasSameRules(other)));
     319             : }
     320             : 
     321             : /**
     322             :  * TimeZone API.
     323             :  */
     324           0 : TimeZone* OlsonTimeZone::clone() const {
     325           0 :     return new OlsonTimeZone(*this);
     326             : }
     327             : 
     328             : /**
     329             :  * TimeZone API.
     330             :  */
     331           0 : int32_t OlsonTimeZone::getOffset(uint8_t era, int32_t year, int32_t month,
     332             :                                  int32_t dom, uint8_t dow,
     333             :                                  int32_t millis, UErrorCode& ec) const {
     334           0 :     if (month < UCAL_JANUARY || month > UCAL_DECEMBER) {
     335           0 :         if (U_SUCCESS(ec)) {
     336           0 :             ec = U_ILLEGAL_ARGUMENT_ERROR;
     337             :         }
     338           0 :         return 0;
     339             :     } else {
     340           0 :         return getOffset(era, year, month, dom, dow, millis,
     341           0 :                          Grego::monthLength(year, month),
     342           0 :                          ec);
     343             :     }
     344             : }
     345             : 
     346             : /**
     347             :  * TimeZone API.
     348             :  */
     349           0 : int32_t OlsonTimeZone::getOffset(uint8_t era, int32_t year, int32_t month,
     350             :                                  int32_t dom, uint8_t dow,
     351             :                                  int32_t millis, int32_t monthLength,
     352             :                                  UErrorCode& ec) const {
     353           0 :     if (U_FAILURE(ec)) {
     354           0 :         return 0;
     355             :     }
     356             : 
     357           0 :     if ((era != GregorianCalendar::AD && era != GregorianCalendar::BC)
     358           0 :         || month < UCAL_JANUARY
     359           0 :         || month > UCAL_DECEMBER
     360           0 :         || dom < 1
     361           0 :         || dom > monthLength
     362           0 :         || dow < UCAL_SUNDAY
     363           0 :         || dow > UCAL_SATURDAY
     364           0 :         || millis < 0
     365           0 :         || millis >= U_MILLIS_PER_DAY
     366           0 :         || monthLength < 28
     367           0 :         || monthLength > 31) {
     368           0 :         ec = U_ILLEGAL_ARGUMENT_ERROR;
     369           0 :         return 0;
     370             :     }
     371             : 
     372           0 :     if (era == GregorianCalendar::BC) {
     373           0 :         year = -year;
     374             :     }
     375             : 
     376           0 :     if (finalZone != NULL && year >= finalStartYear) {
     377           0 :         return finalZone->getOffset(era, year, month, dom, dow,
     378           0 :                                     millis, monthLength, ec);
     379             :     }
     380             : 
     381             :     // Compute local epoch millis from input fields
     382           0 :     UDate date = (UDate)(Grego::fieldsToDay(year, month, dom) * U_MILLIS_PER_DAY + millis);
     383             :     int32_t rawoff, dstoff;
     384           0 :     getHistoricalOffset(date, TRUE, kDaylight, kStandard, rawoff, dstoff);
     385           0 :     return rawoff + dstoff;
     386             : }
     387             : 
     388             : /**
     389             :  * TimeZone API.
     390             :  */
     391           0 : void OlsonTimeZone::getOffset(UDate date, UBool local, int32_t& rawoff,
     392             :                               int32_t& dstoff, UErrorCode& ec) const {
     393           0 :     if (U_FAILURE(ec)) {
     394           0 :         return;
     395             :     }
     396           0 :     if (finalZone != NULL && date >= finalStartMillis) {
     397           0 :         finalZone->getOffset(date, local, rawoff, dstoff, ec);
     398             :     } else {
     399           0 :         getHistoricalOffset(date, local, kFormer, kLatter, rawoff, dstoff);
     400             :     }
     401             : }
     402             : 
     403             : void
     404           0 : OlsonTimeZone::getOffsetFromLocal(UDate date, int32_t nonExistingTimeOpt, int32_t duplicatedTimeOpt,
     405             :                                   int32_t& rawoff, int32_t& dstoff, UErrorCode& ec) const {
     406           0 :     if (U_FAILURE(ec)) {
     407           0 :         return;
     408             :     }
     409           0 :     if (finalZone != NULL && date >= finalStartMillis) {
     410           0 :         finalZone->getOffsetFromLocal(date, nonExistingTimeOpt, duplicatedTimeOpt, rawoff, dstoff, ec);
     411             :     } else {
     412           0 :         getHistoricalOffset(date, TRUE, nonExistingTimeOpt, duplicatedTimeOpt, rawoff, dstoff);
     413             :     }
     414             : }
     415             : 
     416             : 
     417             : /**
     418             :  * TimeZone API.
     419             :  */
     420           0 : void OlsonTimeZone::setRawOffset(int32_t /*offsetMillis*/) {
     421             :     // We don't support this operation, since OlsonTimeZones are
     422             :     // immutable (except for the ID, which is in the base class).
     423             : 
     424             :     // Nothing to do!
     425           0 : }
     426             : 
     427             : /**
     428             :  * TimeZone API.
     429             :  */
     430           0 : int32_t OlsonTimeZone::getRawOffset() const {
     431           0 :     UErrorCode ec = U_ZERO_ERROR;
     432             :     int32_t raw, dst;
     433           0 :     getOffset((double) uprv_getUTCtime() * U_MILLIS_PER_SECOND,
     434           0 :               FALSE, raw, dst, ec);
     435           0 :     return raw;
     436             : }
     437             : 
     438             : #if defined U_DEBUG_TZ
     439             : void printTime(double ms) {
     440             :             int32_t year, month, dom, dow;
     441             :             double millis=0;
     442             :             double days = ClockMath::floorDivide(((double)ms), (double)U_MILLIS_PER_DAY, millis);
     443             :             
     444             :             Grego::dayToFields(days, year, month, dom, dow);
     445             :             U_DEBUG_TZ_MSG(("   getHistoricalOffset:  time %.1f (%04d.%02d.%02d+%.1fh)\n", ms,
     446             :                             year, month+1, dom, (millis/kOneHour)));
     447             :     }
     448             : #endif
     449             : 
     450             : int64_t
     451           0 : OlsonTimeZone::transitionTimeInSeconds(int16_t transIdx) const {
     452           0 :     U_ASSERT(transIdx >= 0 && transIdx < transitionCount()); 
     453             : 
     454           0 :     if (transIdx < transitionCountPre32) {
     455           0 :         return (((int64_t)((uint32_t)transitionTimesPre32[transIdx << 1])) << 32)
     456           0 :             | ((int64_t)((uint32_t)transitionTimesPre32[(transIdx << 1) + 1]));
     457             :     }
     458             : 
     459           0 :     transIdx -= transitionCountPre32;
     460           0 :     if (transIdx < transitionCount32) {
     461           0 :         return (int64_t)transitionTimes32[transIdx];
     462             :     }
     463             : 
     464           0 :     transIdx -= transitionCount32;
     465           0 :     return (((int64_t)((uint32_t)transitionTimesPost32[transIdx << 1])) << 32)
     466           0 :         | ((int64_t)((uint32_t)transitionTimesPost32[(transIdx << 1) + 1]));
     467             : }
     468             : 
     469             : // Maximum absolute offset in seconds (86400 seconds = 1 day)
     470             : // getHistoricalOffset uses this constant as safety margin of
     471             : // quick zone transition checking.
     472             : #define MAX_OFFSET_SECONDS 86400
     473             : 
     474             : void
     475           0 : OlsonTimeZone::getHistoricalOffset(UDate date, UBool local,
     476             :                                    int32_t NonExistingTimeOpt, int32_t DuplicatedTimeOpt,
     477             :                                    int32_t& rawoff, int32_t& dstoff) const {
     478             :     U_DEBUG_TZ_MSG(("getHistoricalOffset(%.1f, %s, %d, %d, raw, dst)\n",
     479             :         date, local?"T":"F", NonExistingTimeOpt, DuplicatedTimeOpt));
     480             : #if defined U_DEBUG_TZ
     481             :         printTime(date*1000.0);
     482             : #endif
     483           0 :     int16_t transCount = transitionCount();
     484             : 
     485           0 :     if (transCount > 0) {
     486           0 :         double sec = uprv_floor(date / U_MILLIS_PER_SECOND);
     487           0 :         if (!local && sec < transitionTimeInSeconds(0)) {
     488             :             // Before the first transition time
     489           0 :             rawoff = initialRawOffset() * U_MILLIS_PER_SECOND;
     490           0 :             dstoff = initialDstOffset() * U_MILLIS_PER_SECOND;
     491             :         } else {
     492             :             // Linear search from the end is the fastest approach, since
     493             :             // most lookups will happen at/near the end.
     494             :             int16_t transIdx;
     495           0 :             for (transIdx = transCount - 1; transIdx >= 0; transIdx--) {
     496           0 :                 int64_t transition = transitionTimeInSeconds(transIdx);
     497             : 
     498           0 :                 if (local && (sec >= (transition - MAX_OFFSET_SECONDS))) {
     499           0 :                     int32_t offsetBefore = zoneOffsetAt(transIdx - 1);
     500           0 :                     UBool dstBefore = dstOffsetAt(transIdx - 1) != 0;
     501             : 
     502           0 :                     int32_t offsetAfter = zoneOffsetAt(transIdx);
     503           0 :                     UBool dstAfter = dstOffsetAt(transIdx) != 0;
     504             : 
     505           0 :                     UBool dstToStd = dstBefore && !dstAfter;
     506           0 :                     UBool stdToDst = !dstBefore && dstAfter;
     507             :                     
     508           0 :                     if (offsetAfter - offsetBefore >= 0) {
     509             :                         // Positive transition, which makes a non-existing local time range
     510           0 :                         if (((NonExistingTimeOpt & kStdDstMask) == kStandard && dstToStd)
     511           0 :                                 || ((NonExistingTimeOpt & kStdDstMask) == kDaylight && stdToDst)) {
     512           0 :                             transition += offsetBefore;
     513           0 :                         } else if (((NonExistingTimeOpt & kStdDstMask) == kStandard && stdToDst)
     514           0 :                                 || ((NonExistingTimeOpt & kStdDstMask) == kDaylight && dstToStd)) {
     515           0 :                             transition += offsetAfter;
     516           0 :                         } else if ((NonExistingTimeOpt & kFormerLatterMask) == kLatter) {
     517           0 :                             transition += offsetBefore;
     518             :                         } else {
     519             :                             // Interprets the time with rule before the transition,
     520             :                             // default for non-existing time range
     521           0 :                             transition += offsetAfter;
     522             :                         }
     523             :                     } else {
     524             :                         // Negative transition, which makes a duplicated local time range
     525           0 :                         if (((DuplicatedTimeOpt & kStdDstMask) == kStandard && dstToStd)
     526           0 :                                 || ((DuplicatedTimeOpt & kStdDstMask) == kDaylight && stdToDst)) {
     527           0 :                             transition += offsetAfter;
     528           0 :                         } else if (((DuplicatedTimeOpt & kStdDstMask) == kStandard && stdToDst)
     529           0 :                                 || ((DuplicatedTimeOpt & kStdDstMask) == kDaylight && dstToStd)) {
     530           0 :                             transition += offsetBefore;
     531           0 :                         } else if ((DuplicatedTimeOpt & kFormerLatterMask) == kFormer) {
     532           0 :                             transition += offsetBefore;
     533             :                         } else {
     534             :                             // Interprets the time with rule after the transition,
     535             :                             // default for duplicated local time range
     536           0 :                             transition += offsetAfter;
     537             :                         }
     538             :                     }
     539             :                 }
     540           0 :                 if (sec >= transition) {
     541           0 :                     break;
     542             :                 }
     543             :             }
     544             :             // transIdx could be -1 when local=true
     545           0 :             rawoff = rawOffsetAt(transIdx) * U_MILLIS_PER_SECOND;
     546           0 :             dstoff = dstOffsetAt(transIdx) * U_MILLIS_PER_SECOND;
     547             :         }
     548             :     } else {
     549             :         // No transitions, single pair of offsets only
     550           0 :         rawoff = initialRawOffset() * U_MILLIS_PER_SECOND;
     551           0 :         dstoff = initialDstOffset() * U_MILLIS_PER_SECOND;
     552             :     }
     553             :     U_DEBUG_TZ_MSG(("getHistoricalOffset(%.1f, %s, %d, %d, raw, dst) - raw=%d, dst=%d\n",
     554             :         date, local?"T":"F", NonExistingTimeOpt, DuplicatedTimeOpt, rawoff, dstoff));
     555           0 : }
     556             : 
     557             : /**
     558             :  * TimeZone API.
     559             :  */
     560           0 : UBool OlsonTimeZone::useDaylightTime() const {
     561             :     // If DST was observed in 1942 (for example) but has never been
     562             :     // observed from 1943 to the present, most clients will expect
     563             :     // this method to return FALSE.  This method determines whether
     564             :     // DST is in use in the current year (at any point in the year)
     565             :     // and returns TRUE if so.
     566             : 
     567           0 :     UDate current = uprv_getUTCtime();
     568           0 :     if (finalZone != NULL && current >= finalStartMillis) {
     569           0 :         return finalZone->useDaylightTime();
     570             :     }
     571             : 
     572             :     int32_t year, month, dom, dow, doy, mid;
     573           0 :     Grego::timeToFields(current, year, month, dom, dow, doy, mid);
     574             : 
     575             :     // Find start of this year, and start of next year
     576           0 :     double start = Grego::fieldsToDay(year, 0, 1) * SECONDS_PER_DAY;
     577           0 :     double limit = Grego::fieldsToDay(year+1, 0, 1) * SECONDS_PER_DAY;
     578             : 
     579             :     // Return TRUE if DST is observed at any time during the current
     580             :     // year.
     581           0 :     for (int16_t i = 0; i < transitionCount(); ++i) {
     582           0 :         double transition = (double)transitionTimeInSeconds(i);
     583           0 :         if (transition >= limit) {
     584           0 :             break;
     585             :         }
     586           0 :         if ((transition >= start && dstOffsetAt(i) != 0)
     587           0 :                 || (transition > start && dstOffsetAt(i - 1) != 0)) {
     588           0 :             return TRUE;
     589             :         }
     590             :     }
     591           0 :     return FALSE;
     592             : }
     593             : int32_t 
     594           0 : OlsonTimeZone::getDSTSavings() const{
     595           0 :     if (finalZone != NULL){
     596           0 :         return finalZone->getDSTSavings();
     597             :     }
     598           0 :     return TimeZone::getDSTSavings();
     599             : }
     600             : /**
     601             :  * TimeZone API.
     602             :  */
     603           0 : UBool OlsonTimeZone::inDaylightTime(UDate date, UErrorCode& ec) const {
     604             :     int32_t raw, dst;
     605           0 :     getOffset(date, FALSE, raw, dst, ec);
     606           0 :     return dst != 0;
     607             : }
     608             : 
     609             : UBool
     610           0 : OlsonTimeZone::hasSameRules(const TimeZone &other) const {
     611           0 :     if (this == &other) {
     612           0 :         return TRUE;
     613             :     }
     614           0 :     const OlsonTimeZone* z = dynamic_cast<const OlsonTimeZone*>(&other);
     615           0 :     if (z == NULL) {
     616           0 :         return FALSE;
     617             :     }
     618             : 
     619             :     // [sic] pointer comparison: typeMapData points into
     620             :     // memory-mapped or DLL space, so if two zones have the same
     621             :     // pointer, they are equal.
     622           0 :     if (typeMapData == z->typeMapData) {
     623           0 :         return TRUE;
     624             :     }
     625             :     
     626             :     // If the pointers are not equal, the zones may still
     627             :     // be equal if their rules and transitions are equal
     628           0 :     if ((finalZone == NULL && z->finalZone != NULL)
     629           0 :         || (finalZone != NULL && z->finalZone == NULL)
     630           0 :         || (finalZone != NULL && z->finalZone != NULL && *finalZone != *z->finalZone)) {
     631           0 :         return FALSE;
     632             :     }
     633             : 
     634           0 :     if (finalZone != NULL) {
     635           0 :         if (finalStartYear != z->finalStartYear || finalStartMillis != z->finalStartMillis) {
     636           0 :             return FALSE;
     637             :         }
     638             :     }
     639           0 :     if (typeCount != z->typeCount
     640           0 :         || transitionCountPre32 != z->transitionCountPre32
     641           0 :         || transitionCount32 != z->transitionCount32
     642           0 :         || transitionCountPost32 != z->transitionCountPost32) {
     643           0 :         return FALSE;
     644             :     }
     645             : 
     646             :     return
     647           0 :         arrayEqual(transitionTimesPre32, z->transitionTimesPre32, sizeof(transitionTimesPre32[0]) * transitionCountPre32 << 1)
     648           0 :         && arrayEqual(transitionTimes32, z->transitionTimes32, sizeof(transitionTimes32[0]) * transitionCount32)
     649           0 :         && arrayEqual(transitionTimesPost32, z->transitionTimesPost32, sizeof(transitionTimesPost32[0]) * transitionCountPost32 << 1)
     650           0 :         && arrayEqual(typeOffsets, z->typeOffsets, sizeof(typeOffsets[0]) * typeCount << 1)
     651           0 :         && arrayEqual(typeMapData, z->typeMapData, sizeof(typeMapData[0]) * transitionCount());
     652             : }
     653             : 
     654             : void
     655           0 : OlsonTimeZone::clearTransitionRules(void) {
     656           0 :     initialRule = NULL;
     657           0 :     firstTZTransition = NULL;
     658           0 :     firstFinalTZTransition = NULL;
     659           0 :     historicRules = NULL;
     660           0 :     historicRuleCount = 0;
     661           0 :     finalZoneWithStartYear = NULL;
     662           0 :     firstTZTransitionIdx = 0;
     663           0 :     transitionRulesInitOnce.reset();
     664           0 : }
     665             : 
     666             : void
     667           0 : OlsonTimeZone::deleteTransitionRules(void) {
     668           0 :     if (initialRule != NULL) {
     669           0 :         delete initialRule;
     670             :     }
     671           0 :     if (firstTZTransition != NULL) {
     672           0 :         delete firstTZTransition;
     673             :     }
     674           0 :     if (firstFinalTZTransition != NULL) {
     675           0 :         delete firstFinalTZTransition;
     676             :     }
     677           0 :     if (finalZoneWithStartYear != NULL) {
     678           0 :         delete finalZoneWithStartYear;
     679             :     }
     680           0 :     if (historicRules != NULL) {
     681           0 :         for (int i = 0; i < historicRuleCount; i++) {
     682           0 :             if (historicRules[i] != NULL) {
     683           0 :                 delete historicRules[i];
     684             :             }
     685             :         }
     686           0 :         uprv_free(historicRules);
     687             :     }
     688           0 :     clearTransitionRules();
     689           0 : }
     690             : 
     691             : /*
     692             :  * Lazy transition rules initializer
     693             :  */
     694             : 
     695           0 : static void U_CALLCONV initRules(OlsonTimeZone *This, UErrorCode &status) {
     696           0 :     This->initTransitionRules(status);
     697           0 : }
     698             :     
     699             : void
     700           0 : OlsonTimeZone::checkTransitionRules(UErrorCode& status) const {
     701           0 :     OlsonTimeZone *ncThis = const_cast<OlsonTimeZone *>(this);
     702           0 :     umtx_initOnce(ncThis->transitionRulesInitOnce, &initRules, ncThis, status);
     703           0 : }
     704             : 
     705             : void
     706           0 : OlsonTimeZone::initTransitionRules(UErrorCode& status) {
     707           0 :     if(U_FAILURE(status)) {
     708           0 :         return;
     709             :     }
     710           0 :     deleteTransitionRules();
     711           0 :     UnicodeString tzid;
     712           0 :     getID(tzid);
     713             : 
     714           0 :     UnicodeString stdName = tzid + UNICODE_STRING_SIMPLE("(STD)");
     715           0 :     UnicodeString dstName = tzid + UNICODE_STRING_SIMPLE("(DST)");
     716             : 
     717             :     int32_t raw, dst;
     718             : 
     719             :     // Create initial rule
     720           0 :     raw = initialRawOffset() * U_MILLIS_PER_SECOND;
     721           0 :     dst = initialDstOffset() * U_MILLIS_PER_SECOND;
     722           0 :     initialRule = new InitialTimeZoneRule((dst == 0 ? stdName : dstName), raw, dst);
     723             :     // Check to make sure initialRule was created
     724           0 :     if (initialRule == NULL) {
     725           0 :         status = U_MEMORY_ALLOCATION_ERROR;
     726           0 :         deleteTransitionRules();
     727           0 :         return;
     728             :     }
     729             : 
     730           0 :     int32_t transCount = transitionCount();
     731           0 :     if (transCount > 0) {
     732             :         int16_t transitionIdx, typeIdx;
     733             : 
     734             :         // We probably no longer need to check the first "real" transition
     735             :         // here, because the new tzcode remove such transitions already.
     736             :         // For now, keeping this code for just in case. Feb 19, 2010 Yoshito
     737           0 :         firstTZTransitionIdx = 0;
     738           0 :         for (transitionIdx = 0; transitionIdx < transCount; transitionIdx++) {
     739           0 :             if (typeMapData[transitionIdx] != 0) { // type 0 is the initial type
     740           0 :                 break;
     741             :             }
     742           0 :             firstTZTransitionIdx++;
     743             :         }
     744           0 :         if (transitionIdx == transCount) {
     745             :             // Actually no transitions...
     746             :         } else {
     747             :             // Build historic rule array
     748           0 :             UDate* times = (UDate*)uprv_malloc(sizeof(UDate)*transCount); /* large enough to store all transition times */
     749           0 :             if (times == NULL) {
     750           0 :                 status = U_MEMORY_ALLOCATION_ERROR;
     751           0 :                 deleteTransitionRules();
     752           0 :                 return;
     753             :             }
     754           0 :             for (typeIdx = 0; typeIdx < typeCount; typeIdx++) {
     755             :                 // Gather all start times for each pair of offsets
     756           0 :                 int32_t nTimes = 0;
     757           0 :                 for (transitionIdx = firstTZTransitionIdx; transitionIdx < transCount; transitionIdx++) {
     758           0 :                     if (typeIdx == (int16_t)typeMapData[transitionIdx]) {
     759           0 :                         UDate tt = (UDate)transitionTime(transitionIdx);
     760           0 :                         if (finalZone == NULL || tt <= finalStartMillis) {
     761             :                             // Exclude transitions after finalMillis
     762           0 :                             times[nTimes++] = tt;
     763             :                         }
     764             :                     }
     765             :                 }
     766           0 :                 if (nTimes > 0) {
     767             :                     // Create a TimeArrayTimeZoneRule
     768           0 :                     raw = typeOffsets[typeIdx << 1] * U_MILLIS_PER_SECOND;
     769           0 :                     dst = typeOffsets[(typeIdx << 1) + 1] * U_MILLIS_PER_SECOND;
     770           0 :                     if (historicRules == NULL) {
     771           0 :                         historicRuleCount = typeCount;
     772           0 :                         historicRules = (TimeArrayTimeZoneRule**)uprv_malloc(sizeof(TimeArrayTimeZoneRule*)*historicRuleCount);
     773           0 :                         if (historicRules == NULL) {
     774           0 :                             status = U_MEMORY_ALLOCATION_ERROR;
     775           0 :                             deleteTransitionRules();
     776           0 :                             uprv_free(times);
     777           0 :                             return;
     778             :                         }
     779           0 :                         for (int i = 0; i < historicRuleCount; i++) {
     780             :                             // Initialize TimeArrayTimeZoneRule pointers as NULL
     781           0 :                             historicRules[i] = NULL;
     782             :                         }
     783             :                     }
     784           0 :                     historicRules[typeIdx] = new TimeArrayTimeZoneRule((dst == 0 ? stdName : dstName),
     785           0 :                         raw, dst, times, nTimes, DateTimeRule::UTC_TIME);
     786             :                     // Check for memory allocation error
     787           0 :                     if (historicRules[typeIdx] == NULL) {
     788           0 :                         status = U_MEMORY_ALLOCATION_ERROR;
     789           0 :                         deleteTransitionRules();
     790           0 :                         return;
     791             :                     }
     792             :                 }
     793             :             }
     794           0 :             uprv_free(times);
     795             : 
     796             :             // Create initial transition
     797           0 :             typeIdx = (int16_t)typeMapData[firstTZTransitionIdx];
     798           0 :             firstTZTransition = new TimeZoneTransition((UDate)transitionTime(firstTZTransitionIdx),
     799           0 :                     *initialRule, *historicRules[typeIdx]);
     800             :             // Check to make sure firstTZTransition was created.
     801           0 :             if (firstTZTransition == NULL) {
     802           0 :                 status = U_MEMORY_ALLOCATION_ERROR;
     803           0 :                 deleteTransitionRules();
     804           0 :                 return;
     805             :             }
     806             :         }
     807             :     }
     808           0 :     if (finalZone != NULL) {
     809             :         // Get the first occurence of final rule starts
     810           0 :         UDate startTime = (UDate)finalStartMillis;
     811           0 :         TimeZoneRule *firstFinalRule = NULL;
     812             : 
     813           0 :         if (finalZone->useDaylightTime()) {
     814             :             /*
     815             :              * Note: When an OlsonTimeZone is constructed, we should set the final year
     816             :              * as the start year of finalZone.  However, the bounday condition used for
     817             :              * getting offset from finalZone has some problems.
     818             :              * For now, we do not set the valid start year when the construction time
     819             :              * and create a clone and set the start year when extracting rules.
     820             :              */
     821           0 :             finalZoneWithStartYear = (SimpleTimeZone*)finalZone->clone();
     822             :             // Check to make sure finalZone was actually cloned.
     823           0 :             if (finalZoneWithStartYear == NULL) {
     824           0 :                 status = U_MEMORY_ALLOCATION_ERROR;
     825           0 :                 deleteTransitionRules();
     826           0 :                 return;
     827             :             }
     828           0 :             finalZoneWithStartYear->setStartYear(finalStartYear);
     829             : 
     830           0 :             TimeZoneTransition tzt;
     831           0 :             finalZoneWithStartYear->getNextTransition(startTime, false, tzt);
     832           0 :             firstFinalRule  = tzt.getTo()->clone();
     833             :             // Check to make sure firstFinalRule received proper clone.
     834           0 :             if (firstFinalRule == NULL) {
     835           0 :                 status = U_MEMORY_ALLOCATION_ERROR;
     836           0 :                 deleteTransitionRules();
     837           0 :                 return;
     838             :             }
     839           0 :             startTime = tzt.getTime();
     840             :         } else {
     841             :             // final rule with no transitions
     842           0 :             finalZoneWithStartYear = (SimpleTimeZone*)finalZone->clone();
     843             :             // Check to make sure finalZone was actually cloned.
     844           0 :             if (finalZoneWithStartYear == NULL) {
     845           0 :                 status = U_MEMORY_ALLOCATION_ERROR;
     846           0 :                 deleteTransitionRules();
     847           0 :                 return;
     848             :             }
     849           0 :             finalZone->getID(tzid);
     850           0 :             firstFinalRule = new TimeArrayTimeZoneRule(tzid,
     851           0 :                 finalZone->getRawOffset(), 0, &startTime, 1, DateTimeRule::UTC_TIME);
     852             :             // Check firstFinalRule was properly created.
     853           0 :             if (firstFinalRule == NULL) {
     854           0 :                 status = U_MEMORY_ALLOCATION_ERROR;
     855           0 :                 deleteTransitionRules();
     856           0 :                 return;
     857             :             }
     858             :         }
     859           0 :         TimeZoneRule *prevRule = NULL;
     860           0 :         if (transCount > 0) {
     861           0 :             prevRule = historicRules[typeMapData[transCount - 1]];
     862             :         }
     863           0 :         if (prevRule == NULL) {
     864             :             // No historic transitions, but only finalZone available
     865           0 :             prevRule = initialRule;
     866             :         }
     867           0 :         firstFinalTZTransition = new TimeZoneTransition();
     868             :         // Check to make sure firstFinalTZTransition was created before dereferencing
     869           0 :         if (firstFinalTZTransition == NULL) {
     870           0 :             status = U_MEMORY_ALLOCATION_ERROR;
     871           0 :             deleteTransitionRules();
     872           0 :             return;
     873             :         }
     874           0 :         firstFinalTZTransition->setTime(startTime);
     875           0 :         firstFinalTZTransition->adoptFrom(prevRule->clone());
     876           0 :         firstFinalTZTransition->adoptTo(firstFinalRule);
     877             :     }
     878             : }
     879             : 
     880             : UBool
     881           0 : OlsonTimeZone::getNextTransition(UDate base, UBool inclusive, TimeZoneTransition& result) const {
     882           0 :     UErrorCode status = U_ZERO_ERROR;
     883           0 :     checkTransitionRules(status);
     884           0 :     if (U_FAILURE(status)) {
     885           0 :         return FALSE;
     886             :     }
     887             : 
     888           0 :     if (finalZone != NULL) {
     889           0 :         if (inclusive && base == firstFinalTZTransition->getTime()) {
     890           0 :             result = *firstFinalTZTransition;
     891           0 :             return TRUE;
     892           0 :         } else if (base >= firstFinalTZTransition->getTime()) {
     893           0 :             if (finalZone->useDaylightTime()) {
     894             :                 //return finalZone->getNextTransition(base, inclusive, result);
     895           0 :                 return finalZoneWithStartYear->getNextTransition(base, inclusive, result);
     896             :             } else {
     897             :                 // No more transitions
     898           0 :                 return FALSE;
     899             :             }
     900             :         }
     901             :     }
     902           0 :     if (historicRules != NULL) {
     903             :         // Find a historical transition
     904           0 :         int16_t transCount = transitionCount();
     905           0 :         int16_t ttidx = transCount - 1;
     906           0 :         for (; ttidx >= firstTZTransitionIdx; ttidx--) {
     907           0 :             UDate t = (UDate)transitionTime(ttidx);
     908           0 :             if (base > t || (!inclusive && base == t)) {
     909             :                 break;
     910             :             }
     911             :         }
     912           0 :         if (ttidx == transCount - 1)  {
     913           0 :             if (firstFinalTZTransition != NULL) {
     914           0 :                 result = *firstFinalTZTransition;
     915           0 :                 return TRUE;
     916             :             } else {
     917           0 :                 return FALSE;
     918             :             }
     919           0 :         } else if (ttidx < firstTZTransitionIdx) {
     920           0 :             result = *firstTZTransition;
     921           0 :             return TRUE;
     922             :         } else {
     923             :             // Create a TimeZoneTransition
     924           0 :             TimeZoneRule *to = historicRules[typeMapData[ttidx + 1]];
     925           0 :             TimeZoneRule *from = historicRules[typeMapData[ttidx]];
     926           0 :             UDate startTime = (UDate)transitionTime(ttidx+1);
     927             : 
     928             :             // The transitions loaded from zoneinfo.res may contain non-transition data
     929           0 :             UnicodeString fromName, toName;
     930           0 :             from->getName(fromName);
     931           0 :             to->getName(toName);
     932           0 :             if (fromName == toName && from->getRawOffset() == to->getRawOffset()
     933           0 :                     && from->getDSTSavings() == to->getDSTSavings()) {
     934           0 :                 return getNextTransition(startTime, false, result);
     935             :             }
     936           0 :             result.setTime(startTime);
     937           0 :             result.adoptFrom(from->clone());
     938           0 :             result.adoptTo(to->clone());
     939           0 :             return TRUE;
     940             :         }
     941             :     }
     942           0 :     return FALSE;
     943             : }
     944             : 
     945             : UBool
     946           0 : OlsonTimeZone::getPreviousTransition(UDate base, UBool inclusive, TimeZoneTransition& result) const {
     947           0 :     UErrorCode status = U_ZERO_ERROR;
     948           0 :     checkTransitionRules(status);
     949           0 :     if (U_FAILURE(status)) {
     950           0 :         return FALSE;
     951             :     }
     952             : 
     953           0 :     if (finalZone != NULL) {
     954           0 :         if (inclusive && base == firstFinalTZTransition->getTime()) {
     955           0 :             result = *firstFinalTZTransition;
     956           0 :             return TRUE;
     957           0 :         } else if (base > firstFinalTZTransition->getTime()) {
     958           0 :             if (finalZone->useDaylightTime()) {
     959             :                 //return finalZone->getPreviousTransition(base, inclusive, result);
     960           0 :                 return finalZoneWithStartYear->getPreviousTransition(base, inclusive, result);
     961             :             } else {
     962           0 :                 result = *firstFinalTZTransition;
     963           0 :                 return TRUE;
     964             :             }
     965             :         }
     966             :     }
     967             : 
     968           0 :     if (historicRules != NULL) {
     969             :         // Find a historical transition
     970           0 :         int16_t ttidx = transitionCount() - 1;
     971           0 :         for (; ttidx >= firstTZTransitionIdx; ttidx--) {
     972           0 :             UDate t = (UDate)transitionTime(ttidx);
     973           0 :             if (base > t || (inclusive && base == t)) {
     974             :                 break;
     975             :             }
     976             :         }
     977           0 :         if (ttidx < firstTZTransitionIdx) {
     978             :             // No more transitions
     979           0 :             return FALSE;
     980           0 :         } else if (ttidx == firstTZTransitionIdx) {
     981           0 :             result = *firstTZTransition;
     982           0 :             return TRUE;
     983             :         } else {
     984             :             // Create a TimeZoneTransition
     985           0 :             TimeZoneRule *to = historicRules[typeMapData[ttidx]];
     986           0 :             TimeZoneRule *from = historicRules[typeMapData[ttidx-1]];
     987           0 :             UDate startTime = (UDate)transitionTime(ttidx);
     988             : 
     989             :             // The transitions loaded from zoneinfo.res may contain non-transition data
     990           0 :             UnicodeString fromName, toName;
     991           0 :             from->getName(fromName);
     992           0 :             to->getName(toName);
     993           0 :             if (fromName == toName && from->getRawOffset() == to->getRawOffset()
     994           0 :                     && from->getDSTSavings() == to->getDSTSavings()) {
     995           0 :                 return getPreviousTransition(startTime, false, result);
     996             :             }
     997           0 :             result.setTime(startTime);
     998           0 :             result.adoptFrom(from->clone());
     999           0 :             result.adoptTo(to->clone());
    1000           0 :             return TRUE;
    1001             :         }
    1002             :     }
    1003           0 :     return FALSE;
    1004             : }
    1005             : 
    1006             : int32_t
    1007           0 : OlsonTimeZone::countTransitionRules(UErrorCode& status) const {
    1008           0 :     if (U_FAILURE(status)) {
    1009           0 :         return 0;
    1010             :     }
    1011           0 :     checkTransitionRules(status);
    1012           0 :     if (U_FAILURE(status)) {
    1013           0 :         return 0;
    1014             :     }
    1015             : 
    1016           0 :     int32_t count = 0;
    1017           0 :     if (historicRules != NULL) {
    1018             :         // historicRules may contain null entries when original zoneinfo data
    1019             :         // includes non transition data.
    1020           0 :         for (int32_t i = 0; i < historicRuleCount; i++) {
    1021           0 :             if (historicRules[i] != NULL) {
    1022           0 :                 count++;
    1023             :             }
    1024             :         }
    1025             :     }
    1026           0 :     if (finalZone != NULL) {
    1027           0 :         if (finalZone->useDaylightTime()) {
    1028           0 :             count += 2;
    1029             :         } else {
    1030           0 :             count++;
    1031             :         }
    1032             :     }
    1033           0 :     return count;
    1034             : }
    1035             : 
    1036             : void
    1037           0 : OlsonTimeZone::getTimeZoneRules(const InitialTimeZoneRule*& initial,
    1038             :                                 const TimeZoneRule* trsrules[],
    1039             :                                 int32_t& trscount,
    1040             :                                 UErrorCode& status) const {
    1041           0 :     if (U_FAILURE(status)) {
    1042           0 :         return;
    1043             :     }
    1044           0 :     checkTransitionRules(status);
    1045           0 :     if (U_FAILURE(status)) {
    1046           0 :         return;
    1047             :     }
    1048             : 
    1049             :     // Initial rule
    1050           0 :     initial = initialRule;
    1051             : 
    1052             :     // Transition rules
    1053           0 :     int32_t cnt = 0;
    1054           0 :     if (historicRules != NULL && trscount > cnt) {
    1055             :         // historicRules may contain null entries when original zoneinfo data
    1056             :         // includes non transition data.
    1057           0 :         for (int32_t i = 0; i < historicRuleCount; i++) {
    1058           0 :             if (historicRules[i] != NULL) {
    1059           0 :                 trsrules[cnt++] = historicRules[i];
    1060           0 :                 if (cnt >= trscount) {
    1061           0 :                     break;
    1062             :                 }
    1063             :             }
    1064             :         }
    1065             :     }
    1066           0 :     if (finalZoneWithStartYear != NULL && trscount > cnt) {
    1067             :         const InitialTimeZoneRule *tmpini;
    1068           0 :         int32_t tmpcnt = trscount - cnt;
    1069           0 :         finalZoneWithStartYear->getTimeZoneRules(tmpini, &trsrules[cnt], tmpcnt, status);
    1070           0 :         if (U_FAILURE(status)) {
    1071           0 :             return;
    1072             :         }
    1073           0 :         cnt += tmpcnt;
    1074             :     }
    1075             :     // Set the result length
    1076           0 :     trscount = cnt;
    1077             : }
    1078             : 
    1079             : U_NAMESPACE_END
    1080             : 
    1081             : #endif // !UCONFIG_NO_FORMATTING
    1082             : 
    1083             : //eof

Generated by: LCOV version 1.13