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