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