Home | History | Annotate | Download | only in i18n
      1 // Copyright (C) 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 static UBool arrayEqual(const void *a1, const void *a2, int32_t size) {
     55     if (a1 == NULL && a2 == NULL) {
     56         return TRUE;
     57     }
     58     if ((a1 != NULL && a2 == NULL) || (a1 == NULL && a2 != NULL)) {
     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 = NULL;
    101 
    102     transitionCountPre32 = transitionCount32 = transitionCountPost32 = 0;
    103     transitionTimesPre32 = transitionTimes32 = transitionTimesPost32 = NULL;
    104 
    105     typeMapData = NULL;
    106 
    107     typeCount = 1;
    108     typeOffsets = ZEROS;
    109 
    110     finalZone = NULL;
    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(NULL)
    125 {
    126     clearTransitionRules();
    127     U_DEBUG_TZ_MSG(("OlsonTimeZone(%s)\n", ures_getKey((UResourceBundle*)res)));
    128     if ((top == NULL || res == NULL) && 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         UResourceBundle r;
    138         ures_initStackObject(&r);
    139 
    140         // Pre-32bit second transitions
    141         ures_getByKey(res, kTRANSPRE32, &r, &ec);
    142         transitionTimesPre32 = ures_getIntVector(&r, &len, &ec);
    143         transitionCountPre32 = len >> 1;
    144         if (ec == U_MISSING_RESOURCE_ERROR) {
    145             // No pre-32bit transitions
    146             transitionTimesPre32 = NULL;
    147             transitionCountPre32 = 0;
    148             ec = U_ZERO_ERROR;
    149         } else if (U_SUCCESS(ec) && (len < 0 || len > 0x7FFF || (len & 1) != 0) /* len must be even */) {
    150             ec = U_INVALID_FORMAT_ERROR;
    151         }
    152 
    153         // 32bit second transitions
    154         ures_getByKey(res, kTRANS, &r, &ec);
    155         transitionTimes32 = ures_getIntVector(&r, &len, &ec);
    156         transitionCount32 = len;
    157         if (ec == U_MISSING_RESOURCE_ERROR) {
    158             // No 32bit transitions
    159             transitionTimes32 = NULL;
    160             transitionCount32 = 0;
    161             ec = U_ZERO_ERROR;
    162         } else if (U_SUCCESS(ec) && (len < 0 || len > 0x7FFF)) {
    163             ec = U_INVALID_FORMAT_ERROR;
    164         }
    165 
    166         // Post-32bit second transitions
    167         ures_getByKey(res, kTRANSPOST32, &r, &ec);
    168         transitionTimesPost32 = ures_getIntVector(&r, &len, &ec);
    169         transitionCountPost32 = len >> 1;
    170         if (ec == U_MISSING_RESOURCE_ERROR) {
    171             // No pre-32bit transitions
    172             transitionTimesPost32 = NULL;
    173             transitionCountPost32 = 0;
    174             ec = U_ZERO_ERROR;
    175         } else if (U_SUCCESS(ec) && (len < 0 || len > 0x7FFF || (len & 1) != 0) /* len must be even */) {
    176             ec = U_INVALID_FORMAT_ERROR;
    177         }
    178 
    179         // Type offsets list must be of even size, with size >= 2
    180         ures_getByKey(res, kTYPEOFFSETS, &r, &ec);
    181         typeOffsets = ures_getIntVector(&r, &len, &ec);
    182         if (U_SUCCESS(ec) && (len < 2 || len > 0x7FFE || (len & 1) != 0)) {
    183             ec = U_INVALID_FORMAT_ERROR;
    184         }
    185         typeCount = (int16_t) len >> 1;
    186 
    187         // Type map data must be of the same size as the transition count
    188         typeMapData =  NULL;
    189         if (transitionCount() > 0) {
    190             ures_getByKey(res, kTYPEMAP, &r, &ec);
    191             typeMapData = ures_getBinary(&r, &len, &ec);
    192             if (ec == U_MISSING_RESOURCE_ERROR) {
    193                 // no type mapping data
    194                 ec = U_INVALID_FORMAT_ERROR;
    195             } else if (U_SUCCESS(ec) && len != transitionCount()) {
    196                 ec = U_INVALID_FORMAT_ERROR;
    197             }
    198         }
    199 
    200         // Process final rule and data, if any
    201         const UChar *ruleIdUStr = ures_getStringByKey(res, kFINALRULE, &len, &ec);
    202         ures_getByKey(res, kFINALRAW, &r, &ec);
    203         int32_t ruleRaw = ures_getInt(&r, &ec);
    204         ures_getByKey(res, kFINALYEAR, &r, &ec);
    205         int32_t ruleYear = ures_getInt(&r, &ec);
    206         if (U_SUCCESS(ec)) {
    207             UnicodeString ruleID(TRUE, ruleIdUStr, len);
    208             UResourceBundle *rule = TimeZone::loadRule(top, ruleID, NULL, 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                     (int8_t)ruleData[0], (int8_t)ruleData[1], (int8_t)ruleData[2],
    216                     ruleData[3] * U_MILLIS_PER_SECOND,
    217                     (SimpleTimeZone::TimeMode) ruleData[4],
    218                     (int8_t)ruleData[5], (int8_t)ruleData[6], (int8_t)ruleData[7],
    219                     ruleData[8] * U_MILLIS_PER_SECOND,
    220                     (SimpleTimeZone::TimeMode) ruleData[9],
    221                     ruleData[10] * U_MILLIS_PER_SECOND, ec);
    222                 if (finalZone == NULL) {
    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         ures_close(&r);
    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(0) {
    270     *this = other;
    271 }
    272 
    273 /**
    274  * Assignment operator
    275  */
    276 OlsonTimeZone& OlsonTimeZone::operator=(const OlsonTimeZone& other) {
    277     canonicalID = other.canonicalID;
    278 
    279     transitionTimesPre32 = other.transitionTimesPre32;
    280     transitionTimes32 = other.transitionTimes32;
    281     transitionTimesPost32 = other.transitionTimesPost32;
    282 
    283     transitionCountPre32 = other.transitionCountPre32;
    284     transitionCount32 = other.transitionCount32;
    285     transitionCountPost32 = other.transitionCountPost32;
    286 
    287     typeCount = other.typeCount;
    288     typeOffsets = other.typeOffsets;
    289     typeMapData = other.typeMapData;
    290 
    291     delete finalZone;
    292     finalZone = (other.finalZone != 0) ?
    293         (SimpleTimeZone*) other.finalZone->clone() : 0;
    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 UBool 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 TimeZone* 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 != NULL && 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 = (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 != NULL && 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
    404 OlsonTimeZone::getOffsetFromLocal(UDate date, int32_t nonExistingTimeOpt, int32_t duplicatedTimeOpt,
    405                                   int32_t& rawoff, int32_t& dstoff, UErrorCode& ec) const {
    406     if (U_FAILURE(ec)) {
    407         return;
    408     }
    409     if (finalZone != NULL && 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((double) uprv_getUTCtime() * U_MILLIS_PER_SECOND,
    434               FALSE, raw, dst, ec);
    435     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 OlsonTimeZone::transitionTimeInSeconds(int16_t transIdx) const {
    452     U_ASSERT(transIdx >= 0 && transIdx < transitionCount());
    453 
    454     if (transIdx < transitionCountPre32) {
    455         return (((int64_t)((uint32_t)transitionTimesPre32[transIdx << 1])) << 32)
    456             | ((int64_t)((uint32_t)transitionTimesPre32[(transIdx << 1) + 1]));
    457     }
    458 
    459     transIdx -= transitionCountPre32;
    460     if (transIdx < transitionCount32) {
    461         return (int64_t)transitionTimes32[transIdx];
    462     }
    463 
    464     transIdx -= transitionCount32;
    465     return (((int64_t)((uint32_t)transitionTimesPost32[transIdx << 1])) << 32)
    466         | ((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 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     int16_t transCount = transitionCount();
    484 
    485     if (transCount > 0) {
    486         double sec = uprv_floor(date / U_MILLIS_PER_SECOND);
    487         if (!local && sec < transitionTimeInSeconds(0)) {
    488             // Before the first transition time
    489             rawoff = initialRawOffset() * U_MILLIS_PER_SECOND;
    490             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             for (transIdx = transCount - 1; transIdx >= 0; transIdx--) {
    496                 int64_t transition = transitionTimeInSeconds(transIdx);
    497 
    498                 if (local && (sec >= (transition - MAX_OFFSET_SECONDS))) {
    499                     int32_t offsetBefore = zoneOffsetAt(transIdx - 1);
    500                     UBool dstBefore = dstOffsetAt(transIdx - 1) != 0;
    501 
    502                     int32_t offsetAfter = zoneOffsetAt(transIdx);
    503                     UBool dstAfter = dstOffsetAt(transIdx) != 0;
    504 
    505                     UBool dstToStd = dstBefore && !dstAfter;
    506                     UBool stdToDst = !dstBefore && dstAfter;
    507 
    508                     if (offsetAfter - offsetBefore >= 0) {
    509                         // Positive transition, which makes a non-existing local time range
    510                         if (((NonExistingTimeOpt & kStdDstMask) == kStandard && dstToStd)
    511                                 || ((NonExistingTimeOpt & kStdDstMask) == kDaylight && stdToDst)) {
    512                             transition += offsetBefore;
    513                         } else if (((NonExistingTimeOpt & kStdDstMask) == kStandard && stdToDst)
    514                                 || ((NonExistingTimeOpt & kStdDstMask) == kDaylight && dstToStd)) {
    515                             transition += offsetAfter;
    516                         } else if ((NonExistingTimeOpt & kFormerLatterMask) == kLatter) {
    517                             transition += offsetBefore;
    518                         } else {
    519                             // Interprets the time with rule before the transition,
    520                             // default for non-existing time range
    521                             transition += offsetAfter;
    522                         }
    523                     } else {
    524                         // Negative transition, which makes a duplicated local time range
    525                         if (((DuplicatedTimeOpt & kStdDstMask) == kStandard && dstToStd)
    526                                 || ((DuplicatedTimeOpt & kStdDstMask) == kDaylight && stdToDst)) {
    527                             transition += offsetAfter;
    528                         } else if (((DuplicatedTimeOpt & kStdDstMask) == kStandard && stdToDst)
    529                                 || ((DuplicatedTimeOpt & kStdDstMask) == kDaylight && dstToStd)) {
    530                             transition += offsetBefore;
    531                         } else if ((DuplicatedTimeOpt & kFormerLatterMask) == kFormer) {
    532                             transition += offsetBefore;
    533                         } else {
    534                             // Interprets the time with rule after the transition,
    535                             // default for duplicated local time range
    536                             transition += offsetAfter;
    537                         }
    538                     }
    539                 }
    540                 if (sec >= transition) {
    541                     break;
    542                 }
    543             }
    544             // transIdx could be -1 when local=true
    545             rawoff = rawOffsetAt(transIdx) * U_MILLIS_PER_SECOND;
    546             dstoff = dstOffsetAt(transIdx) * U_MILLIS_PER_SECOND;
    547         }
    548     } else {
    549         // No transitions, single pair of offsets only
    550         rawoff = initialRawOffset() * U_MILLIS_PER_SECOND;
    551         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 }
    556 
    557 /**
    558  * TimeZone API.
    559  */
    560 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     UDate current = uprv_getUTCtime();
    568     if (finalZone != NULL && current >= finalStartMillis) {
    569         return finalZone->useDaylightTime();
    570     }
    571 
    572     int32_t year, month, dom, dow, doy, mid;
    573     Grego::timeToFields(current, year, month, dom, dow, doy, mid);
    574 
    575     // Find start of this year, and start of next year
    576     double start = Grego::fieldsToDay(year, 0, 1) * SECONDS_PER_DAY;
    577     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     for (int16_t i = 0; i < transitionCount(); ++i) {
    582         double transition = (double)transitionTimeInSeconds(i);
    583         if (transition >= limit) {
    584             break;
    585         }
    586         if ((transition >= start && dstOffsetAt(i) != 0)
    587                 || (transition > start && dstOffsetAt(i - 1) != 0)) {
    588             return TRUE;
    589         }
    590     }
    591     return FALSE;
    592 }
    593 int32_t
    594 OlsonTimeZone::getDSTSavings() const{
    595     if (finalZone != NULL){
    596         return finalZone->getDSTSavings();
    597     }
    598     return TimeZone::getDSTSavings();
    599 }
    600 /**
    601  * TimeZone API.
    602  */
    603 UBool OlsonTimeZone::inDaylightTime(UDate date, UErrorCode& ec) const {
    604     int32_t raw, dst;
    605     getOffset(date, FALSE, raw, dst, ec);
    606     return dst != 0;
    607 }
    608 
    609 UBool
    610 OlsonTimeZone::hasSameRules(const TimeZone &other) const {
    611     if (this == &other) {
    612         return TRUE;
    613     }
    614     const OlsonTimeZone* z = dynamic_cast<const OlsonTimeZone*>(&other);
    615     if (z == NULL) {
    616         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     if (typeMapData == z->typeMapData) {
    623         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     if ((finalZone == NULL && z->finalZone != NULL)
    629         || (finalZone != NULL && z->finalZone == NULL)
    630         || (finalZone != NULL && z->finalZone != NULL && *finalZone != *z->finalZone)) {
    631         return FALSE;
    632     }
    633 
    634     if (finalZone != NULL) {
    635         if (finalStartYear != z->finalStartYear || finalStartMillis != z->finalStartMillis) {
    636             return FALSE;
    637         }
    638     }
    639     if (typeCount != z->typeCount
    640         || transitionCountPre32 != z->transitionCountPre32
    641         || transitionCount32 != z->transitionCount32
    642         || transitionCountPost32 != z->transitionCountPost32) {
    643         return FALSE;
    644     }
    645 
    646     return
    647         arrayEqual(transitionTimesPre32, z->transitionTimesPre32, sizeof(transitionTimesPre32[0]) * transitionCountPre32 << 1)
    648         && arrayEqual(transitionTimes32, z->transitionTimes32, sizeof(transitionTimes32[0]) * transitionCount32)
    649         && arrayEqual(transitionTimesPost32, z->transitionTimesPost32, sizeof(transitionTimesPost32[0]) * transitionCountPost32 << 1)
    650         && arrayEqual(typeOffsets, z->typeOffsets, sizeof(typeOffsets[0]) * typeCount << 1)
    651         && arrayEqual(typeMapData, z->typeMapData, sizeof(typeMapData[0]) * transitionCount());
    652 }
    653 
    654 void
    655 OlsonTimeZone::clearTransitionRules(void) {
    656     initialRule = NULL;
    657     firstTZTransition = NULL;
    658     firstFinalTZTransition = NULL;
    659     historicRules = NULL;
    660     historicRuleCount = 0;
    661     finalZoneWithStartYear = NULL;
    662     firstTZTransitionIdx = 0;
    663     transitionRulesInitOnce.reset();
    664 }
    665 
    666 void
    667 OlsonTimeZone::deleteTransitionRules(void) {
    668     if (initialRule != NULL) {
    669         delete initialRule;
    670     }
    671     if (firstTZTransition != NULL) {
    672         delete firstTZTransition;
    673     }
    674     if (firstFinalTZTransition != NULL) {
    675         delete firstFinalTZTransition;
    676     }
    677     if (finalZoneWithStartYear != NULL) {
    678         delete finalZoneWithStartYear;
    679     }
    680     if (historicRules != NULL) {
    681         for (int i = 0; i < historicRuleCount; i++) {
    682             if (historicRules[i] != NULL) {
    683                 delete historicRules[i];
    684             }
    685         }
    686         uprv_free(historicRules);
    687     }
    688     clearTransitionRules();
    689 }
    690 
    691 /*
    692  * Lazy transition rules initializer
    693  */
    694 
    695 static void U_CALLCONV initRules(OlsonTimeZone *This, UErrorCode &status) {
    696     This->initTransitionRules(status);
    697 }
    698 
    699 void
    700 OlsonTimeZone::checkTransitionRules(UErrorCode& status) const {
    701     OlsonTimeZone *ncThis = const_cast<OlsonTimeZone *>(this);
    702     umtx_initOnce(ncThis->transitionRulesInitOnce, &initRules, ncThis, status);
    703 }
    704 
    705 void
    706 OlsonTimeZone::initTransitionRules(UErrorCode& status) {
    707     if(U_FAILURE(status)) {
    708         return;
    709     }
    710     deleteTransitionRules();
    711     UnicodeString tzid;
    712     getID(tzid);
    713 
    714     UnicodeString stdName = tzid + UNICODE_STRING_SIMPLE("(STD)");
    715     UnicodeString dstName = tzid + UNICODE_STRING_SIMPLE("(DST)");
    716 
    717     int32_t raw, dst;
    718 
    719     // Create initial rule
    720     raw = initialRawOffset() * U_MILLIS_PER_SECOND;
    721     dst = initialDstOffset() * U_MILLIS_PER_SECOND;
    722     initialRule = new InitialTimeZoneRule((dst == 0 ? stdName : dstName), raw, dst);
    723     // Check to make sure initialRule was created
    724     if (initialRule == NULL) {
    725         status = U_MEMORY_ALLOCATION_ERROR;
    726         deleteTransitionRules();
    727         return;
    728     }
    729 
    730     int32_t transCount = transitionCount();
    731     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         firstTZTransitionIdx = 0;
    738         for (transitionIdx = 0; transitionIdx < transCount; transitionIdx++) {
    739             if (typeMapData[transitionIdx] != 0) { // type 0 is the initial type
    740                 break;
    741             }
    742             firstTZTransitionIdx++;
    743         }
    744         if (transitionIdx == transCount) {
    745             // Actually no transitions...
    746         } else {
    747             // Build historic rule array
    748             UDate* times = (UDate*)uprv_malloc(sizeof(UDate)*transCount); /* large enough to store all transition times */
    749             if (times == NULL) {
    750                 status = U_MEMORY_ALLOCATION_ERROR;
    751                 deleteTransitionRules();
    752                 return;
    753             }
    754             for (typeIdx = 0; typeIdx < typeCount; typeIdx++) {
    755                 // Gather all start times for each pair of offsets
    756                 int32_t nTimes = 0;
    757                 for (transitionIdx = firstTZTransitionIdx; transitionIdx < transCount; transitionIdx++) {
    758                     if (typeIdx == (int16_t)typeMapData[transitionIdx]) {
    759                         UDate tt = (UDate)transitionTime(transitionIdx);
    760                         if (finalZone == NULL || tt <= finalStartMillis) {
    761                             // Exclude transitions after finalMillis
    762                             times[nTimes++] = tt;
    763                         }
    764                     }
    765                 }
    766                 if (nTimes > 0) {
    767                     // Create a TimeArrayTimeZoneRule
    768                     raw = typeOffsets[typeIdx << 1] * U_MILLIS_PER_SECOND;
    769                     dst = typeOffsets[(typeIdx << 1) + 1] * U_MILLIS_PER_SECOND;
    770                     if (historicRules == NULL) {
    771                         historicRuleCount = typeCount;
    772                         historicRules = (TimeArrayTimeZoneRule**)uprv_malloc(sizeof(TimeArrayTimeZoneRule*)*historicRuleCount);
    773                         if (historicRules == NULL) {
    774                             status = U_MEMORY_ALLOCATION_ERROR;
    775                             deleteTransitionRules();
    776                             uprv_free(times);
    777                             return;
    778                         }
    779                         for (int i = 0; i < historicRuleCount; i++) {
    780                             // Initialize TimeArrayTimeZoneRule pointers as NULL
    781                             historicRules[i] = NULL;
    782                         }
    783                     }
    784                     historicRules[typeIdx] = new TimeArrayTimeZoneRule((dst == 0 ? stdName : dstName),
    785                         raw, dst, times, nTimes, DateTimeRule::UTC_TIME);
    786                     // Check for memory allocation error
    787                     if (historicRules[typeIdx] == NULL) {
    788                         status = U_MEMORY_ALLOCATION_ERROR;
    789                         deleteTransitionRules();
    790                         return;
    791                     }
    792                 }
    793             }
    794             uprv_free(times);
    795 
    796             // Create initial transition
    797             typeIdx = (int16_t)typeMapData[firstTZTransitionIdx];
    798             firstTZTransition = new TimeZoneTransition((UDate)transitionTime(firstTZTransitionIdx),
    799                     *initialRule, *historicRules[typeIdx]);
    800             // Check to make sure firstTZTransition was created.
    801             if (firstTZTransition == NULL) {
    802                 status = U_MEMORY_ALLOCATION_ERROR;
    803                 deleteTransitionRules();
    804                 return;
    805             }
    806         }
    807     }
    808     if (finalZone != NULL) {
    809         // Get the first occurence of final rule starts
    810         UDate startTime = (UDate)finalStartMillis;
    811         TimeZoneRule *firstFinalRule = NULL;
    812 
    813         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             finalZoneWithStartYear = (SimpleTimeZone*)finalZone->clone();
    822             // Check to make sure finalZone was actually cloned.
    823             if (finalZoneWithStartYear == NULL) {
    824                 status = U_MEMORY_ALLOCATION_ERROR;
    825                 deleteTransitionRules();
    826                 return;
    827             }
    828             finalZoneWithStartYear->setStartYear(finalStartYear);
    829 
    830             TimeZoneTransition tzt;
    831             finalZoneWithStartYear->getNextTransition(startTime, false, tzt);
    832             firstFinalRule  = tzt.getTo()->clone();
    833             // Check to make sure firstFinalRule received proper clone.
    834             if (firstFinalRule == NULL) {
    835                 status = U_MEMORY_ALLOCATION_ERROR;
    836                 deleteTransitionRules();
    837                 return;
    838             }
    839             startTime = tzt.getTime();
    840         } else {
    841             // final rule with no transitions
    842             finalZoneWithStartYear = (SimpleTimeZone*)finalZone->clone();
    843             // Check to make sure finalZone was actually cloned.
    844             if (finalZoneWithStartYear == NULL) {
    845                 status = U_MEMORY_ALLOCATION_ERROR;
    846                 deleteTransitionRules();
    847                 return;
    848             }
    849             finalZone->getID(tzid);
    850             firstFinalRule = new TimeArrayTimeZoneRule(tzid,
    851                 finalZone->getRawOffset(), 0, &startTime, 1, DateTimeRule::UTC_TIME);
    852             // Check firstFinalRule was properly created.
    853             if (firstFinalRule == NULL) {
    854                 status = U_MEMORY_ALLOCATION_ERROR;
    855                 deleteTransitionRules();
    856                 return;
    857             }
    858         }
    859         TimeZoneRule *prevRule = NULL;
    860         if (transCount > 0) {
    861             prevRule = historicRules[typeMapData[transCount - 1]];
    862         }
    863         if (prevRule == NULL) {
    864             // No historic transitions, but only finalZone available
    865             prevRule = initialRule;
    866         }
    867         firstFinalTZTransition = new TimeZoneTransition();
    868         // Check to make sure firstFinalTZTransition was created before dereferencing
    869         if (firstFinalTZTransition == NULL) {
    870             status = U_MEMORY_ALLOCATION_ERROR;
    871             deleteTransitionRules();
    872             return;
    873         }
    874         firstFinalTZTransition->setTime(startTime);
    875         firstFinalTZTransition->adoptFrom(prevRule->clone());
    876         firstFinalTZTransition->adoptTo(firstFinalRule);
    877     }
    878 }
    879 
    880 UBool
    881 OlsonTimeZone::getNextTransition(UDate base, UBool inclusive, TimeZoneTransition& result) const {
    882     UErrorCode status = U_ZERO_ERROR;
    883     checkTransitionRules(status);
    884     if (U_FAILURE(status)) {
    885         return FALSE;
    886     }
    887 
    888     if (finalZone != NULL) {
    889         if (inclusive && base == firstFinalTZTransition->getTime()) {
    890             result = *firstFinalTZTransition;
    891             return TRUE;
    892         } else if (base >= firstFinalTZTransition->getTime()) {
    893             if (finalZone->useDaylightTime()) {
    894                 //return finalZone->getNextTransition(base, inclusive, result);
    895                 return finalZoneWithStartYear->getNextTransition(base, inclusive, result);
    896             } else {
    897                 // No more transitions
    898                 return FALSE;
    899             }
    900         }
    901     }
    902     if (historicRules != NULL) {
    903         // Find a historical transition
    904         int16_t transCount = transitionCount();
    905         int16_t ttidx = transCount - 1;
    906         for (; ttidx >= firstTZTransitionIdx; ttidx--) {
    907             UDate t = (UDate)transitionTime(ttidx);
    908             if (base > t || (!inclusive && base == t)) {
    909                 break;
    910             }
    911         }
    912         if (ttidx == transCount - 1)  {
    913             if (firstFinalTZTransition != NULL) {
    914                 result = *firstFinalTZTransition;
    915                 return TRUE;
    916             } else {
    917                 return FALSE;
    918             }
    919         } else if (ttidx < firstTZTransitionIdx) {
    920             result = *firstTZTransition;
    921             return TRUE;
    922         } else {
    923             // Create a TimeZoneTransition
    924             TimeZoneRule *to = historicRules[typeMapData[ttidx + 1]];
    925             TimeZoneRule *from = historicRules[typeMapData[ttidx]];
    926             UDate startTime = (UDate)transitionTime(ttidx+1);
    927 
    928             // The transitions loaded from zoneinfo.res may contain non-transition data
    929             UnicodeString fromName, toName;
    930             from->getName(fromName);
    931             to->getName(toName);
    932             if (fromName == toName && from->getRawOffset() == to->getRawOffset()
    933                     && from->getDSTSavings() == to->getDSTSavings()) {
    934                 return getNextTransition(startTime, false, result);
    935             }
    936             result.setTime(startTime);
    937             result.adoptFrom(from->clone());
    938             result.adoptTo(to->clone());
    939             return TRUE;
    940         }
    941     }
    942     return FALSE;
    943 }
    944 
    945 UBool
    946 OlsonTimeZone::getPreviousTransition(UDate base, UBool inclusive, TimeZoneTransition& result) const {
    947     UErrorCode status = U_ZERO_ERROR;
    948     checkTransitionRules(status);
    949     if (U_FAILURE(status)) {
    950         return FALSE;
    951     }
    952 
    953     if (finalZone != NULL) {
    954         if (inclusive && base == firstFinalTZTransition->getTime()) {
    955             result = *firstFinalTZTransition;
    956             return TRUE;
    957         } else if (base > firstFinalTZTransition->getTime()) {
    958             if (finalZone->useDaylightTime()) {
    959                 //return finalZone->getPreviousTransition(base, inclusive, result);
    960                 return finalZoneWithStartYear->getPreviousTransition(base, inclusive, result);
    961             } else {
    962                 result = *firstFinalTZTransition;
    963                 return TRUE;
    964             }
    965         }
    966     }
    967 
    968     if (historicRules != NULL) {
    969         // Find a historical transition
    970         int16_t ttidx = transitionCount() - 1;
    971         for (; ttidx >= firstTZTransitionIdx; ttidx--) {
    972             UDate t = (UDate)transitionTime(ttidx);
    973             if (base > t || (inclusive && base == t)) {
    974                 break;
    975             }
    976         }
    977         if (ttidx < firstTZTransitionIdx) {
    978             // No more transitions
    979             return FALSE;
    980         } else if (ttidx == firstTZTransitionIdx) {
    981             result = *firstTZTransition;
    982             return TRUE;
    983         } else {
    984             // Create a TimeZoneTransition
    985             TimeZoneRule *to = historicRules[typeMapData[ttidx]];
    986             TimeZoneRule *from = historicRules[typeMapData[ttidx-1]];
    987             UDate startTime = (UDate)transitionTime(ttidx);
    988 
    989             // The transitions loaded from zoneinfo.res may contain non-transition data
    990             UnicodeString fromName, toName;
    991             from->getName(fromName);
    992             to->getName(toName);
    993             if (fromName == toName && from->getRawOffset() == to->getRawOffset()
    994                     && from->getDSTSavings() == to->getDSTSavings()) {
    995                 return getPreviousTransition(startTime, false, result);
    996             }
    997             result.setTime(startTime);
    998             result.adoptFrom(from->clone());
    999             result.adoptTo(to->clone());
   1000             return TRUE;
   1001         }
   1002     }
   1003     return FALSE;
   1004 }
   1005 
   1006 int32_t
   1007 OlsonTimeZone::countTransitionRules(UErrorCode& status) const {
   1008     if (U_FAILURE(status)) {
   1009         return 0;
   1010     }
   1011     checkTransitionRules(status);
   1012     if (U_FAILURE(status)) {
   1013         return 0;
   1014     }
   1015 
   1016     int32_t count = 0;
   1017     if (historicRules != NULL) {
   1018         // historicRules may contain null entries when original zoneinfo data
   1019         // includes non transition data.
   1020         for (int32_t i = 0; i < historicRuleCount; i++) {
   1021             if (historicRules[i] != NULL) {
   1022                 count++;
   1023             }
   1024         }
   1025     }
   1026     if (finalZone != NULL) {
   1027         if (finalZone->useDaylightTime()) {
   1028             count += 2;
   1029         } else {
   1030             count++;
   1031         }
   1032     }
   1033     return count;
   1034 }
   1035 
   1036 void
   1037 OlsonTimeZone::getTimeZoneRules(const InitialTimeZoneRule*& initial,
   1038                                 const TimeZoneRule* trsrules[],
   1039                                 int32_t& trscount,
   1040                                 UErrorCode& status) const {
   1041     if (U_FAILURE(status)) {
   1042         return;
   1043     }
   1044     checkTransitionRules(status);
   1045     if (U_FAILURE(status)) {
   1046         return;
   1047     }
   1048 
   1049     // Initial rule
   1050     initial = initialRule;
   1051 
   1052     // Transition rules
   1053     int32_t cnt = 0;
   1054     if (historicRules != NULL && trscount > cnt) {
   1055         // historicRules may contain null entries when original zoneinfo data
   1056         // includes non transition data.
   1057         for (int32_t i = 0; i < historicRuleCount; i++) {
   1058             if (historicRules[i] != NULL) {
   1059                 trsrules[cnt++] = historicRules[i];
   1060                 if (cnt >= trscount) {
   1061                     break;
   1062                 }
   1063             }
   1064         }
   1065     }
   1066     if (finalZoneWithStartYear != NULL && trscount > cnt) {
   1067         const InitialTimeZoneRule *tmpini;
   1068         int32_t tmpcnt = trscount - cnt;
   1069         finalZoneWithStartYear->getTimeZoneRules(tmpini, &trsrules[cnt], tmpcnt, status);
   1070         if (U_FAILURE(status)) {
   1071             return;
   1072         }
   1073         cnt += tmpcnt;
   1074     }
   1075     // Set the result length
   1076     trscount = cnt;
   1077 }
   1078 
   1079 U_NAMESPACE_END
   1080 
   1081 #endif // !UCONFIG_NO_FORMATTING
   1082 
   1083 //eof
   1084