Home | History | Annotate | Download | only in i18n
      1 //  2016 and later: Unicode, Inc. and others.
      2 // License & terms of use: http://www.unicode.org/copyright.html
      3 /*
      4 *******************************************************************************
      5 * Copyright (C) 2007-2012, International Business Machines Corporation and
      6 * others. All Rights Reserved.
      7 *******************************************************************************
      8 */
      9 
     10 #include "utypeinfo.h"  // for 'typeid' to work
     11 
     12 #include "unicode/utypes.h"
     13 
     14 #if !UCONFIG_NO_FORMATTING
     15 
     16 #include "unicode/tzrule.h"
     17 #include "unicode/ucal.h"
     18 #include "gregoimp.h"
     19 #include "cmemory.h"
     20 #include "uarrsort.h"
     21 
     22 U_CDECL_BEGIN
     23 // UComparator function for sorting start times
     24 static int32_t U_CALLCONV
     25 compareDates(const void * /*context*/, const void *left, const void *right) {
     26     UDate l = *((UDate*)left);
     27     UDate r = *((UDate*)right);
     28     int32_t res = l < r ? -1 : (l == r ? 0 : 1);
     29     return res;
     30 }
     31 U_CDECL_END
     32 
     33 U_NAMESPACE_BEGIN
     34 
     35 TimeZoneRule::TimeZoneRule(const UnicodeString& name, int32_t rawOffset, int32_t dstSavings)
     36 : UObject(), fName(name), fRawOffset(rawOffset), fDSTSavings(dstSavings) {
     37 }
     38 
     39 TimeZoneRule::TimeZoneRule(const TimeZoneRule& source)
     40 : UObject(source), fName(source.fName), fRawOffset(source.fRawOffset), fDSTSavings(source.fDSTSavings) {
     41 }
     42 
     43 TimeZoneRule::~TimeZoneRule() {
     44 }
     45 
     46 TimeZoneRule&
     47 TimeZoneRule::operator=(const TimeZoneRule& right) {
     48     if (this != &right) {
     49         fName = right.fName;
     50         fRawOffset = right.fRawOffset;
     51         fDSTSavings = right.fDSTSavings;
     52     }
     53     return *this;
     54 }
     55 
     56 UBool
     57 TimeZoneRule::operator==(const TimeZoneRule& that) const {
     58     return ((this == &that) ||
     59             (typeid(*this) == typeid(that) &&
     60             fName == that.fName &&
     61             fRawOffset == that.fRawOffset &&
     62             fDSTSavings == that.fDSTSavings));
     63 }
     64 
     65 UBool
     66 TimeZoneRule::operator!=(const TimeZoneRule& that) const {
     67     return !operator==(that);
     68 }
     69 
     70 UnicodeString&
     71 TimeZoneRule::getName(UnicodeString& name) const {
     72     name = fName;
     73     return name;
     74 }
     75 
     76 int32_t
     77 TimeZoneRule::getRawOffset(void) const {
     78     return fRawOffset;
     79 }
     80 
     81 int32_t
     82 TimeZoneRule::getDSTSavings(void) const {
     83     return fDSTSavings;
     84 }
     85 
     86 UBool
     87 TimeZoneRule::isEquivalentTo(const TimeZoneRule& other) const {
     88     return ((this == &other) ||
     89             (typeid(*this) == typeid(other) &&
     90             fRawOffset == other.fRawOffset &&
     91             fDSTSavings == other.fDSTSavings));
     92 }
     93 
     94 
     95 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(InitialTimeZoneRule)
     96 
     97 InitialTimeZoneRule::InitialTimeZoneRule(const UnicodeString& name,
     98                                          int32_t rawOffset,
     99                                          int32_t dstSavings)
    100 : TimeZoneRule(name, rawOffset, dstSavings) {
    101 }
    102 
    103 InitialTimeZoneRule::InitialTimeZoneRule(const InitialTimeZoneRule& source)
    104 : TimeZoneRule(source) {
    105 }
    106 
    107 InitialTimeZoneRule::~InitialTimeZoneRule() {
    108 }
    109 
    110 InitialTimeZoneRule*
    111 InitialTimeZoneRule::clone(void) const {
    112     return new InitialTimeZoneRule(*this);
    113 }
    114 
    115 InitialTimeZoneRule&
    116 InitialTimeZoneRule::operator=(const InitialTimeZoneRule& right) {
    117     if (this != &right) {
    118         TimeZoneRule::operator=(right);
    119     }
    120     return *this;
    121 }
    122 
    123 UBool
    124 InitialTimeZoneRule::operator==(const TimeZoneRule& that) const {
    125     return ((this == &that) ||
    126             (typeid(*this) == typeid(that) &&
    127             TimeZoneRule::operator==(that)));
    128 }
    129 
    130 UBool
    131 InitialTimeZoneRule::operator!=(const TimeZoneRule& that) const {
    132     return !operator==(that);
    133 }
    134 
    135 UBool
    136 InitialTimeZoneRule::isEquivalentTo(const TimeZoneRule& other) const {
    137     if (this == &other) {
    138         return TRUE;
    139     }
    140     if (typeid(*this) != typeid(other) || TimeZoneRule::isEquivalentTo(other) == FALSE) {
    141         return FALSE;
    142     }
    143     return TRUE;
    144 }
    145 
    146 UBool
    147 InitialTimeZoneRule::getFirstStart(int32_t /*prevRawOffset*/,
    148                                   int32_t /*prevDSTSavings*/,
    149                                   UDate& /*result*/) const {
    150     return FALSE;
    151 }
    152 
    153 UBool
    154 InitialTimeZoneRule::getFinalStart(int32_t /*prevRawOffset*/,
    155                                   int32_t /*prevDSTSavings*/,
    156                                   UDate& /*result*/) const {
    157     return FALSE;
    158 }
    159 
    160 UBool
    161 InitialTimeZoneRule::getNextStart(UDate /*base*/,
    162                                  int32_t /*prevRawOffset*/,
    163                                  int32_t /*prevDSTSavings*/,
    164                                  UBool /*inclusive*/,
    165                                  UDate& /*result*/) const {
    166     return FALSE;
    167 }
    168 
    169 UBool
    170 InitialTimeZoneRule::getPreviousStart(UDate /*base*/,
    171                                      int32_t /*prevRawOffset*/,
    172                                      int32_t /*prevDSTSavings*/,
    173                                      UBool /*inclusive*/,
    174                                      UDate& /*result*/) const {
    175     return FALSE;
    176 }
    177 
    178 
    179 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(AnnualTimeZoneRule)
    180 
    181 const int32_t AnnualTimeZoneRule::MAX_YEAR = 0x7FFFFFFF; /* max signed int32 */
    182 
    183 AnnualTimeZoneRule::AnnualTimeZoneRule(const UnicodeString& name,
    184                                        int32_t rawOffset,
    185                                        int32_t dstSavings,
    186                                        const DateTimeRule& dateTimeRule,
    187                                        int32_t startYear,
    188                                        int32_t endYear)
    189 : TimeZoneRule(name, rawOffset, dstSavings), fDateTimeRule(new DateTimeRule(dateTimeRule)),
    190   fStartYear(startYear), fEndYear(endYear) {
    191 }
    192 
    193 AnnualTimeZoneRule::AnnualTimeZoneRule(const UnicodeString& name,
    194                                        int32_t rawOffset,
    195                                        int32_t dstSavings,
    196                                        DateTimeRule* dateTimeRule,
    197                                        int32_t startYear,
    198                                        int32_t endYear)
    199 : TimeZoneRule(name, rawOffset, dstSavings), fDateTimeRule(dateTimeRule),
    200   fStartYear(startYear), fEndYear(endYear) {
    201 }
    202 
    203 AnnualTimeZoneRule::AnnualTimeZoneRule(const AnnualTimeZoneRule& source)
    204 : TimeZoneRule(source), fDateTimeRule(new DateTimeRule(*(source.fDateTimeRule))),
    205   fStartYear(source.fStartYear), fEndYear(source.fEndYear) {
    206 }
    207 
    208 AnnualTimeZoneRule::~AnnualTimeZoneRule() {
    209     delete fDateTimeRule;
    210 }
    211 
    212 AnnualTimeZoneRule*
    213 AnnualTimeZoneRule::clone(void) const {
    214     return new AnnualTimeZoneRule(*this);
    215 }
    216 
    217 AnnualTimeZoneRule&
    218 AnnualTimeZoneRule::operator=(const AnnualTimeZoneRule& right) {
    219     if (this != &right) {
    220         TimeZoneRule::operator=(right);
    221         delete fDateTimeRule;
    222         fDateTimeRule = right.fDateTimeRule->clone();
    223         fStartYear = right.fStartYear;
    224         fEndYear = right.fEndYear;
    225     }
    226     return *this;
    227 }
    228 
    229 UBool
    230 AnnualTimeZoneRule::operator==(const TimeZoneRule& that) const {
    231     if (this == &that) {
    232         return TRUE;
    233     }
    234     if (typeid(*this) != typeid(that)) {
    235         return FALSE;
    236     }
    237     AnnualTimeZoneRule *atzr = (AnnualTimeZoneRule*)&that;
    238     return (*fDateTimeRule == *(atzr->fDateTimeRule) &&
    239             fStartYear == atzr->fStartYear &&
    240             fEndYear == atzr->fEndYear);
    241 }
    242 
    243 UBool
    244 AnnualTimeZoneRule::operator!=(const TimeZoneRule& that) const {
    245     return !operator==(that);
    246 }
    247 
    248 const DateTimeRule*
    249 AnnualTimeZoneRule::getRule() const {
    250     return fDateTimeRule;
    251 }
    252 
    253 int32_t
    254 AnnualTimeZoneRule::getStartYear() const {
    255     return fStartYear;
    256 }
    257 
    258 int32_t
    259 AnnualTimeZoneRule::getEndYear() const {
    260     return fEndYear;
    261 }
    262 
    263 UBool
    264 AnnualTimeZoneRule::getStartInYear(int32_t year,
    265                                    int32_t prevRawOffset,
    266                                    int32_t prevDSTSavings,
    267                                    UDate &result) const {
    268     if (year < fStartYear || year > fEndYear) {
    269         return FALSE;
    270     }
    271     double ruleDay;
    272     DateTimeRule::DateRuleType type = fDateTimeRule->getDateRuleType();
    273     if (type == DateTimeRule::DOM) {
    274         ruleDay = Grego::fieldsToDay(year, fDateTimeRule->getRuleMonth(), fDateTimeRule->getRuleDayOfMonth());
    275     } else {
    276         UBool after = TRUE;
    277         if (type == DateTimeRule::DOW) {
    278             // Normalize DOW rule into DOW_GEQ_DOM or DOW_LEQ_DOM
    279             int32_t weeks = fDateTimeRule->getRuleWeekInMonth();
    280             if (weeks > 0) {
    281                 ruleDay = Grego::fieldsToDay(year, fDateTimeRule->getRuleMonth(), 1);
    282                 ruleDay += 7 * (weeks - 1);
    283             } else {
    284                 after = FALSE;
    285                 ruleDay = Grego::fieldsToDay(year, fDateTimeRule->getRuleMonth(),
    286                     Grego::monthLength(year, fDateTimeRule->getRuleMonth()));
    287                 ruleDay += 7 * (weeks + 1);
    288            }
    289         } else {
    290             int32_t month = fDateTimeRule->getRuleMonth();
    291             int32_t dom = fDateTimeRule->getRuleDayOfMonth();
    292             if (type == DateTimeRule::DOW_LEQ_DOM) {
    293                 after = FALSE;
    294                 // Handle Feb <=29
    295                 if (month == UCAL_FEBRUARY && dom == 29 && !Grego::isLeapYear(year)) {
    296                     dom--;
    297                 }
    298             }
    299             ruleDay = Grego::fieldsToDay(year, month, dom);
    300         }
    301         int32_t dow = Grego::dayOfWeek(ruleDay);
    302         int32_t delta = fDateTimeRule->getRuleDayOfWeek() - dow;
    303         if (after) {
    304             delta = delta < 0 ? delta + 7 : delta;
    305         } else {
    306             delta = delta > 0 ? delta - 7 : delta;
    307         }
    308         ruleDay += delta;
    309     }
    310 
    311     result = ruleDay*U_MILLIS_PER_DAY + fDateTimeRule->getRuleMillisInDay();
    312     if (fDateTimeRule->getTimeRuleType() != DateTimeRule::UTC_TIME) {
    313         result -= prevRawOffset;
    314     }
    315     if (fDateTimeRule->getTimeRuleType() == DateTimeRule::WALL_TIME) {
    316         result -= prevDSTSavings;
    317     }
    318     return TRUE;
    319 }
    320 
    321 UBool
    322 AnnualTimeZoneRule::isEquivalentTo(const TimeZoneRule& other) const {
    323     if (this == &other) {
    324         return TRUE;
    325     }
    326     if (typeid(*this) != typeid(other) || TimeZoneRule::isEquivalentTo(other) == FALSE) {
    327         return FALSE;
    328     }
    329     AnnualTimeZoneRule* that = (AnnualTimeZoneRule*)&other;
    330     return (*fDateTimeRule == *(that->fDateTimeRule) &&
    331             fStartYear == that->fStartYear &&
    332             fEndYear == that->fEndYear);
    333 }
    334 
    335 UBool
    336 AnnualTimeZoneRule::getFirstStart(int32_t prevRawOffset,
    337                                   int32_t prevDSTSavings,
    338                                   UDate& result) const {
    339     return getStartInYear(fStartYear, prevRawOffset, prevDSTSavings, result);
    340 }
    341 
    342 UBool
    343 AnnualTimeZoneRule::getFinalStart(int32_t prevRawOffset,
    344                                   int32_t prevDSTSavings,
    345                                   UDate& result) const {
    346     if (fEndYear == MAX_YEAR) {
    347         return FALSE;
    348     }
    349     return getStartInYear(fEndYear, prevRawOffset, prevDSTSavings, result);
    350 }
    351 
    352 UBool
    353 AnnualTimeZoneRule::getNextStart(UDate base,
    354                                  int32_t prevRawOffset,
    355                                  int32_t prevDSTSavings,
    356                                  UBool inclusive,
    357                                  UDate& result) const {
    358     int32_t year, month, dom, dow, doy, mid;
    359     Grego::timeToFields(base, year, month, dom, dow, doy, mid);
    360     if (year < fStartYear) {
    361         return getFirstStart(prevRawOffset, prevDSTSavings, result);
    362     }
    363     UDate tmp;
    364     if (getStartInYear(year, prevRawOffset, prevDSTSavings, tmp)) {
    365         if (tmp < base || (!inclusive && (tmp == base))) {
    366             // Return the next one
    367             return getStartInYear(year + 1, prevRawOffset, prevDSTSavings, result);
    368         } else {
    369             result = tmp;
    370             return TRUE;
    371         }
    372     }
    373     return FALSE;
    374 }
    375 
    376 UBool
    377 AnnualTimeZoneRule::getPreviousStart(UDate base,
    378                                      int32_t prevRawOffset,
    379                                      int32_t prevDSTSavings,
    380                                      UBool inclusive,
    381                                      UDate& result) const {
    382     int32_t year, month, dom, dow, doy, mid;
    383     Grego::timeToFields(base, year, month, dom, dow, doy, mid);
    384     if (year > fEndYear) {
    385         return getFinalStart(prevRawOffset, prevDSTSavings, result);
    386     }
    387     UDate tmp;
    388     if (getStartInYear(year, prevRawOffset, prevDSTSavings, tmp)) {
    389         if (tmp > base || (!inclusive && (tmp == base))) {
    390             // Return the previous one
    391             return getStartInYear(year - 1, prevRawOffset, prevDSTSavings, result);
    392         } else {
    393             result = tmp;
    394             return TRUE;
    395         }
    396     }
    397     return FALSE;
    398 }
    399 
    400 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(TimeArrayTimeZoneRule)
    401 
    402 TimeArrayTimeZoneRule::TimeArrayTimeZoneRule(const UnicodeString& name,
    403                                              int32_t rawOffset,
    404                                              int32_t dstSavings,
    405                                              const UDate* startTimes,
    406                                              int32_t numStartTimes,
    407                                              DateTimeRule::TimeRuleType timeRuleType)
    408 : TimeZoneRule(name, rawOffset, dstSavings), fTimeRuleType(timeRuleType),
    409   fStartTimes(NULL) {
    410     UErrorCode status = U_ZERO_ERROR;
    411     initStartTimes(startTimes, numStartTimes, status);
    412     //TODO - status?
    413 }
    414 
    415 
    416 TimeArrayTimeZoneRule::TimeArrayTimeZoneRule(const TimeArrayTimeZoneRule& source)
    417 : TimeZoneRule(source), fTimeRuleType(source.fTimeRuleType), fStartTimes(NULL) {
    418     UErrorCode status = U_ZERO_ERROR;
    419     initStartTimes(source.fStartTimes, source.fNumStartTimes, status);
    420     //TODO - status?
    421 }
    422 
    423 
    424 TimeArrayTimeZoneRule::~TimeArrayTimeZoneRule() {
    425     if (fStartTimes != NULL && fStartTimes != fLocalStartTimes) {
    426         uprv_free(fStartTimes);
    427     }
    428 }
    429 
    430 TimeArrayTimeZoneRule*
    431 TimeArrayTimeZoneRule::clone(void) const {
    432     return new TimeArrayTimeZoneRule(*this);
    433 }
    434 
    435 
    436 TimeArrayTimeZoneRule&
    437 TimeArrayTimeZoneRule::operator=(const TimeArrayTimeZoneRule& right) {
    438     if (this != &right) {
    439         TimeZoneRule::operator=(right);
    440         UErrorCode status = U_ZERO_ERROR;
    441         initStartTimes(right.fStartTimes, right.fNumStartTimes, status);
    442         //TODO - status?
    443         fTimeRuleType = right.fTimeRuleType;
    444     }
    445     return *this;
    446 }
    447 
    448 UBool
    449 TimeArrayTimeZoneRule::operator==(const TimeZoneRule& that) const {
    450     if (this == &that) {
    451         return TRUE;
    452     }
    453     if (typeid(*this) != typeid(that) || TimeZoneRule::operator==(that) == FALSE) {
    454         return FALSE;
    455     }
    456     TimeArrayTimeZoneRule *tatzr = (TimeArrayTimeZoneRule*)&that;
    457     if (fTimeRuleType != tatzr->fTimeRuleType ||
    458         fNumStartTimes != tatzr->fNumStartTimes) {
    459         return FALSE;
    460     }
    461     // Compare start times
    462     UBool res = TRUE;
    463     for (int32_t i = 0; i < fNumStartTimes; i++) {
    464         if (fStartTimes[i] != tatzr->fStartTimes[i]) {
    465             res = FALSE;
    466             break;
    467         }
    468     }
    469     return res;
    470 }
    471 
    472 UBool
    473 TimeArrayTimeZoneRule::operator!=(const TimeZoneRule& that) const {
    474     return !operator==(that);
    475 }
    476 
    477 DateTimeRule::TimeRuleType
    478 TimeArrayTimeZoneRule::getTimeType(void) const {
    479     return fTimeRuleType;
    480 }
    481 
    482 UBool
    483 TimeArrayTimeZoneRule::getStartTimeAt(int32_t index, UDate& result) const {
    484     if (index >= fNumStartTimes || index < 0) {
    485         return FALSE;
    486     }
    487     result = fStartTimes[index];
    488     return TRUE;
    489 }
    490 
    491 int32_t
    492 TimeArrayTimeZoneRule::countStartTimes(void) const {
    493     return fNumStartTimes;
    494 }
    495 
    496 UBool
    497 TimeArrayTimeZoneRule::isEquivalentTo(const TimeZoneRule& other) const {
    498     if (this == &other) {
    499         return TRUE;
    500     }
    501     if (typeid(*this) != typeid(other) || 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(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(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