tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

olsontz.cpp (40025B)


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