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