tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

tzrule.cpp (19295B)


      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 bool
     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 bool
     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() const {
     78    return fRawOffset;
     79 }
     80 
     81 int32_t
     82 TimeZoneRule::getDSTSavings() 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() 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 bool
    124 InitialTimeZoneRule::operator==(const TimeZoneRule& that) const {
    125    return ((this == &that) ||
    126            (typeid(*this) == typeid(that) &&
    127            TimeZoneRule::operator==(that)));
    128 }
    129 
    130 bool
    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() 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 bool
    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 bool
    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    UErrorCode status = U_ZERO_ERROR;
    359    int32_t year = Grego::timeToYear(base, status);
    360    U_ASSERT(U_SUCCESS(status));
    361    if (year < fStartYear) {
    362        return getFirstStart(prevRawOffset, prevDSTSavings, result);
    363    }
    364    UDate tmp;
    365    if (getStartInYear(year, prevRawOffset, prevDSTSavings, tmp)) {
    366        if (tmp < base || (!inclusive && (tmp == base))) {
    367            // Return the next one
    368            return getStartInYear(year + 1, prevRawOffset, prevDSTSavings, result);
    369        } else {
    370            result = tmp;
    371            return true;
    372        }
    373    }
    374    return false;
    375 }
    376 
    377 UBool
    378 AnnualTimeZoneRule::getPreviousStart(UDate base,
    379                                     int32_t prevRawOffset,
    380                                     int32_t prevDSTSavings,
    381                                     UBool inclusive,
    382                                     UDate& result) const {
    383    UErrorCode status = U_ZERO_ERROR;
    384    int32_t year = Grego::timeToYear(base, status);
    385    U_ASSERT(U_SUCCESS(status));
    386    if (year > fEndYear) {
    387        return getFinalStart(prevRawOffset, prevDSTSavings, result);
    388    }
    389    UDate tmp;
    390    if (getStartInYear(year, prevRawOffset, prevDSTSavings, tmp)) {
    391        if (tmp > base || (!inclusive && (tmp == base))) {
    392            // Return the previous one
    393            return getStartInYear(year - 1, prevRawOffset, prevDSTSavings, result);
    394        } else {
    395            result = tmp;
    396            return true;
    397        }
    398    }
    399    return false;
    400 }
    401 
    402 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(TimeArrayTimeZoneRule)
    403 
    404 TimeArrayTimeZoneRule::TimeArrayTimeZoneRule(const UnicodeString& name,
    405                                             int32_t rawOffset,
    406                                             int32_t dstSavings,
    407                                             const UDate* startTimes,
    408                                             int32_t numStartTimes,
    409                                             DateTimeRule::TimeRuleType timeRuleType)
    410 : TimeZoneRule(name, rawOffset, dstSavings), fTimeRuleType(timeRuleType),
    411  fStartTimes(nullptr) {
    412    UErrorCode status = U_ZERO_ERROR;
    413    initStartTimes(startTimes, numStartTimes, status);
    414    //TODO - status?
    415 }
    416 
    417 
    418 TimeArrayTimeZoneRule::TimeArrayTimeZoneRule(const TimeArrayTimeZoneRule& source)
    419 : TimeZoneRule(source), fTimeRuleType(source.fTimeRuleType), fStartTimes(nullptr) {
    420    UErrorCode status = U_ZERO_ERROR;
    421    initStartTimes(source.fStartTimes, source.fNumStartTimes, status);
    422    //TODO - status?
    423 }
    424 
    425 
    426 TimeArrayTimeZoneRule::~TimeArrayTimeZoneRule() {
    427    if (fStartTimes != nullptr && fStartTimes != fLocalStartTimes) {
    428        uprv_free(fStartTimes);
    429    }
    430 }
    431 
    432 TimeArrayTimeZoneRule*
    433 TimeArrayTimeZoneRule::clone() const {
    434    return new TimeArrayTimeZoneRule(*this);
    435 }
    436 
    437 
    438 TimeArrayTimeZoneRule&
    439 TimeArrayTimeZoneRule::operator=(const TimeArrayTimeZoneRule& right) {
    440    if (this != &right) {
    441        TimeZoneRule::operator=(right);
    442        UErrorCode status = U_ZERO_ERROR;
    443        initStartTimes(right.fStartTimes, right.fNumStartTimes, status);
    444        //TODO - status?
    445        fTimeRuleType = right.fTimeRuleType;        
    446    }
    447    return *this;
    448 }
    449 
    450 bool
    451 TimeArrayTimeZoneRule::operator==(const TimeZoneRule& that) const {
    452    if (this == &that) {
    453        return true;
    454    }
    455    if (typeid(*this) != typeid(that) || !TimeZoneRule::operator==(that)) {
    456        return false;
    457    }
    458    TimeArrayTimeZoneRule *tatzr = (TimeArrayTimeZoneRule*)&that;
    459    if (fTimeRuleType != tatzr->fTimeRuleType ||
    460        fNumStartTimes != tatzr->fNumStartTimes) {
    461        return false;
    462    }
    463    // Compare start times
    464    bool res = true;
    465    for (int32_t i = 0; i < fNumStartTimes; i++) {
    466        if (fStartTimes[i] != tatzr->fStartTimes[i]) {
    467            res = false;
    468            break;
    469        }
    470    }
    471    return res;
    472 }
    473 
    474 bool
    475 TimeArrayTimeZoneRule::operator!=(const TimeZoneRule& that) const {
    476    return !operator==(that);
    477 }
    478 
    479 DateTimeRule::TimeRuleType
    480 TimeArrayTimeZoneRule::getTimeType() const {
    481    return fTimeRuleType;
    482 }
    483 
    484 UBool
    485 TimeArrayTimeZoneRule::getStartTimeAt(int32_t index, UDate& result) const {
    486    if (index >= fNumStartTimes || index < 0) {
    487        return false;
    488    }
    489    result = fStartTimes[index];
    490    return true;
    491 }
    492 
    493 int32_t
    494 TimeArrayTimeZoneRule::countStartTimes() const {
    495    return fNumStartTimes;
    496 }
    497 
    498 UBool
    499 TimeArrayTimeZoneRule::isEquivalentTo(const TimeZoneRule& other) const {
    500    if (this == &other) {
    501        return true;
    502    }
    503    if (typeid(*this) != typeid(other) || TimeZoneRule::isEquivalentTo(other) == false) {
    504        return false;
    505    }
    506    TimeArrayTimeZoneRule* that = (TimeArrayTimeZoneRule*)&other;
    507    if (fTimeRuleType != that->fTimeRuleType ||
    508        fNumStartTimes != that->fNumStartTimes) {
    509        return false;
    510    }
    511    // Compare start times
    512    UBool res = true;
    513    for (int32_t i = 0; i < fNumStartTimes; i++) {
    514        if (fStartTimes[i] != that->fStartTimes[i]) {
    515            res = false;
    516            break;
    517        }
    518    }
    519    return res;
    520 }
    521 
    522 UBool
    523 TimeArrayTimeZoneRule::getFirstStart(int32_t prevRawOffset,
    524                                             int32_t prevDSTSavings,
    525                                             UDate& result) const {
    526    if (fNumStartTimes <= 0 || fStartTimes == nullptr) {
    527        return false;
    528    }
    529    result = getUTC(fStartTimes[0], prevRawOffset, prevDSTSavings);
    530    return true;
    531 }
    532 
    533 UBool
    534 TimeArrayTimeZoneRule::getFinalStart(int32_t prevRawOffset,
    535                                     int32_t prevDSTSavings,
    536                                     UDate& result) const {
    537    if (fNumStartTimes <= 0 || fStartTimes == nullptr) {
    538        return false;
    539    }
    540    result = getUTC(fStartTimes[fNumStartTimes - 1], prevRawOffset, prevDSTSavings);
    541    return true;
    542 }
    543 
    544 UBool
    545 TimeArrayTimeZoneRule::getNextStart(UDate base,
    546                                    int32_t prevRawOffset,
    547                                    int32_t prevDSTSavings,
    548                                    UBool inclusive,
    549                                    UDate& result) const {
    550    int32_t i = fNumStartTimes - 1;
    551    for (; i >= 0; i--) {
    552        UDate time = getUTC(fStartTimes[i], prevRawOffset, prevDSTSavings);
    553        if (time < base || (!inclusive && time == base)) {
    554            break;
    555        }
    556        result = time;
    557    }
    558    if (i == fNumStartTimes - 1) {
    559        return false;
    560    }
    561    return true;
    562 }
    563 
    564 UBool
    565 TimeArrayTimeZoneRule::getPreviousStart(UDate base,
    566                                        int32_t prevRawOffset,
    567                                        int32_t prevDSTSavings,
    568                                        UBool inclusive,
    569                                        UDate& result) const {
    570    int32_t i = fNumStartTimes - 1;
    571    for (; i >= 0; i--) {
    572        UDate time = getUTC(fStartTimes[i], prevRawOffset, prevDSTSavings);
    573        if (time < base || (inclusive && time == base)) {
    574            result = time;
    575            return true;
    576        }
    577    }
    578    return false;
    579 }
    580 
    581 
    582 // ---- private methods ------
    583 
    584 UBool
    585 TimeArrayTimeZoneRule::initStartTimes(const UDate source[], int32_t size, UErrorCode& status) {
    586    // Free old array
    587    if (fStartTimes != nullptr && fStartTimes != fLocalStartTimes) {
    588        uprv_free(fStartTimes);
    589    }
    590    // Allocate new one if needed
    591    if (size > TIMEARRAY_STACK_BUFFER_SIZE) {
    592        fStartTimes = static_cast<UDate*>(uprv_malloc(sizeof(UDate) * size));
    593        if (fStartTimes == nullptr) {
    594            status = U_MEMORY_ALLOCATION_ERROR;
    595            fNumStartTimes = 0;
    596            return false;
    597        }
    598    } else {
    599        fStartTimes = (UDate*)fLocalStartTimes;
    600    }
    601    uprv_memcpy(fStartTimes, source, sizeof(UDate)*size);
    602    fNumStartTimes = size;
    603    // Sort dates
    604    uprv_sortArray(fStartTimes, fNumStartTimes, static_cast<int32_t>(sizeof(UDate)), compareDates, nullptr, true, &status);
    605    if (U_FAILURE(status)) {
    606        if (fStartTimes != nullptr && fStartTimes != fLocalStartTimes) {
    607            uprv_free(fStartTimes);
    608        }
    609        fNumStartTimes = 0;
    610        return false;
    611    }
    612    return true;
    613 }
    614 
    615 UDate
    616 TimeArrayTimeZoneRule::getUTC(UDate time, int32_t raw, int32_t dst) const {
    617    if (fTimeRuleType != DateTimeRule::UTC_TIME) {
    618        time -= raw;
    619    }
    620    if (fTimeRuleType == DateTimeRule::WALL_TIME) {
    621        time -= dst;
    622    }
    623    return time;
    624 }
    625 
    626 U_NAMESPACE_END
    627 
    628 #endif /* #if !UCONFIG_NO_FORMATTING */
    629 
    630 //eof