intl/icu/source/i18n/tzrule.cpp

Wed, 31 Dec 2014 07:22:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 07:22:50 +0100
branch
TOR_BUG_3246
changeset 4
fc2d59ddac77
permissions
-rw-r--r--

Correct previous dual key logic pending first delivery installment.

     1 /*
     2 *******************************************************************************
     3 * Copyright (C) 2007-2012, International Business Machines Corporation and
     4 * others. All Rights Reserved.
     5 *******************************************************************************
     6 */
     8 #include "utypeinfo.h"  // for 'typeid' to work
    10 #include "unicode/utypes.h"
    12 #if !UCONFIG_NO_FORMATTING
    14 #include "unicode/tzrule.h"
    15 #include "unicode/ucal.h"
    16 #include "gregoimp.h"
    17 #include "cmemory.h"
    18 #include "uarrsort.h"
    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
    31 U_NAMESPACE_BEGIN
    33 TimeZoneRule::TimeZoneRule(const UnicodeString& name, int32_t rawOffset, int32_t dstSavings)
    34 : UObject(), fName(name), fRawOffset(rawOffset), fDSTSavings(dstSavings) {
    35 }
    37 TimeZoneRule::TimeZoneRule(const TimeZoneRule& source)
    38 : UObject(source), fName(source.fName), fRawOffset(source.fRawOffset), fDSTSavings(source.fDSTSavings) {
    39 }
    41 TimeZoneRule::~TimeZoneRule() {
    42 }
    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 }
    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 }
    63 UBool
    64 TimeZoneRule::operator!=(const TimeZoneRule& that) const {
    65     return !operator==(that);
    66 }
    68 UnicodeString&
    69 TimeZoneRule::getName(UnicodeString& name) const {
    70     name = fName;
    71     return name;
    72 }
    74 int32_t
    75 TimeZoneRule::getRawOffset(void) const {
    76     return fRawOffset;
    77 }
    79 int32_t
    80 TimeZoneRule::getDSTSavings(void) const {
    81     return fDSTSavings;
    82 }
    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 }
    93 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(InitialTimeZoneRule)
    95 InitialTimeZoneRule::InitialTimeZoneRule(const UnicodeString& name,
    96                                          int32_t rawOffset,
    97                                          int32_t dstSavings)
    98 : TimeZoneRule(name, rawOffset, dstSavings) {
    99 }
   101 InitialTimeZoneRule::InitialTimeZoneRule(const InitialTimeZoneRule& source)
   102 : TimeZoneRule(source) {
   103 }
   105 InitialTimeZoneRule::~InitialTimeZoneRule() {
   106 }
   108 InitialTimeZoneRule*
   109 InitialTimeZoneRule::clone(void) const {
   110     return new InitialTimeZoneRule(*this);
   111 }
   113 InitialTimeZoneRule&
   114 InitialTimeZoneRule::operator=(const InitialTimeZoneRule& right) {
   115     if (this != &right) {
   116         TimeZoneRule::operator=(right);
   117     }
   118     return *this;
   119 }
   121 UBool
   122 InitialTimeZoneRule::operator==(const TimeZoneRule& that) const {
   123     return ((this == &that) ||
   124             (typeid(*this) == typeid(that) &&
   125             TimeZoneRule::operator==(that)));
   126 }
   128 UBool
   129 InitialTimeZoneRule::operator!=(const TimeZoneRule& that) const {
   130     return !operator==(that);
   131 }
   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 }
   144 UBool
   145 InitialTimeZoneRule::getFirstStart(int32_t /*prevRawOffset*/,
   146                                   int32_t /*prevDSTSavings*/,
   147                                   UDate& /*result*/) const {
   148     return FALSE;
   149 }
   151 UBool
   152 InitialTimeZoneRule::getFinalStart(int32_t /*prevRawOffset*/,
   153                                   int32_t /*prevDSTSavings*/,
   154                                   UDate& /*result*/) const {
   155     return FALSE;
   156 }
   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 }
   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 }
   177 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(AnnualTimeZoneRule)
   179 const int32_t AnnualTimeZoneRule::MAX_YEAR = 0x7FFFFFFF; /* max signed int32 */
   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 }
   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 }
   201 AnnualTimeZoneRule::AnnualTimeZoneRule(const AnnualTimeZoneRule& source)
   202 : TimeZoneRule(source), fDateTimeRule(new DateTimeRule(*(source.fDateTimeRule))),
   203   fStartYear(source.fStartYear), fEndYear(source.fEndYear) {
   204 }
   206 AnnualTimeZoneRule::~AnnualTimeZoneRule() {
   207     delete fDateTimeRule;
   208 }
   210 AnnualTimeZoneRule*
   211 AnnualTimeZoneRule::clone(void) const {
   212     return new AnnualTimeZoneRule(*this);
   213 }
   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 }
   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 }
   241 UBool
   242 AnnualTimeZoneRule::operator!=(const TimeZoneRule& that) const {
   243     return !operator==(that);
   244 }
   246 const DateTimeRule*
   247 AnnualTimeZoneRule::getRule() const {
   248     return fDateTimeRule;
   249 }
   251 int32_t
   252 AnnualTimeZoneRule::getStartYear() const {
   253     return fStartYear;
   254 }
   256 int32_t
   257 AnnualTimeZoneRule::getEndYear() const {
   258     return fEndYear;
   259 }
   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     }
   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 }
   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 }
   333 UBool
   334 AnnualTimeZoneRule::getFirstStart(int32_t prevRawOffset,
   335                                   int32_t prevDSTSavings,
   336                                   UDate& result) const {
   337     return getStartInYear(fStartYear, prevRawOffset, prevDSTSavings, result);
   338 }
   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 }
   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 }
   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 }
   398 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(TimeArrayTimeZoneRule)
   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 }
   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 }
   422 TimeArrayTimeZoneRule::~TimeArrayTimeZoneRule() {
   423     if (fStartTimes != NULL && fStartTimes != fLocalStartTimes) {
   424         uprv_free(fStartTimes);
   425     }
   426 }
   428 TimeArrayTimeZoneRule*
   429 TimeArrayTimeZoneRule::clone(void) const {
   430     return new TimeArrayTimeZoneRule(*this);
   431 }
   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 }
   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 }
   470 UBool
   471 TimeArrayTimeZoneRule::operator!=(const TimeZoneRule& that) const {
   472     return !operator==(that);
   473 }
   475 DateTimeRule::TimeRuleType
   476 TimeArrayTimeZoneRule::getTimeType(void) const {
   477     return fTimeRuleType;
   478 }
   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 }
   489 int32_t
   490 TimeArrayTimeZoneRule::countStartTimes(void) const {
   491     return fNumStartTimes;
   492 }
   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 }
   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 }
   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 }
   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 }
   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 }
   578 // ---- private methods ------
   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 }
   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 }
   622 U_NAMESPACE_END
   624 #endif /* #if !UCONFIG_NO_FORMATTING */
   626 //eof

mercurial