Home | History | Annotate | Download | only in intltest
      1 // Copyright (C) 2016 and later: Unicode, Inc. and others.
      2 // License & terms of use: http://www.unicode.org/copyright.html
      3 /*
      4 *******************************************************************************
      5 * Copyright (C) 2007-2011, International Business Machines Corporation and         *
      6 * others. All Rights Reserved.                                                *
      7 *******************************************************************************
      8 */
      9 #include "unicode/utypes.h"
     10 
     11 #if !UCONFIG_NO_FORMATTING
     12 
     13 #include "tzoffloc.h"
     14 
     15 #include "unicode/ucal.h"
     16 #include "unicode/timezone.h"
     17 #include "unicode/calendar.h"
     18 #include "unicode/dtrule.h"
     19 #include "unicode/tzrule.h"
     20 #include "unicode/rbtz.h"
     21 #include "unicode/simpletz.h"
     22 #include "unicode/tzrule.h"
     23 #include "unicode/smpdtfmt.h"
     24 #include "unicode/gregocal.h"
     25 
     26 void
     27 TimeZoneOffsetLocalTest::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ )
     28 {
     29     if (exec) {
     30         logln("TestSuite TimeZoneOffsetLocalTest");
     31     }
     32     switch (index) {
     33         TESTCASE(0, TestGetOffsetAroundTransition);
     34         default: name = ""; break;
     35     }
     36 }
     37 
     38 /*
     39  * Testing getOffset APIs around rule transition by local standard/wall time.
     40  */
     41 void
     42 TimeZoneOffsetLocalTest::TestGetOffsetAroundTransition() {
     43     const int32_t NUM_DATES = 10;
     44     const int32_t NUM_TIMEZONES = 3;
     45 
     46     const int32_t HOUR = 60*60*1000;
     47     const int32_t MINUTE = 60*1000;
     48 
     49     const int32_t DATES[NUM_DATES][6] = {
     50         {2006, UCAL_APRIL, 2, 1, 30, 1*HOUR+30*MINUTE},
     51         {2006, UCAL_APRIL, 2, 2, 00, 2*HOUR},
     52         {2006, UCAL_APRIL, 2, 2, 30, 2*HOUR+30*MINUTE},
     53         {2006, UCAL_APRIL, 2, 3, 00, 3*HOUR},
     54         {2006, UCAL_APRIL, 2, 3, 30, 3*HOUR+30*MINUTE},
     55         {2006, UCAL_OCTOBER, 29, 0, 30, 0*HOUR+30*MINUTE},
     56         {2006, UCAL_OCTOBER, 29, 1, 00, 1*HOUR},
     57         {2006, UCAL_OCTOBER, 29, 1, 30, 1*HOUR+30*MINUTE},
     58         {2006, UCAL_OCTOBER, 29, 2, 00, 2*HOUR},
     59         {2006, UCAL_OCTOBER, 29, 2, 30, 2*HOUR+30*MINUTE},
     60     };
     61 
     62     // Expected offsets by int32_t getOffset(uint8_t era, int32_t year, int32_t month, int32_t day,
     63     // uint8_t dayOfWeek, int32_t millis, UErrorCode& status)
     64     const int32_t OFFSETS1[NUM_DATES] = {
     65         // April 2, 2006
     66         -8*HOUR,
     67         -7*HOUR,
     68         -7*HOUR,
     69         -7*HOUR,
     70         -7*HOUR,
     71 
     72         // October 29, 2006
     73         -7*HOUR,
     74         -8*HOUR,
     75         -8*HOUR,
     76         -8*HOUR,
     77         -8*HOUR,
     78     };
     79 
     80     // Expected offsets by void getOffset(UDate date, UBool local, int32_t& rawOffset,
     81     // int32_t& dstOffset, UErrorCode& ec) with local=TRUE
     82     // or void getOffsetFromLocal(UDate date, int32_t nonExistingTimeOpt, int32_t duplicatedTimeOpt,
     83     // int32_t& rawOffset, int32_t& dstOffset, UErrorCode& status) with
     84     // nonExistingTimeOpt=kStandard/duplicatedTimeOpt=kStandard
     85     const int32_t OFFSETS2[NUM_DATES][2] = {
     86         // April 2, 2006
     87         {-8*HOUR, 0},
     88         {-8*HOUR, 0},
     89         {-8*HOUR, 0},
     90         {-8*HOUR, 1*HOUR},
     91         {-8*HOUR, 1*HOUR},
     92 
     93         // Oct 29, 2006
     94         {-8*HOUR, 1*HOUR},
     95         {-8*HOUR, 0},
     96         {-8*HOUR, 0},
     97         {-8*HOUR, 0},
     98         {-8*HOUR, 0},
     99     };
    100 
    101     // Expected offsets by void getOffsetFromLocal(UDate date, int32_t nonExistingTimeOpt,
    102     // int32_t duplicatedTimeOpt, int32_t& rawOffset, int32_t& dstOffset, UErrorCode& status) with
    103     // nonExistingTimeOpt=kDaylight/duplicatedTimeOpt=kDaylight
    104     const int32_t OFFSETS3[][2] = {
    105         // April 2, 2006
    106         {-8*HOUR, 0},
    107         {-8*HOUR, 1*HOUR},
    108         {-8*HOUR, 1*HOUR},
    109         {-8*HOUR, 1*HOUR},
    110         {-8*HOUR, 1*HOUR},
    111 
    112         // October 29, 2006
    113         {-8*HOUR, 1*HOUR},
    114         {-8*HOUR, 1*HOUR},
    115         {-8*HOUR, 1*HOUR},
    116         {-8*HOUR, 0},
    117         {-8*HOUR, 0},
    118     };
    119 
    120     UErrorCode status = U_ZERO_ERROR;
    121 
    122     int32_t rawOffset, dstOffset;
    123     TimeZone* utc = TimeZone::createTimeZone("UTC");
    124     Calendar* cal = Calendar::createInstance(*utc, status);
    125     if (U_FAILURE(status)) {
    126         dataerrln("Calendar::createInstance failed: %s", u_errorName(status));
    127         return;
    128     }
    129     cal->clear();
    130 
    131     // Set up TimeZone objects - OlsonTimeZone, SimpleTimeZone and RuleBasedTimeZone
    132     BasicTimeZone *TESTZONES[NUM_TIMEZONES];
    133 
    134     TESTZONES[0] = (BasicTimeZone*)TimeZone::createTimeZone("America/Los_Angeles");
    135     TESTZONES[1] = new SimpleTimeZone(-8*HOUR, "Simple Pacific Time",
    136                                         UCAL_APRIL, 1, UCAL_SUNDAY, 2*HOUR,
    137                                         UCAL_OCTOBER, -1, UCAL_SUNDAY, 2*HOUR, status);
    138     if (U_FAILURE(status)) {
    139         errln("SimpleTimeZone constructor failed");
    140         return;
    141     }
    142 
    143     InitialTimeZoneRule *ir = new InitialTimeZoneRule(
    144             "Pacific Standard Time", // Initial time Name
    145             -8*HOUR,        // Raw offset
    146             0*HOUR);        // DST saving amount
    147 
    148     RuleBasedTimeZone *rbPT = new RuleBasedTimeZone("Rule based Pacific Time", ir);
    149 
    150     DateTimeRule *dtr;
    151     AnnualTimeZoneRule *atzr;
    152     const int32_t STARTYEAR = 2000;
    153 
    154     dtr = new DateTimeRule(UCAL_APRIL, 1, UCAL_SUNDAY,
    155                         2*HOUR, DateTimeRule::WALL_TIME); // 1st Sunday in April, at 2AM wall time
    156     atzr = new AnnualTimeZoneRule("Pacific Daylight Time",
    157             -8*HOUR /* rawOffset */, 1*HOUR /* dstSavings */, dtr,
    158             STARTYEAR, AnnualTimeZoneRule::MAX_YEAR);
    159     rbPT->addTransitionRule(atzr, status);
    160     if (U_FAILURE(status)) {
    161         errln("Could not add DST start rule to the RuleBasedTimeZone rbPT");
    162         return;
    163     }
    164 
    165     dtr = new DateTimeRule(UCAL_OCTOBER, -1, UCAL_SUNDAY,
    166                         2*HOUR, DateTimeRule::WALL_TIME); // last Sunday in October, at 2AM wall time
    167     atzr = new AnnualTimeZoneRule("Pacific Standard Time",
    168             -8*HOUR /* rawOffset */, 0 /* dstSavings */, dtr,
    169             STARTYEAR, AnnualTimeZoneRule::MAX_YEAR);
    170     rbPT->addTransitionRule(atzr, status);
    171     if (U_FAILURE(status)) {
    172         errln("Could not add STD start rule to the RuleBasedTimeZone rbPT");
    173         return;
    174     }
    175 
    176     rbPT->complete(status);
    177     if (U_FAILURE(status)) {
    178         errln("complete() failed for RuleBasedTimeZone rbPT");
    179         return;
    180     }
    181 
    182     TESTZONES[2] = rbPT;
    183 
    184     // Calculate millis
    185     UDate MILLIS[NUM_DATES];
    186     for (int32_t i = 0; i < NUM_DATES; i++) {
    187         cal->clear();
    188         cal->set(DATES[i][0], DATES[i][1], DATES[i][2], DATES[i][3], DATES[i][4]);
    189         MILLIS[i] = cal->getTime(status);
    190         if (U_FAILURE(status)) {
    191             errln("cal->getTime failed");
    192             return;
    193         }
    194     }
    195 
    196     SimpleDateFormat df(UnicodeString("yyyy-MM-dd HH:mm:ss"), status);
    197     if (U_FAILURE(status)) {
    198         dataerrln("Failed to initialize a SimpleDateFormat - %s", u_errorName(status));
    199     }
    200     df.setTimeZone(*utc);
    201     UnicodeString dateStr;
    202 
    203     // Test getOffset(uint8_t era, int32_t year, int32_t month, int32_t day,
    204     // uint8_t dayOfWeek, int32_t millis, UErrorCode& status)
    205     for (int32_t i = 0; i < NUM_TIMEZONES; i++) {
    206         for (int32_t d = 0; d < NUM_DATES; d++) {
    207             status = U_ZERO_ERROR;
    208             int32_t offset = TESTZONES[i]->getOffset(GregorianCalendar::AD, DATES[d][0], DATES[d][1], DATES[d][2],
    209                                                 UCAL_SUNDAY, DATES[d][5], status);
    210             if (U_FAILURE(status)) {
    211                 errln((UnicodeString)"getOffset(era,year,month,day,dayOfWeek,millis,status) failed for TESTZONES[" + i + "]");
    212             } else if (offset != OFFSETS1[d]) {
    213                 dateStr.remove();
    214                 df.format(MILLIS[d], dateStr);
    215                 dataerrln((UnicodeString)"Bad offset returned by TESTZONES[" + i + "] at "
    216                         + dateStr + "(standard) - Got: " + offset + " Expected: " + OFFSETS1[d]);
    217             }
    218         }
    219     }
    220 
    221     // Test getOffset(UDate date, UBool local, int32_t& rawOffset,
    222     // int32_t& dstOffset, UErrorCode& ec) with local = TRUE
    223     for (int32_t i = 0; i < NUM_TIMEZONES; i++) {
    224         for (int32_t m = 0; m < NUM_DATES; m++) {
    225             status = U_ZERO_ERROR;
    226             TESTZONES[i]->getOffset(MILLIS[m], TRUE, rawOffset, dstOffset, status);
    227             if (U_FAILURE(status)) {
    228                 errln((UnicodeString)"getOffset(date,local,rawOfset,dstOffset,ec) failed for TESTZONES[" + i + "]");
    229             } else if (rawOffset != OFFSETS2[m][0] || dstOffset != OFFSETS2[m][1]) {
    230                 dateStr.remove();
    231                 df.format(MILLIS[m], dateStr);
    232                 dataerrln((UnicodeString)"Bad offset returned by TESTZONES[" + i + "] at "
    233                         + dateStr + "(wall) - Got: "
    234                         + rawOffset + "/" + dstOffset
    235                         + " Expected: " + OFFSETS2[m][0] + "/" + OFFSETS2[m][1]);
    236             }
    237         }
    238     }
    239 
    240     // Test getOffsetFromLocal(UDate date, int32_t nonExistingTimeOpt, int32_t duplicatedTimeOpt,
    241     // int32_t& rawOffset, int32_t& dstOffset, UErroCode& status)
    242     // with nonExistingTimeOpt=kStandard/duplicatedTimeOpt=kStandard
    243     for (int32_t i = 0; i < NUM_TIMEZONES; i++) {
    244         for (int m = 0; m < NUM_DATES; m++) {
    245             status = U_ZERO_ERROR;
    246             TESTZONES[i]->getOffsetFromLocal(MILLIS[m], BasicTimeZone::kStandard, BasicTimeZone::kStandard,
    247                 rawOffset, dstOffset, status);
    248             if (U_FAILURE(status)) {
    249                 errln((UnicodeString)"getOffsetFromLocal with kStandard/kStandard failed for TESTZONES[" + i + "]");
    250             } else if (rawOffset != OFFSETS2[m][0] || dstOffset != OFFSETS2[m][1]) {
    251                 dateStr.remove();
    252                 df.format(MILLIS[m], dateStr);
    253                 dataerrln((UnicodeString)"Bad offset returned by TESTZONES[" + i + "] at "
    254                         + dateStr + "(wall/kStandard/kStandard) - Got: "
    255                         + rawOffset + "/" + dstOffset
    256                         + " Expected: " + OFFSETS2[m][0] + "/" + OFFSETS2[m][1]);
    257             }
    258         }
    259     }
    260 
    261     // Test getOffsetFromLocal(UDate date, int32_t nonExistingTimeOpt, int32_t duplicatedTimeOpt,
    262     // int32_t& rawOffset, int32_t& dstOffset, UErroCode& status)
    263     // with nonExistingTimeOpt=kDaylight/duplicatedTimeOpt=kDaylight
    264     for (int32_t i = 0; i < NUM_TIMEZONES; i++) {
    265         for (int m = 0; m < NUM_DATES; m++) {
    266             status = U_ZERO_ERROR;
    267             TESTZONES[i]->getOffsetFromLocal(MILLIS[m], BasicTimeZone::kDaylight, BasicTimeZone::kDaylight,
    268                 rawOffset, dstOffset, status);
    269             if (U_FAILURE(status)) {
    270                 errln((UnicodeString)"getOffsetFromLocal with kDaylight/kDaylight failed for TESTZONES[" + i + "]");
    271             } else if (rawOffset != OFFSETS3[m][0] || dstOffset != OFFSETS3[m][1]) {
    272                 dateStr.remove();
    273                 df.format(MILLIS[m], dateStr);
    274                 dataerrln((UnicodeString)"Bad offset returned by TESTZONES[" + i + "] at "
    275                         + dateStr + "(wall/kDaylight/kDaylight) - Got: "
    276                         + rawOffset + "/" + dstOffset
    277                         + " Expected: " + OFFSETS3[m][0] + "/" + OFFSETS3[m][1]);
    278             }
    279         }
    280     }
    281 
    282     // Test getOffsetFromLocal(UDate date, int32_t nonExistingTimeOpt, int32_t duplicatedTimeOpt,
    283     // int32_t& rawOffset, int32_t& dstOffset, UErroCode& status)
    284     // with nonExistingTimeOpt=kFormer/duplicatedTimeOpt=kLatter
    285     for (int32_t i = 0; i < NUM_TIMEZONES; i++) {
    286         for (int m = 0; m < NUM_DATES; m++) {
    287             status = U_ZERO_ERROR;
    288             TESTZONES[i]->getOffsetFromLocal(MILLIS[m], BasicTimeZone::kFormer, BasicTimeZone::kLatter,
    289                 rawOffset, dstOffset, status);
    290             if (U_FAILURE(status)) {
    291                 errln((UnicodeString)"getOffsetFromLocal with kFormer/kLatter failed for TESTZONES[" + i + "]");
    292             } else if (rawOffset != OFFSETS2[m][0] || dstOffset != OFFSETS2[m][1]) {
    293                 dateStr.remove();
    294                 df.format(MILLIS[m], dateStr);
    295                 dataerrln((UnicodeString)"Bad offset returned by TESTZONES[" + i + "] at "
    296                         + dateStr + "(wall/kFormer/kLatter) - Got: "
    297                         + rawOffset + "/" + dstOffset
    298                         + " Expected: " + OFFSETS2[m][0] + "/" + OFFSETS2[m][1]);
    299             }
    300         }
    301     }
    302 
    303     // Test getOffsetFromLocal(UDate date, int32_t nonExistingTimeOpt, int32_t duplicatedTimeOpt,
    304     // int32_t& rawOffset, int32_t& dstOffset, UErroCode& status)
    305     // with nonExistingTimeOpt=kLatter/duplicatedTimeOpt=kFormer
    306     for (int32_t i = 0; i < NUM_TIMEZONES; i++) {
    307         for (int m = 0; m < NUM_DATES; m++) {
    308             status = U_ZERO_ERROR;
    309             TESTZONES[i]->getOffsetFromLocal(MILLIS[m], BasicTimeZone::kLatter, BasicTimeZone::kFormer,
    310                 rawOffset, dstOffset, status);
    311             if (U_FAILURE(status)) {
    312                 errln((UnicodeString)"getOffsetFromLocal with kLatter/kFormer failed for TESTZONES[" + i + "]");
    313             } else if (rawOffset != OFFSETS3[m][0] || dstOffset != OFFSETS3[m][1]) {
    314                 dateStr.remove();
    315                 df.format(MILLIS[m], dateStr);
    316                 dataerrln((UnicodeString)"Bad offset returned by TESTZONES[" + i + "] at "
    317                         + dateStr + "(wall/kLatter/kFormer) - Got: "
    318                         + rawOffset + "/" + dstOffset
    319                         + " Expected: " + OFFSETS3[m][0] + "/" + OFFSETS3[m][1]);
    320             }
    321         }
    322     }
    323 
    324     for (int32_t i = 0; i < NUM_TIMEZONES; i++) {
    325         delete TESTZONES[i];
    326     }
    327     delete utc;
    328     delete cal;
    329 }
    330 
    331 #endif /* #if !UCONFIG_NO_FORMATTING */
    332