Home | History | Annotate | Download | only in i18n
      1 /*
      2 *******************************************************************************
      3 * Copyright (C) 2007, International Business Machines Corporation and         *
      4 * others. All Rights Reserved.                                                *
      5 *******************************************************************************
      6 */
      7 
      8 #include "unicode/utypes.h"
      9 
     10 #if !UCONFIG_NO_FORMATTING
     11 
     12 #include "unicode/tzrule.h"
     13 #include "unicode/ucal.h"
     14 #include "gregoimp.h"
     15 #include "cmemory.h"
     16 #include "uarrsort.h"
     17 
     18 U_CDECL_BEGIN
     19 // UComparator function for sorting start times
     20 static int32_t U_CALLCONV
     21 compareDates(const void * /*context*/, const void *left, const void *right) {
     22     UDate l = *((UDate*)left);
     23     UDate r = *((UDate*)right);
     24     int32_t res = l < r ? -1 : (l == r ? 0 : 1);
     25     return res;
     26 }
     27 U_CDECL_END
     28 
     29 U_NAMESPACE_BEGIN
     30 
     31 TimeZoneRule::TimeZoneRule(const UnicodeString& name, int32_t rawOffset, int32_t dstSavings)
     32 : UObject(), fName(name), fRawOffset(rawOffset), fDSTSavings(dstSavings) {
     33 }
     34 
     35 TimeZoneRule::TimeZoneRule(const TimeZoneRule& source)
     36 : UObject(source), fName(source.fName), fRawOffset(source.fRawOffset), fDSTSavings(source.fDSTSavings) {
     37 }
     38 
     39 TimeZoneRule::~TimeZoneRule() {
     40 }
     41 
     42 TimeZoneRule&
     43 TimeZoneRule::operator=(const TimeZoneRule& right) {
     44     if (this != &right) {
     45         fName = right.fName;
     46         fRawOffset = right.fRawOffset;
     47         fDSTSavings = right.fDSTSavings;
     48     }
     49     return *this;
     50 }
     51 
     52 UBool
     53 TimeZoneRule::operator==(const TimeZoneRule& that) const {
     54     return ((this == &that) ||
     55             (getDynamicClassID() == that.getDynamicClassID() &&
     56             fName == that.fName &&
     57             fRawOffset == that.fRawOffset &&
     58             fDSTSavings == that.fDSTSavings));
     59 }
     60 
     61 UBool
     62 TimeZoneRule::operator!=(const TimeZoneRule& that) const {
     63     return !operator==(that);
     64 }
     65 
     66 UnicodeString&
     67 TimeZoneRule::getName(UnicodeString& name) const {
     68     name = fName;
     69     return name;
     70 }
     71 
     72 int32_t
     73 TimeZoneRule::getRawOffset(void) const {
     74     return fRawOffset;
     75 }
     76 
     77 int32_t
     78 TimeZoneRule::getDSTSavings(void) const {
     79     return fDSTSavings;
     80 }
     81 
     82 UBool
     83 TimeZoneRule::isEquivalentTo(const TimeZoneRule& other) const {
     84     return ((this == &other) ||
     85             (getDynamicClassID() == other.getDynamicClassID() &&
     86             fRawOffset == other.fRawOffset &&
     87             fDSTSavings == other.fDSTSavings));
     88 }
     89 
     90 
     91 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(InitialTimeZoneRule)
     92 
     93 InitialTimeZoneRule::InitialTimeZoneRule(const UnicodeString& name,
     94                                          int32_t rawOffset,
     95                                          int32_t dstSavings)
     96 : TimeZoneRule(name, rawOffset, dstSavings) {
     97 }
     98 
     99 InitialTimeZoneRule::InitialTimeZoneRule(const InitialTimeZoneRule& source)
    100 : TimeZoneRule(source) {
    101 }
    102 
    103 InitialTimeZoneRule::~InitialTimeZoneRule() {
    104 }
    105 
    106 InitialTimeZoneRule*
    107 InitialTimeZoneRule::clone(void) const {
    108     return new InitialTimeZoneRule(*this);
    109 }
    110 
    111 InitialTimeZoneRule&
    112 InitialTimeZoneRule::operator=(const InitialTimeZoneRule& right) {
    113     if (this != &right) {
    114         TimeZoneRule::operator=(right);
    115     }
    116     return *this;
    117 }
    118 
    119 UBool
    120 InitialTimeZoneRule::operator==(const TimeZoneRule& that) const {
    121     return ((this == &that) ||
    122             (getDynamicClassID() == that.getDynamicClassID() &&
    123             TimeZoneRule::operator==(that)));
    124 }
    125 
    126 UBool
    127 InitialTimeZoneRule::operator!=(const TimeZoneRule& that) const {
    128     return !operator==(that);
    129 }
    130 
    131 UBool
    132 InitialTimeZoneRule::isEquivalentTo(const TimeZoneRule& other) const {
    133     if (this == &other) {
    134         return TRUE;
    135     }
    136     if (getDynamicClassID() != other.getDynamicClassID() ||
    137         TimeZoneRule::isEquivalentTo(other) == FALSE) {
    138         return FALSE;
    139     }
    140     return TRUE;
    141 }
    142 
    143 UBool
    144 InitialTimeZoneRule::getFirstStart(int32_t /*prevRawOffset*/,
    145                                   int32_t /*prevDSTSavings*/,
    146                                   UDate& /*result*/) const {
    147     return FALSE;
    148 }
    149 
    150 UBool
    151 InitialTimeZoneRule::getFinalStart(int32_t /*prevRawOffset*/,
    152                                   int32_t /*prevDSTSavings*/,
    153                                   UDate& /*result*/) const {
    154     return FALSE;
    155 }
    156 
    157 UBool
    158 InitialTimeZoneRule::getNextStart(const UDate /*base*/,
    159                                  int32_t /*prevRawOffset*/,
    160                                  int32_t /*prevDSTSavings*/,
    161                                  UBool /*inclusive*/,
    162                                  UDate& /*result*/) const {
    163     return FALSE;
    164 }
    165 
    166 UBool
    167 InitialTimeZoneRule::getPreviousStart(const UDate /*base*/,
    168                                      int32_t /*prevRawOffset*/,
    169                                      int32_t /*prevDSTSavings*/,
    170                                      UBool /*inclusive*/,
    171                                      UDate& /*result*/) const {
    172     return FALSE;
    173 }
    174 
    175 
    176 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(AnnualTimeZoneRule)
    177 
    178 const int32_t AnnualTimeZoneRule::MAX_YEAR = 0x7FFFFFFF; /* max signed int32 */
    179 
    180 AnnualTimeZoneRule::AnnualTimeZoneRule(const UnicodeString& name,
    181                                        int32_t rawOffset,
    182                                        int32_t dstSavings,
    183                                        const DateTimeRule& dateTimeRule,
    184                                        int32_t startYear,
    185                                        int32_t endYear)
    186 : TimeZoneRule(name, rawOffset, dstSavings), fDateTimeRule(new DateTimeRule(dateTimeRule)),
    187   fStartYear(startYear), fEndYear(endYear) {
    188 }
    189 
    190 AnnualTimeZoneRule::AnnualTimeZoneRule(const UnicodeString& name,
    191                                        int32_t rawOffset,
    192                                        int32_t dstSavings,
    193                                        DateTimeRule* dateTimeRule,
    194                                        int32_t startYear,
    195                                        int32_t endYear)
    196 : TimeZoneRule(name, rawOffset, dstSavings), fDateTimeRule(dateTimeRule),
    197   fStartYear(startYear), fEndYear(endYear) {
    198 }
    199 
    200 AnnualTimeZoneRule::AnnualTimeZoneRule(const AnnualTimeZoneRule& source)
    201 : TimeZoneRule(source), fDateTimeRule(new DateTimeRule(*(source.fDateTimeRule))),
    202   fStartYear(source.fStartYear), fEndYear(source.fEndYear) {
    203 }
    204 
    205 AnnualTimeZoneRule::~AnnualTimeZoneRule() {
    206     delete fDateTimeRule;
    207 }
    208 
    209 AnnualTimeZoneRule*
    210 AnnualTimeZoneRule::clone(void) const {
    211     return new AnnualTimeZoneRule(*this);
    212 }
    213 
    214 AnnualTimeZoneRule&
    215 AnnualTimeZoneRule::operator=(const AnnualTimeZoneRule& right) {
    216     if (this != &right) {
    217         TimeZoneRule::operator=(right);
    218         delete fDateTimeRule;
    219         fDateTimeRule = right.fDateTimeRule->clone();
    220         fStartYear = right.fStartYear;
    221         fEndYear = right.fEndYear;
    222     }
    223     return *this;
    224 }
    225 
    226 UBool
    227 AnnualTimeZoneRule::operator==(const TimeZoneRule& that) const {
    228     if (this == &that) {
    229         return TRUE;
    230     }
    231     if (getDynamicClassID() != that.getDynamicClassID()) {
    232         return FALSE;
    233     }
    234     AnnualTimeZoneRule *atzr = (AnnualTimeZoneRule*)&that;
    235     return (*fDateTimeRule == *(atzr->fDateTimeRule) &&
    236             fStartYear == atzr->fStartYear &&
    237             fEndYear == atzr->fEndYear);
    238 }
    239 
    240 UBool
    241 AnnualTimeZoneRule::operator!=(const TimeZoneRule& that) const {
    242     return !operator==(that);
    243 }
    244 
    245 const DateTimeRule*
    246 AnnualTimeZoneRule::getRule() const {
    247     return fDateTimeRule;
    248 }
    249 
    250 int32_t
    251 AnnualTimeZoneRule::getStartYear() const {
    252     return fStartYear;
    253 }
    254 
    255 int32_t
    256 AnnualTimeZoneRule::getEndYear() const {
    257     return fEndYear;
    258 }
    259 
    260 UBool
    261 AnnualTimeZoneRule::getStartInYear(int32_t year,
    262                                    int32_t prevRawOffset,
    263                                    int32_t prevDSTSavings,
    264                                    UDate &result) const {
    265     if (year < fStartYear || year > fEndYear) {
    266         return FALSE;
    267     }
    268     double ruleDay;
    269     DateTimeRule::DateRuleType type = fDateTimeRule->getDateRuleType();
    270     if (type == DateTimeRule::DOM) {
    271         ruleDay = Grego::fieldsToDay(year, fDateTimeRule->getRuleMonth(), fDateTimeRule->getRuleDayOfMonth());
    272     } else {
    273         UBool after = TRUE;
    274         if (type == DateTimeRule::DOW) {
    275             // Normalize DOW rule into DOW_GEQ_DOM or DOW_LEQ_DOM
    276             int32_t weeks = fDateTimeRule->getRuleWeekInMonth();
    277             if (weeks > 0) {
    278                 ruleDay = Grego::fieldsToDay(year, fDateTimeRule->getRuleMonth(), 1);
    279                 ruleDay += 7 * (weeks - 1);
    280             } else {
    281                 after = FALSE;
    282                 ruleDay = Grego::fieldsToDay(year, fDateTimeRule->getRuleMonth(),
    283                     Grego::monthLength(year, fDateTimeRule->getRuleMonth()));
    284                 ruleDay += 7 * (weeks + 1);
    285            }
    286         } else {
    287             int32_t month = fDateTimeRule->getRuleMonth();
    288             int32_t dom = fDateTimeRule->getRuleDayOfMonth();
    289             if (type == DateTimeRule::DOW_LEQ_DOM) {
    290                 after = FALSE;
    291                 // Handle Feb <=29
    292                 if (month == UCAL_FEBRUARY && dom == 29 && !Grego::isLeapYear(year)) {
    293                     dom--;
    294                 }
    295             }
    296             ruleDay = Grego::fieldsToDay(year, month, dom);
    297         }
    298         int32_t dow = Grego::dayOfWeek(ruleDay);
    299         int32_t delta = fDateTimeRule->getRuleDayOfWeek() - dow;
    300         if (after) {
    301             delta = delta < 0 ? delta + 7 : delta;
    302         } else {
    303             delta = delta > 0 ? delta - 7 : delta;
    304         }
    305         ruleDay += delta;
    306     }
    307 
    308     result = ruleDay*U_MILLIS_PER_DAY + fDateTimeRule->getRuleMillisInDay();
    309     if (fDateTimeRule->getTimeRuleType() != DateTimeRule::UTC_TIME) {
    310         result -= prevRawOffset;
    311     }
    312     if (fDateTimeRule->getTimeRuleType() == DateTimeRule::WALL_TIME) {
    313         result -= prevDSTSavings;
    314     }
    315     return TRUE;
    316 }
    317 
    318 UBool
    319 AnnualTimeZoneRule::isEquivalentTo(const TimeZoneRule& other) const {
    320     if (this == &other) {
    321         return TRUE;
    322     }
    323     if (getDynamicClassID() != other.getDynamicClassID() ||
    324         TimeZoneRule::isEquivalentTo(other) == FALSE) {
    325         return FALSE;
    326     }
    327     AnnualTimeZoneRule* that = (AnnualTimeZoneRule*)&other;
    328     return (*fDateTimeRule == *(that->fDateTimeRule) &&
    329             fStartYear == that->fStartYear &&
    330             fEndYear == that->fEndYear);
    331 }
    332 
    333 UBool
    334 AnnualTimeZoneRule::getFirstStart(int32_t prevRawOffset,
    335                                   int32_t prevDSTSavings,
    336                                   UDate& result) const {
    337     return getStartInYear(fStartYear, prevRawOffset, prevDSTSavings, result);
    338 }
    339 
    340 UBool
    341 AnnualTimeZoneRule::getFinalStart(int32_t prevRawOffset,
    342                                   int32_t prevDSTSavings,
    343                                   UDate& result) const {
    344     if (fEndYear == MAX_YEAR) {
    345         return FALSE;
    346     }
    347     return getStartInYear(fEndYear, prevRawOffset, prevDSTSavings, result);
    348 }
    349 
    350 UBool
    351 AnnualTimeZoneRule::getNextStart(const UDate base,
    352                                  int32_t prevRawOffset,
    353                                  int32_t prevDSTSavings,
    354                                  UBool inclusive,
    355                                  UDate& result) const {
    356     int32_t year, month, dom, dow, doy, mid;
    357     Grego::timeToFields(base, year, month, dom, dow, doy, mid);
    358     if (year < fStartYear) {
    359         return getFirstStart(prevRawOffset, prevDSTSavings, result);
    360     }
    361     UDate tmp;
    362     if (getStartInYear(year, prevRawOffset, prevDSTSavings, tmp)) {
    363         if (tmp < base || (!inclusive && (tmp == base))) {
    364             // Return the next one
    365             return getStartInYear(year + 1, prevRawOffset, prevDSTSavings, result);
    366         } else {
    367             result = tmp;
    368             return TRUE;
    369         }
    370     }
    371     return FALSE;
    372 }
    373 
    374 UBool
    375 AnnualTimeZoneRule::getPreviousStart(const UDate base,
    376                                      int32_t prevRawOffset,
    377                                      int32_t prevDSTSavings,
    378                                      UBool inclusive,
    379                                      UDate& result) const {
    380     int32_t year, month, dom, dow, doy, mid;
    381     Grego::timeToFields(base, year, month, dom, dow, doy, mid);
    382     if (year > fEndYear) {
    383         return getFinalStart(prevRawOffset, prevDSTSavings, result);
    384     }
    385     UDate tmp;
    386     if (getStartInYear(year, prevRawOffset, prevDSTSavings, tmp)) {
    387         if (tmp > base || (!inclusive && (tmp == base))) {
    388             // Return the previous one
    389             return getStartInYear(year - 1, prevRawOffset, prevDSTSavings, result);
    390         } else {
    391             result = tmp;
    392             return TRUE;
    393         }
    394     }
    395     return FALSE;
    396 }
    397 
    398 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(TimeArrayTimeZoneRule)
    399 
    400 TimeArrayTimeZoneRule::TimeArrayTimeZoneRule(const UnicodeString& name,
    401                                              int32_t rawOffset,
    402                                              int32_t dstSavings,
    403                                              const UDate* startTimes,
    404                                              int32_t numStartTimes,
    405                                              DateTimeRule::TimeRuleType timeRuleType)
    406 : TimeZoneRule(name, rawOffset, dstSavings), fTimeRuleType(timeRuleType),
    407   fStartTimes(NULL) {
    408     UErrorCode status = U_ZERO_ERROR;
    409     initStartTimes(startTimes, numStartTimes, status);
    410     //TODO - status?
    411 }
    412 
    413 
    414 TimeArrayTimeZoneRule::TimeArrayTimeZoneRule(const TimeArrayTimeZoneRule& source)
    415 : TimeZoneRule(source), fTimeRuleType(source.fTimeRuleType), fStartTimes(NULL) {
    416     UErrorCode status = U_ZERO_ERROR;
    417     initStartTimes(source.fStartTimes, source.fNumStartTimes, status);
    418     //TODO - status?
    419 }
    420 
    421 
    422 TimeArrayTimeZoneRule::~TimeArrayTimeZoneRule() {
    423     if (fStartTimes != NULL && fStartTimes != fLocalStartTimes) {
    424         uprv_free(fStartTimes);
    425     }
    426 }
    427 
    428 TimeArrayTimeZoneRule*
    429 TimeArrayTimeZoneRule::clone(void) const {
    430     return new TimeArrayTimeZoneRule(*this);
    431 }
    432 
    433 
    434 TimeArrayTimeZoneRule&
    435 TimeArrayTimeZoneRule::operator=(const TimeArrayTimeZoneRule& right) {
    436     if (this != &right) {
    437         TimeZoneRule::operator=(right);
    438         UErrorCode status = U_ZERO_ERROR;
    439         initStartTimes(right.fStartTimes, right.fNumStartTimes, status);
    440         //TODO - status?
    441         fTimeRuleType = right.fTimeRuleType;
    442     }
    443     return *this;
    444 }
    445 
    446 UBool
    447 TimeArrayTimeZoneRule::operator==(const TimeZoneRule& that) const {
    448     if (this == &that) {
    449         return TRUE;
    450     }
    451     if (getDynamicClassID() != that.getDynamicClassID()
    452         || TimeZoneRule::operator==(that) == FALSE) {
    453         return FALSE;
    454     }
    455     TimeArrayTimeZoneRule *tatzr = (TimeArrayTimeZoneRule*)&that;
    456     if (fTimeRuleType != tatzr->fTimeRuleType ||
    457         fNumStartTimes != tatzr->fNumStartTimes) {
    458         return FALSE;
    459     }
    460     // Compare start times
    461     UBool res = TRUE;
    462     for (int32_t i = 0; i < fNumStartTimes; i++) {
    463         if (fStartTimes[i] != tatzr->fStartTimes[i]) {
    464             res = FALSE;
    465             break;
    466         }
    467     }
    468     return res;
    469 }
    470 
    471 UBool
    472 TimeArrayTimeZoneRule::operator!=(const TimeZoneRule& that) const {
    473     return !operator==(that);
    474 }
    475 
    476 DateTimeRule::TimeRuleType
    477 TimeArrayTimeZoneRule::getTimeType(void) const {
    478     return fTimeRuleType;
    479 }
    480 
    481 UBool
    482 TimeArrayTimeZoneRule::getStartTimeAt(int32_t index, UDate& result) const {
    483     if (index >= fNumStartTimes || index < 0) {
    484         return FALSE;
    485     }
    486     result = fStartTimes[index];
    487     return TRUE;
    488 }
    489 
    490 int32_t
    491 TimeArrayTimeZoneRule::countStartTimes(void) const {
    492     return fNumStartTimes;
    493 }
    494 
    495 UBool
    496 TimeArrayTimeZoneRule::isEquivalentTo(const TimeZoneRule& other) const {
    497     if (this == &other) {
    498         return TRUE;
    499     }
    500     if (getDynamicClassID() != other.getDynamicClassID()
    501         || TimeZoneRule::isEquivalentTo(other) == FALSE) {
    502         return FALSE;
    503     }
    504     TimeArrayTimeZoneRule* that = (TimeArrayTimeZoneRule*)&other;
    505     if (fTimeRuleType != that->fTimeRuleType ||
    506         fNumStartTimes != that->fNumStartTimes) {
    507         return FALSE;
    508     }
    509     // Compare start times
    510     UBool res = TRUE;
    511     for (int32_t i = 0; i < fNumStartTimes; i++) {
    512         if (fStartTimes[i] != that->fStartTimes[i]) {
    513             res = FALSE;
    514             break;
    515         }
    516     }
    517     return res;
    518 }
    519 
    520 UBool
    521 TimeArrayTimeZoneRule::getFirstStart(int32_t prevRawOffset,
    522                                              int32_t prevDSTSavings,
    523                                              UDate& result) const {
    524     if (fNumStartTimes <= 0 || fStartTimes == NULL) {
    525         return FALSE;
    526     }
    527     result = getUTC(fStartTimes[0], prevRawOffset, prevDSTSavings);
    528     return TRUE;
    529 }
    530 
    531 UBool
    532 TimeArrayTimeZoneRule::getFinalStart(int32_t prevRawOffset,
    533                                      int32_t prevDSTSavings,
    534                                      UDate& result) const {
    535     if (fNumStartTimes <= 0 || fStartTimes == NULL) {
    536         return FALSE;
    537     }
    538     result = getUTC(fStartTimes[fNumStartTimes - 1], prevRawOffset, prevDSTSavings);
    539     return TRUE;
    540 }
    541 
    542 UBool
    543 TimeArrayTimeZoneRule::getNextStart(const UDate base,
    544                                     int32_t prevRawOffset,
    545                                     int32_t prevDSTSavings,
    546                                     UBool inclusive,
    547                                     UDate& result) const {
    548     int32_t i = fNumStartTimes - 1;
    549     for (; i >= 0; i--) {
    550         UDate time = getUTC(fStartTimes[i], prevRawOffset, prevDSTSavings);
    551         if (time < base || (!inclusive && time == base)) {
    552             break;
    553         }
    554         result = time;
    555     }
    556     if (i == fNumStartTimes - 1) {
    557         return FALSE;
    558     }
    559     return TRUE;
    560 }
    561 
    562 UBool
    563 TimeArrayTimeZoneRule::getPreviousStart(const UDate base,
    564                                         int32_t prevRawOffset,
    565                                         int32_t prevDSTSavings,
    566                                         UBool inclusive,
    567                                         UDate& result) const {
    568     int32_t i = fNumStartTimes - 1;
    569     for (; i >= 0; i--) {
    570         UDate time = getUTC(fStartTimes[i], prevRawOffset, prevDSTSavings);
    571         if (time < base || (inclusive && time == base)) {
    572             result = time;
    573             return TRUE;
    574         }
    575     }
    576     return FALSE;
    577 }
    578 
    579 
    580 // ---- private methods ------
    581 
    582 UBool
    583 TimeArrayTimeZoneRule::initStartTimes(const UDate source[], int32_t size, UErrorCode& status) {
    584     // Free old array
    585     if (fStartTimes != NULL && fStartTimes != fLocalStartTimes) {
    586         uprv_free(fStartTimes);
    587     }
    588     // Allocate new one if needed
    589     if (size > TIMEARRAY_STACK_BUFFER_SIZE) {
    590         fStartTimes = (UDate*)uprv_malloc(sizeof(UDate)*size);
    591         if (fStartTimes == NULL) {
    592             status = U_MEMORY_ALLOCATION_ERROR;
    593             fNumStartTimes = 0;
    594             return FALSE;
    595         }
    596     } else {
    597         fStartTimes = (UDate*)fLocalStartTimes;
    598     }
    599     uprv_memcpy(fStartTimes, source, sizeof(UDate)*size);
    600     fNumStartTimes = size;
    601     // Sort dates
    602     uprv_sortArray(fStartTimes, fNumStartTimes, (int32_t)sizeof(UDate), compareDates, NULL, TRUE, &status);
    603     if (U_FAILURE(status)) {
    604         if (fStartTimes != NULL && fStartTimes != fLocalStartTimes) {
    605             uprv_free(fStartTimes);
    606         }
    607         fNumStartTimes = 0;
    608         return FALSE;
    609     }
    610     return TRUE;
    611 }
    612 
    613 UDate
    614 TimeArrayTimeZoneRule::getUTC(UDate time, int32_t raw, int32_t dst) const {
    615     if (fTimeRuleType != DateTimeRule::UTC_TIME) {
    616         time -= raw;
    617     }
    618     if (fTimeRuleType == DateTimeRule::WALL_TIME) {
    619         time -= dst;
    620     }
    621     return time;
    622 }
    623 
    624 U_NAMESPACE_END
    625 
    626 #endif /* #if !UCONFIG_NO_FORMATTING */
    627 
    628 //eof
    629 
    630