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