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