Home | History | Annotate | Download | only in intltest
      1 /********************************************************************
      2  * Copyright (c) 1997-2009, International Business Machines
      3  * Corporation and others. All Rights Reserved.
      4  ********************************************************************/
      5 
      6 #include "unicode/utypes.h"
      7 
      8 #if !UCONFIG_NO_FORMATTING
      9 
     10 #include "unicode/simpletz.h"
     11 #include "unicode/smpdtfmt.h"
     12 #include "unicode/strenum.h"
     13 #include "tzregts.h"
     14 #include "calregts.h"
     15 #include "cmemory.h"
     16 
     17 // *****************************************************************************
     18 // class TimeZoneRegressionTest
     19 // *****************************************************************************
     20 /* length of an array */
     21 #define ARRAY_LENGTH(array) (sizeof(array)/sizeof(array[0]))
     22 #define CASE(id,test) case id: name = #test; if (exec) { logln(#test "---"); logln((UnicodeString)""); test(); } break
     23 
     24 void
     25 TimeZoneRegressionTest::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ )
     26 {
     27     // if (exec) logln((UnicodeString)"TestSuite NumberFormatRegressionTest");
     28     switch (index) {
     29 
     30         CASE(0, Test4052967);
     31         CASE(1, Test4073209);
     32         CASE(2, Test4073215);
     33         CASE(3, Test4084933);
     34         CASE(4, Test4096952);
     35         CASE(5, Test4109314);
     36         CASE(6, Test4126678);
     37         CASE(7, Test4151406);
     38         CASE(8, Test4151429);
     39         CASE(9, Test4154537);
     40         CASE(10, Test4154542);
     41         CASE(11, Test4154650);
     42         CASE(12, Test4154525);
     43         CASE(13, Test4162593);
     44         CASE(14, TestJ186);
     45         CASE(15, TestJ449);
     46         CASE(16, TestJDK12API);
     47         CASE(17, Test4176686);
     48         CASE(18, Test4184229);
     49         default: name = ""; break;
     50     }
     51 }
     52 
     53 UBool
     54 TimeZoneRegressionTest::failure(UErrorCode status, const char* msg)
     55 {
     56     if(U_FAILURE(status)) {
     57         errln(UnicodeString("FAIL: ") + msg + " failed, error " + u_errorName(status));
     58         return TRUE;
     59     }
     60 
     61     return FALSE;
     62 }
     63 
     64 /**
     65  * @bug 4052967
     66  */
     67 void TimeZoneRegressionTest:: Test4052967() {
     68     // {sfb} not applicable in C++ ?
     69     /*logln("*** CHECK TIMEZONE AGAINST HOST OS SETTING ***");
     70     logln("user.timezone:" + System.getProperty("user.timezone", "<not set>"));
     71     logln(new Date().toString());
     72     logln("*** THE RESULTS OF THIS TEST MUST BE VERIFIED MANUALLY ***");*/
     73 }
     74 
     75 /**
     76  * @bug 4073209
     77  */
     78 void TimeZoneRegressionTest:: Test4073209() {
     79     TimeZone *z1 = TimeZone::createTimeZone("PST");
     80     TimeZone *z2 = TimeZone::createTimeZone("PST");
     81     if (z1 == z2)
     82         errln("Fail: TimeZone should return clones");
     83     delete z1;
     84     delete z2;
     85 }
     86 
     87 UDate TimeZoneRegressionTest::findTransitionBinary(const SimpleTimeZone& tz, UDate min, UDate max) {
     88     UErrorCode status = U_ZERO_ERROR;
     89     UBool startsInDST = tz.inDaylightTime(min, status);
     90     if (failure(status, "SimpleTimeZone::inDaylightTime")) return 0;
     91     if (tz.inDaylightTime(max, status) == startsInDST) {
     92         logln((UnicodeString)"Error: inDaylightTime() != " + ((!startsInDST)?"TRUE":"FALSE"));
     93         return 0;
     94     }
     95     if (failure(status, "SimpleTimeZone::inDaylightTime")) return 0;
     96     while ((max - min) > 100) { // Min accuracy in ms
     97         UDate mid = (min + max) / 2;
     98         if (tz.inDaylightTime(mid, status) == startsInDST) {
     99             min = mid;
    100         } else {
    101             max = mid;
    102         }
    103         if (failure(status, "SimpleTimeZone::inDaylightTime")) return 0;
    104     }
    105     return (min + max) / 2;
    106 }
    107 
    108 UDate TimeZoneRegressionTest::findTransitionStepwise(const SimpleTimeZone& tz, UDate min, UDate max) {
    109     UErrorCode status = U_ZERO_ERROR;
    110     UBool startsInDST = tz.inDaylightTime(min, status);
    111     if (failure(status, "SimpleTimeZone::inDaylightTime")) return 0;
    112     while (min < max) {
    113         if (tz.inDaylightTime(min, status) != startsInDST) {
    114             return min;
    115         }
    116         if (failure(status, "SimpleTimeZone::inDaylightTime")) return 0;
    117         min += (UDate)24*60*60*1000; // one day
    118     }
    119     return 0;
    120 }
    121 
    122 /**
    123  * @bug 4073215
    124  */
    125 // {sfb} will this work using a Calendar?
    126 void TimeZoneRegressionTest:: Test4073215()
    127 {
    128     UErrorCode status = U_ZERO_ERROR;
    129     UnicodeString str, str2;
    130     SimpleTimeZone *z = new SimpleTimeZone(0, "GMT");
    131     if (z->useDaylightTime())
    132         errln("Fail: Fix test to start with non-DST zone");
    133     z->setStartRule(UCAL_FEBRUARY, 1, UCAL_SUNDAY, 0, status);
    134     failure(status, "z->setStartRule()");
    135     z->setEndRule(UCAL_MARCH, -1, UCAL_SUNDAY, 0, status);
    136     failure(status, "z->setStartRule()");
    137     if (!z->useDaylightTime())
    138         errln("Fail: DST not active");
    139 
    140     GregorianCalendar cal(1997, UCAL_JANUARY, 31, status);
    141     if(U_FAILURE(status)) {
    142       errln("Error creating calendar %s", u_errorName(status));
    143       return;
    144     }
    145     failure(status, "new GregorianCalendar");
    146     cal.adoptTimeZone(z);
    147 
    148     SimpleDateFormat sdf((UnicodeString)"E d MMM yyyy G HH:mm", status);
    149     if(U_FAILURE(status)) {
    150       errcheckln(status, "Error creating date format %s", u_errorName(status));
    151       return;
    152     }
    153     sdf.setCalendar(cal);
    154     failure(status, "new SimpleDateFormat");
    155 
    156     UDate jan31, mar1, mar31;
    157 
    158     UBool indt = z->inDaylightTime(jan31=cal.getTime(status), status);
    159     failure(status, "inDaylightTime or getTime call on Jan 31");
    160     if (indt) {
    161         errln("Fail: Jan 31 inDaylightTime=TRUE, exp FALSE");
    162     }
    163     cal.set(1997, UCAL_MARCH, 1);
    164     indt = z->inDaylightTime(mar1=cal.getTime(status), status);
    165     failure(status, "inDaylightTime or getTime call on Mar 1");
    166     if (!indt) {
    167         UnicodeString str;
    168         sdf.format(cal.getTime(status), str);
    169         failure(status, "getTime");
    170         errln((UnicodeString)"Fail: " + str + " inDaylightTime=FALSE, exp TRUE");
    171     }
    172     cal.set(1997, UCAL_MARCH, 31);
    173     indt = z->inDaylightTime(mar31=cal.getTime(status), status);
    174     failure(status, "inDaylightTime or getTime call on Mar 31");
    175     if (indt) {
    176         errln("Fail: Mar 31 inDaylightTime=TRUE, exp FALSE");
    177     }
    178 
    179     /*
    180     cal.set(1997, Calendar::DECEMBER, 31);
    181     UDate dec31 = cal.getTime(status);
    182     failure(status, "getTime");
    183     UDate trans = findTransitionStepwise(*z, jan31, dec31);
    184     logln((UnicodeString)"Stepwise from " +
    185           sdf.format(jan31, str.remove()) + "; transition at " +
    186           (trans?sdf.format(trans, str2.remove()):(UnicodeString)"NONE"));
    187     trans = findTransitionStepwise(*z, mar1, dec31);
    188     logln((UnicodeString)"Stepwise from " +
    189           sdf.format(mar1, str.remove()) + "; transition at " +
    190           (trans?sdf.format(trans, str2.remove()):(UnicodeString)"NONE"));
    191     trans = findTransitionStepwise(*z, mar31, dec31);
    192     logln((UnicodeString)"Stepwise from " +
    193           sdf.format(mar31, str.remove()) + "; transition at " +
    194           (trans?sdf.format(trans, str2.remove()):(UnicodeString)"NONE"));
    195     */
    196 }
    197 
    198 /**
    199  * @bug 4084933
    200  * The expected behavior of TimeZone around the boundaries is:
    201  * (Assume transition time of 2:00 AM)
    202  *    day of onset 1:59 AM STD  = display name 1:59 AM ST
    203  *                 2:00 AM STD  = display name 3:00 AM DT
    204  *    day of end   0:59 AM STD  = display name 1:59 AM DT
    205  *                 1:00 AM STD  = display name 1:00 AM ST
    206  */
    207 void TimeZoneRegressionTest:: Test4084933() {
    208     UErrorCode status = U_ZERO_ERROR;
    209     TimeZone *tz = TimeZone::createTimeZone("PST");
    210 
    211     int32_t offset1 = tz->getOffset(1,
    212         1997, UCAL_OCTOBER, 26, UCAL_SUNDAY, (2*60*60*1000), status);
    213     int32_t offset2 = tz->getOffset(1,
    214         1997, UCAL_OCTOBER, 26, UCAL_SUNDAY, (2*60*60*1000)-1, status);
    215 
    216     int32_t offset3 = tz->getOffset(1,
    217         1997, UCAL_OCTOBER, 26, UCAL_SUNDAY, (1*60*60*1000), status);
    218     int32_t offset4 = tz->getOffset(1,
    219         1997, UCAL_OCTOBER, 26, UCAL_SUNDAY, (1*60*60*1000)-1, status);
    220 
    221     /*
    222      *  The following was added just for consistency.  It shows that going *to* Daylight
    223      *  Savings Time (PDT) does work at 2am.
    224      */
    225     int32_t offset5 = tz->getOffset(1,
    226         1997, UCAL_APRIL, 6, UCAL_SUNDAY, (2*60*60*1000), status);
    227     int32_t offset6 = tz->getOffset(1,
    228         1997, UCAL_APRIL, 6, UCAL_SUNDAY, (2*60*60*1000)-1, status);
    229     int32_t offset5a = tz->getOffset(1,
    230         1997, UCAL_APRIL, 6, UCAL_SUNDAY, (3*60*60*1000), status);
    231     int32_t offset6a = tz->getOffset(1,
    232         1997, UCAL_APRIL, 6, UCAL_SUNDAY, (3*60*60*1000)-1, status);
    233     int32_t offset7 = tz->getOffset(1,
    234         1997, UCAL_APRIL, 6, UCAL_SUNDAY, (1*60*60*1000), status);
    235     int32_t offset8 = tz->getOffset(1,
    236         1997, UCAL_APRIL, 6, UCAL_SUNDAY, (1*60*60*1000)-1, status);
    237     int32_t SToffset = (int32_t)(-8 * 60*60*1000L);
    238     int32_t DToffset = (int32_t)(-7 * 60*60*1000L);
    239 
    240 #define ERR_IF_FAIL(x) if(x) { dataerrln("FAIL: TimeZone misbehaving - %s", #x); }
    241 
    242         ERR_IF_FAIL(U_FAILURE(status))
    243         ERR_IF_FAIL(offset1 != SToffset)
    244         ERR_IF_FAIL(offset2 != SToffset)
    245         ERR_IF_FAIL(offset3 != SToffset)
    246         ERR_IF_FAIL(offset4 != DToffset)
    247         ERR_IF_FAIL(offset5 != DToffset)
    248         ERR_IF_FAIL(offset6 != SToffset)
    249         ERR_IF_FAIL(offset5a != DToffset)
    250         ERR_IF_FAIL(offset6a != DToffset)
    251         ERR_IF_FAIL(offset7 != SToffset)
    252         ERR_IF_FAIL(offset8 != SToffset)
    253 
    254 #undef ERR_IF_FAIL
    255 
    256     delete tz;
    257 }
    258 
    259 /**
    260  * @bug 4096952
    261  */
    262 void TimeZoneRegressionTest:: Test4096952() {
    263     // {sfb} serialization not applicable
    264 /*
    265     UnicodeString ZONES [] = { UnicodeString("GMT"), UnicodeString("MET"), UnicodeString("IST") };
    266     UBool pass = TRUE;
    267     //try {
    268         for (int32_t i=0; i < ZONES.length; ++i) {
    269             TimeZone *zone = TimeZone::createTimeZone(ZONES[i]);
    270             UnicodeString id;
    271             if (zone->getID(id) != ZONES[i])
    272                 errln("Fail: Test broken; zones not instantiating");
    273 
    274             ByteArrayOutputStream baos;
    275             ObjectOutputStream ostream =
    276                 new ObjectOutputStream(baos = new
    277                                        ByteArrayOutputStream());
    278             ostream.writeObject(zone);
    279             ostream.close();
    280             baos.close();
    281             ObjectInputStream istream =
    282                 new ObjectInputStream(new
    283                                       ByteArrayInputStream(baos.toByteArray()));
    284             TimeZone frankenZone = (TimeZone) istream.readObject();
    285             //logln("Zone:        " + zone);
    286             //logln("FrankenZone: " + frankenZone);
    287             if (!zone.equals(frankenZone)) {
    288                 logln("TimeZone " + zone.getID() +
    289                       " not equal to serialized/deserialized one");
    290                 pass = false;
    291             }
    292         }
    293         if (!pass) errln("Fail: TimeZone serialization/equality bug");
    294     }
    295     catch (IOException e) {
    296         errln("Fail: " + e);
    297         e.print32_tStackTrace();
    298     }
    299     catch (ClassNotFoundException e) {
    300         errln("Fail: " + e);
    301         e.print32_tStackTrace();
    302     }
    303 */
    304 }
    305 
    306 /**
    307  * @bug 4109314
    308  */
    309 void TimeZoneRegressionTest:: Test4109314() {
    310     UErrorCode status = U_ZERO_ERROR;
    311     GregorianCalendar *testCal = (GregorianCalendar*)Calendar::createInstance(status);
    312     if(U_FAILURE(status)) {
    313       errln("Error creating calendar %s", u_errorName(status));
    314       delete testCal;
    315       return;
    316     }
    317     failure(status, "Calendar::createInstance");
    318     TimeZone *PST = TimeZone::createTimeZone("PST");
    319     /*Object[] testData = {
    320         PST, new Date(98,Calendar.APRIL,4,22,0), new Date(98, Calendar.APRIL, 5,6,0),
    321         PST, new Date(98,Calendar.OCTOBER,24,22,0), new Date(98,Calendar.OCTOBER,25,6,0),
    322     };*/
    323     UDate testData [] = {
    324         CalendarRegressionTest::makeDate(98,UCAL_APRIL,4,22,0),
    325         CalendarRegressionTest::makeDate(98, UCAL_APRIL,5,6,0),
    326         CalendarRegressionTest::makeDate(98,UCAL_OCTOBER,24,22,0),
    327         CalendarRegressionTest::makeDate(98,UCAL_OCTOBER,25,6,0)
    328     };
    329     UBool pass = TRUE;
    330     for (int32_t i = 0; i < 4; i+=2) {
    331         //testCal->setTimeZone((TimeZone) testData[i]);
    332         testCal->setTimeZone(*PST);
    333         UDate t        = testData[i];
    334         UDate end    = testData[i+1];
    335         while(testCal->getTime(status) < end) {
    336             testCal->setTime(t, status);
    337             if ( ! checkCalendar314(testCal, PST))
    338                 pass = FALSE;
    339             t += 60*60*1000.0;
    340         }
    341     }
    342     if ( ! pass)
    343         errln("Fail: TZ API inconsistent");
    344 
    345     delete testCal;
    346     delete PST;
    347 }
    348 
    349 UBool
    350 TimeZoneRegressionTest::checkCalendar314(GregorianCalendar *testCal, TimeZone *testTZ)
    351 {
    352     UErrorCode status = U_ZERO_ERROR;
    353     // GregorianCalendar testCal = (GregorianCalendar)aCal.clone();
    354 
    355     int32_t tzOffset, tzRawOffset;
    356     float tzOffsetFloat,tzRawOffsetFloat;
    357     // Here is where the user made an error.  They were passing in the value of
    358     // the MILLSECOND field; you need to pass in the millis in the day in STANDARD
    359     // time.
    360     UDate millis = testCal->get(UCAL_MILLISECOND, status) +
    361         1000.0 * (testCal->get(UCAL_SECOND, status) +
    362         60.0 * (testCal->get(UCAL_MINUTE, status) +
    363         60.0 * (testCal->get(UCAL_HOUR_OF_DAY, status)))) -
    364         testCal->get(UCAL_DST_OFFSET, status);
    365 
    366     /* Fix up millis to be in range.  ASSUME THAT WE ARE NOT AT THE
    367      * BEGINNING OR END OF A MONTH.  We must add this code because
    368      * getOffset() has been changed to be more strict about the parameters
    369      * it receives -- it turns out that this test was passing in illegal
    370      * values. */
    371     int32_t date = testCal->get(UCAL_DATE, status);
    372     int32_t dow  = testCal->get(UCAL_DAY_OF_WEEK, status);
    373     while(millis < 0) {
    374         millis += U_MILLIS_PER_DAY;
    375         --date;
    376         dow = UCAL_SUNDAY + ((dow - UCAL_SUNDAY + 6) % 7);
    377     }
    378     while (millis >= U_MILLIS_PER_DAY) {
    379         millis -= U_MILLIS_PER_DAY;
    380         ++date;
    381         dow = UCAL_SUNDAY + ((dow - UCAL_SUNDAY + 1) % 7);
    382     }
    383 
    384     tzOffset = testTZ->getOffset((uint8_t)testCal->get(UCAL_ERA, status),
    385                                 testCal->get(UCAL_YEAR, status),
    386                                 testCal->get(UCAL_MONTH, status),
    387                                 date,
    388                                 (uint8_t)dow,
    389                                 (int32_t)millis,
    390                                 status);
    391     tzRawOffset = testTZ->getRawOffset();
    392     tzOffsetFloat = (float)tzOffset/(float)3600000;
    393     tzRawOffsetFloat = (float)tzRawOffset/(float)3600000;
    394 
    395     UDate testDate = testCal->getTime(status);
    396 
    397     UBool inDaylightTime = testTZ->inDaylightTime(testDate, status);
    398     SimpleDateFormat *sdf = new SimpleDateFormat((UnicodeString)"MM/dd/yyyy HH:mm", status);
    399     sdf->setCalendar(*testCal);
    400     UnicodeString inDaylightTimeString;
    401 
    402     UBool passed;
    403 
    404     if(inDaylightTime)
    405     {
    406         inDaylightTimeString = " DST ";
    407         passed = (tzOffset == (tzRawOffset + 3600000));
    408     }
    409     else
    410     {
    411         inDaylightTimeString = "     ";
    412         passed = (tzOffset == tzRawOffset);
    413     }
    414 
    415     UnicodeString output;
    416     FieldPosition pos(0);
    417     output = testTZ->getID(output) + " " + sdf->format(testDate, output, pos) +
    418         " Offset(" + tzOffsetFloat + ")" +
    419         " RawOffset(" + tzRawOffsetFloat + ")" +
    420         " " + millis/(float)3600000 + " " +
    421         inDaylightTimeString;
    422 
    423     if (passed)
    424         output += "     ";
    425     else
    426         output += "ERROR";
    427 
    428     if (passed)
    429         logln(output);
    430     else
    431         errln(output);
    432 
    433     delete sdf;
    434     return passed;
    435 }
    436 
    437 /**
    438  * @bug 4126678
    439  * CANNOT REPRODUDE
    440  *
    441  * Yet another _alleged_ bug in TimeZone::getOffset(), a method that never
    442  * should have been made public.  It's simply too hard to use correctly.
    443  *
    444  * The original test code failed to do the following:
    445  * (1) Call Calendar::setTime() before getting the fields!
    446  * (2) Use the right millis (as usual) for getOffset(); they were passing
    447  *     in the MILLIS field, instead of the STANDARD MILLIS IN DAY.
    448  * When you fix these two problems, the test passes, as expected.
    449  */
    450 void TimeZoneRegressionTest:: Test4126678()
    451 {
    452     UErrorCode status = U_ZERO_ERROR;
    453     Calendar *cal = Calendar::createInstance(status);
    454     if(U_FAILURE(status)) {
    455       errln("Error creating calendar %s", u_errorName(status));
    456       delete cal;
    457       return;
    458     }
    459     failure(status, "Calendar::createInstance");
    460     TimeZone *tz = TimeZone::createTimeZone("PST");
    461     cal->adoptTimeZone(tz);
    462 
    463     cal->set(1998 - 1900, UCAL_APRIL, 5, 10, 0);
    464     //Date dt = new Date(1998-1900, Calendar::APRIL, 5, 10, 0);
    465 
    466     if (! tz->useDaylightTime() || U_FAILURE(status))
    467         dataerrln("We're not in Daylight Savings Time and we should be. - %s", u_errorName(status));
    468 
    469     //cal.setTime(dt);
    470     int32_t era = cal->get(UCAL_ERA, status);
    471     int32_t year = cal->get(UCAL_YEAR, status);
    472     int32_t month = cal->get(UCAL_MONTH, status);
    473     int32_t day = cal->get(UCAL_DATE, status);
    474     int32_t dayOfWeek = cal->get(UCAL_DAY_OF_WEEK, status);
    475     int32_t millis = cal->get(UCAL_MILLISECOND, status) +
    476         (cal->get(UCAL_SECOND, status) +
    477          (cal->get(UCAL_MINUTE, status) +
    478           (cal->get(UCAL_HOUR, status) * 60) * 60) * 1000) -
    479         cal->get(UCAL_DST_OFFSET, status);
    480 
    481     failure(status, "cal->get");
    482     int32_t offset = tz->getOffset((uint8_t)era, year, month, day, (uint8_t)dayOfWeek, millis, status);
    483     int32_t raw_offset = tz->getRawOffset();
    484     /* Because of better historical timezone support based on Olson data,
    485      * DST is not observed in year 98.  Thus, the expected result is changed.
    486      * As of Mar 2007, ICU timezone transition data is represented by 32-bit.
    487      * When we support 64-bit Olson transition data, the actual offset in
    488      * AD 98 for America/Los_Angeles will be changed again (-7:52:58).  Until
    489      * then, expected result is offset == raw_offset.  -Yoshito
    490      */
    491     /*
    492     if (offset == raw_offset)
    493         errln("Offsets should not match when in DST");
    494     */
    495     /* TODO: When ICU support the Olson LMT offset for America/Los_Angeles, we need to update
    496      * the reference data.
    497      */
    498     if (offset != raw_offset)
    499         errln("Offsets should match");
    500 
    501     delete cal;
    502 }
    503 
    504 /**
    505  * @bug 4151406
    506  * TimeZone::getAvailableIDs(int32_t) throws exception for certain values,
    507  * due to a faulty constant in TimeZone::java.
    508  */
    509 void TimeZoneRegressionTest:: Test4151406() {
    510     int32_t max = 0;
    511     for (int32_t h=-28; h<=30; ++h) {
    512         // h is in half-hours from GMT; rawoffset is in millis
    513         int32_t rawoffset = h * 1800000;
    514         int32_t hh = (h<0) ? -h : h;
    515         UnicodeString hname = UnicodeString((h<0) ? "GMT-" : "GMT+") +
    516             ((hh/2 < 10) ? "0" : "") +
    517             (hh/2) + ':' +
    518             ((hh%2==0) ? "00" : "30");
    519         //try {
    520             UErrorCode ec = U_ZERO_ERROR;
    521             int32_t count;
    522             StringEnumeration* ids = TimeZone::createEnumeration(rawoffset);
    523             count = ids->count(ec);
    524             if (count> max)
    525                 max = count;
    526             if (count > 0) {
    527                 logln(hname + ' ' + (UnicodeString)count + (UnicodeString)" e.g. " + *ids->snext(ec));
    528             } else {
    529                 logln(hname + ' ' + count);
    530             }
    531             // weiv 11/27/2002: why uprv_free? This should be a delete
    532             delete ids;
    533             //delete [] ids;
    534             //uprv_free(ids);
    535         /*} catch (Exception e) {
    536             errln(hname + ' ' + "Fail: " + e);
    537         }*/
    538     }
    539     logln("Maximum zones per offset = %d", max);
    540 }
    541 
    542 /**
    543  * @bug 4151429
    544  */
    545 void TimeZoneRegressionTest:: Test4151429() {
    546     // {sfb} silly test in C++, since we are using an enum and not an int
    547     //try {
    548         /*TimeZone *tz = TimeZone::createTimeZone("GMT");
    549         UnicodeString name;
    550         tz->getDisplayName(TRUE, TimeZone::LONG,
    551                                         Locale.getDefault(), name);
    552         errln("IllegalArgumentException not thrown by TimeZone::getDisplayName()");*/
    553     //} catch(IllegalArgumentException e) {}
    554 }
    555 
    556 /**
    557  * @bug 4154537
    558  * SimpleTimeZone::hasSameRules() doesn't work for zones with no DST
    559  * and different DST parameters.
    560  */
    561 void TimeZoneRegressionTest:: Test4154537() {
    562     UErrorCode status = U_ZERO_ERROR;
    563     // tz1 and tz2 have no DST and different rule parameters
    564     SimpleTimeZone *tz1 = new SimpleTimeZone(0, "1", 0, 0, 0, 0, 2, 0, 0, 0, status);
    565     SimpleTimeZone *tz2 = new SimpleTimeZone(0, "2", 1, 0, 0, 0, 3, 0, 0, 0, status);
    566     // tza and tzA have the same rule params
    567     SimpleTimeZone *tza = new SimpleTimeZone(0, "a", 0, 1, 0, 0, 3, 2, 0, 0, status);
    568     SimpleTimeZone *tzA = new SimpleTimeZone(0, "A", 0, 1, 0, 0, 3, 2, 0, 0, status);
    569     // tzb differs from tza
    570     SimpleTimeZone *tzb = new SimpleTimeZone(0, "b", 0, 1, 0, 0, 3, 1, 0, 0, status);
    571 
    572     if(U_FAILURE(status))
    573         errln("Couldn't create TimeZones");
    574 
    575     if (tz1->useDaylightTime() || tz2->useDaylightTime() ||
    576         !tza->useDaylightTime() || !tzA->useDaylightTime() ||
    577         !tzb->useDaylightTime()) {
    578         errln("Test is broken -- rewrite it");
    579     }
    580     if (!tza->hasSameRules(*tzA) || tza->hasSameRules(*tzb)) {
    581         errln("Fail: hasSameRules() broken for zones with rules");
    582     }
    583     if (!tz1->hasSameRules(*tz2)) {
    584         errln("Fail: hasSameRules() returns false for zones without rules");
    585         //errln("zone 1 = " + tz1);
    586         //errln("zone 2 = " + tz2);
    587     }
    588 
    589     delete tz1;
    590     delete tz2;
    591     delete tza;
    592     delete tzA;
    593     delete tzb;
    594 }
    595 
    596 /**
    597  * @bug 4154542
    598  * SimpleTimeZOne constructors, setStartRule(), and setEndRule() don't
    599  * check for out-of-range arguments.
    600  */
    601 void TimeZoneRegressionTest:: Test4154542()
    602 {
    603     const int32_t GOOD = 1;
    604     const int32_t BAD  = 0;
    605 
    606     const int32_t GOOD_MONTH       = UCAL_JANUARY;
    607     const int32_t GOOD_DAY         = 1;
    608     const int32_t GOOD_DAY_OF_WEEK = UCAL_SUNDAY;
    609     const int32_t GOOD_TIME        = 0;
    610 
    611     int32_t DATA [] = {
    612         GOOD, INT32_MIN,    0,  INT32_MAX,   INT32_MIN,
    613         GOOD, UCAL_JANUARY,    -5,  UCAL_SUNDAY,     0,
    614         GOOD, UCAL_DECEMBER,    5,  UCAL_SATURDAY,   24*60*60*1000,
    615         BAD,  UCAL_DECEMBER,    5,  UCAL_SATURDAY,   24*60*60*1000+1,
    616         BAD,  UCAL_DECEMBER,    5,  UCAL_SATURDAY,  -1,
    617         BAD,  UCAL_JANUARY,    -6,  UCAL_SUNDAY,     0,
    618         BAD,  UCAL_DECEMBER,    6,  UCAL_SATURDAY,   24*60*60*1000,
    619         GOOD, UCAL_DECEMBER,    1,  0,                   0,
    620         GOOD, UCAL_DECEMBER,   31,  0,                   0,
    621         BAD,  UCAL_APRIL,      31,  0,                   0,
    622         BAD,  UCAL_DECEMBER,   32,  0,                   0,
    623         BAD,  UCAL_JANUARY-1,   1,  UCAL_SUNDAY,     0,
    624         BAD,  UCAL_DECEMBER+1,  1,  UCAL_SUNDAY,     0,
    625         GOOD, UCAL_DECEMBER,   31, -UCAL_SUNDAY,     0,
    626         GOOD, UCAL_DECEMBER,   31, -UCAL_SATURDAY,   0,
    627         BAD,  UCAL_DECEMBER,   32, -UCAL_SATURDAY,   0,
    628         BAD,  UCAL_DECEMBER,  -32, -UCAL_SATURDAY,   0,
    629         BAD,  UCAL_DECEMBER,   31, -UCAL_SATURDAY-1, 0,
    630     };
    631     SimpleTimeZone *zone = new SimpleTimeZone(0, "Z");
    632     for (int32_t i=0; i < 18*5; i+=5) {
    633         UBool shouldBeGood = (DATA[i] == GOOD);
    634         int32_t month     = DATA[i+1];
    635         int32_t day       = DATA[i+2];
    636         int32_t dayOfWeek = DATA[i+3];
    637         int32_t time      = DATA[i+4];
    638 
    639         UErrorCode status = U_ZERO_ERROR;
    640 
    641         //Exception ex = null;
    642         //try {
    643             zone->setStartRule(month, day, dayOfWeek, time, status);
    644         //} catch (IllegalArgumentException e) {
    645         //    ex = e;
    646         //}
    647         if (U_SUCCESS(status) != shouldBeGood) {
    648             errln(UnicodeString("setStartRule(month=") + month + ", day=" + day +
    649                   ", dayOfWeek=" + dayOfWeek + ", time=" + time +
    650                   (shouldBeGood ? (") should work")
    651                    : ") should fail but doesn't"));
    652         }
    653 
    654         //ex = null;
    655         //try {
    656         status = U_ZERO_ERROR;
    657             zone->setEndRule(month, day, dayOfWeek, time, status);
    658         //} catch (IllegalArgumentException e) {
    659         //   ex = e;
    660         //}
    661         if (U_SUCCESS(status) != shouldBeGood) {
    662             errln(UnicodeString("setEndRule(month=") + month + ", day=" + day +
    663                   ", dayOfWeek=" + dayOfWeek + ", time=" + time +
    664                   (shouldBeGood ? (") should work")
    665                    : ") should fail but doesn't"));
    666         }
    667 
    668         //ex = null;
    669         //try {
    670         // {sfb} need to look into ctor problems! (UErrorCode vs. dst signature confusion)
    671         status = U_ZERO_ERROR;
    672             SimpleTimeZone *temp = new SimpleTimeZone(0, "Z",
    673                     (int8_t)month, (int8_t)day, (int8_t)dayOfWeek, time,
    674                     (int8_t)GOOD_MONTH, (int8_t)GOOD_DAY, (int8_t)GOOD_DAY_OF_WEEK,
    675                     GOOD_TIME,status);
    676         //} catch (IllegalArgumentException e) {
    677         //    ex = e;
    678         //}
    679         if (U_SUCCESS(status) != shouldBeGood) {
    680             errln(UnicodeString("SimpleTimeZone(month=") + month + ", day=" + day +
    681                   ", dayOfWeek=" + dayOfWeek + ", time=" + time +
    682                   (shouldBeGood ? (", <end>) should work")// + ex)
    683                    : ", <end>) should fail but doesn't"));
    684         }
    685 
    686         delete temp;
    687         //ex = null;
    688         //try {
    689         status = U_ZERO_ERROR;
    690             temp = new SimpleTimeZone(0, "Z",
    691                     (int8_t)GOOD_MONTH, (int8_t)GOOD_DAY, (int8_t)GOOD_DAY_OF_WEEK,
    692                     GOOD_TIME,
    693                     (int8_t)month, (int8_t)day, (int8_t)dayOfWeek, time,status);
    694         //} catch (IllegalArgumentException e) {
    695         //    ex = e;
    696         //}
    697         if (U_SUCCESS(status) != shouldBeGood) {
    698             errln(UnicodeString("SimpleTimeZone(<start>, month=") + month + ", day=" + day +
    699                   ", dayOfWeek=" + dayOfWeek + ", time=" + time +
    700                   (shouldBeGood ? (") should work")// + ex)
    701                    : ") should fail but doesn't"));
    702         }
    703         delete temp;
    704     }
    705     delete zone;
    706 }
    707 
    708 
    709 /**
    710  * @bug 4154525
    711  * SimpleTimeZone accepts illegal DST savings values.  These values
    712  * must be non-zero.  There is no upper limit at this time.
    713  */
    714 void
    715 TimeZoneRegressionTest::Test4154525()
    716 {
    717     const int32_t GOOD = 1, BAD = 0;
    718 
    719     int32_t DATA [] = {
    720         1, GOOD,
    721         0, BAD,
    722         -1, BAD,
    723         60*60*1000, GOOD,
    724         INT32_MIN, BAD,
    725         // Integer.MAX_VALUE, ?, // no upper limit on DST savings at this time
    726     };
    727 
    728     UErrorCode status = U_ZERO_ERROR;
    729     for(int32_t i = 0; i < 10; i+=2) {
    730         int32_t savings = DATA[i];
    731         UBool valid = DATA[i+1] == GOOD;
    732         UnicodeString method;
    733         for(int32_t j=0; j < 2; ++j) {
    734             SimpleTimeZone *z=NULL;
    735             switch (j) {
    736                 case 0:
    737                     method = "constructor";
    738                     z = new SimpleTimeZone(0, "id",
    739                         UCAL_JANUARY, 1, 0, 0,
    740                         UCAL_MARCH, 1, 0, 0,
    741                         savings, status); // <- what we're interested in
    742                     break;
    743                 case 1:
    744                     method = "setDSTSavings()";
    745                     z = new SimpleTimeZone(0, "GMT");
    746                     z->setDSTSavings(savings, status);
    747                     break;
    748             }
    749 
    750             if(U_FAILURE(status)) {
    751                 if(valid) {
    752                     errln(UnicodeString("Fail: DST savings of ") + savings + " to " + method + " gave " + u_errorName(status));
    753                 }
    754                 else {
    755                     logln(UnicodeString("Pass: DST savings of ") + savings + " to " + method + " gave " + u_errorName(status));
    756                 }
    757             }
    758             else {
    759                 if(valid) {
    760                     logln(UnicodeString("Pass: DST savings of ") + savings + " accepted by " + method);
    761                 }
    762                 else {
    763                     errln(UnicodeString("Fail: DST savings of ") + savings + " accepted by " + method);
    764                 }
    765             }
    766             status = U_ZERO_ERROR;
    767             delete z;
    768         }
    769     }
    770 }
    771 
    772 /**
    773  * @bug 4154650
    774  * SimpleTimeZone.getOffset accepts illegal arguments.
    775  */
    776 void
    777 TimeZoneRegressionTest::Test4154650()
    778 {
    779     const int32_t GOOD = 1, BAD = 0;
    780     const int32_t GOOD_ERA = GregorianCalendar::AD, GOOD_YEAR = 1998, GOOD_MONTH = UCAL_AUGUST;
    781     const int32_t GOOD_DAY = 2, GOOD_DOW = UCAL_SUNDAY, GOOD_TIME = 16*3600000;
    782 
    783     int32_t DATA []= {
    784         GOOD, GOOD_ERA, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, GOOD_DOW, GOOD_TIME,
    785 
    786         GOOD, GregorianCalendar::BC, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, GOOD_DOW, GOOD_TIME,
    787         GOOD, GregorianCalendar::AD, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, GOOD_DOW, GOOD_TIME,
    788         BAD,  GregorianCalendar::BC-1, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, GOOD_DOW, GOOD_TIME,
    789         BAD,  GregorianCalendar::AD+1, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, GOOD_DOW, GOOD_TIME,
    790 
    791         GOOD, GOOD_ERA, GOOD_YEAR, UCAL_JANUARY, GOOD_DAY, GOOD_DOW, GOOD_TIME,
    792         GOOD, GOOD_ERA, GOOD_YEAR, UCAL_DECEMBER, GOOD_DAY, GOOD_DOW, GOOD_TIME,
    793         BAD,  GOOD_ERA, GOOD_YEAR, UCAL_JANUARY-1, GOOD_DAY, GOOD_DOW, GOOD_TIME,
    794         BAD,  GOOD_ERA, GOOD_YEAR, UCAL_DECEMBER+1, GOOD_DAY, GOOD_DOW, GOOD_TIME,
    795 
    796         GOOD, GOOD_ERA, GOOD_YEAR, UCAL_JANUARY, 1, GOOD_DOW, GOOD_TIME,
    797         GOOD, GOOD_ERA, GOOD_YEAR, UCAL_JANUARY, 31, GOOD_DOW, GOOD_TIME,
    798         BAD,  GOOD_ERA, GOOD_YEAR, UCAL_JANUARY, 0, GOOD_DOW, GOOD_TIME,
    799         BAD,  GOOD_ERA, GOOD_YEAR, UCAL_JANUARY, 32, GOOD_DOW, GOOD_TIME,
    800 
    801         GOOD, GOOD_ERA, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, UCAL_SUNDAY, GOOD_TIME,
    802         GOOD, GOOD_ERA, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, UCAL_SATURDAY, GOOD_TIME,
    803         BAD,  GOOD_ERA, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, UCAL_SUNDAY-1, GOOD_TIME,
    804         BAD,  GOOD_ERA, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, UCAL_SATURDAY+1, GOOD_TIME,
    805 
    806         GOOD, GOOD_ERA, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, GOOD_DOW, 0,
    807         GOOD, GOOD_ERA, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, GOOD_DOW, 24*3600000-1,
    808         BAD,  GOOD_ERA, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, GOOD_DOW, -1,
    809         BAD,  GOOD_ERA, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, GOOD_DOW, 24*3600000,
    810     };
    811 
    812     int32_t dataLen = (int32_t)(sizeof(DATA) / sizeof(DATA[0]));
    813 
    814     UErrorCode status = U_ZERO_ERROR;
    815     TimeZone *tz = TimeZone::createDefault();
    816     for(int32_t i = 0; i < dataLen; i += 7) {
    817         UBool good = DATA[i] == GOOD;
    818         //IllegalArgumentException e = null;
    819         //try {
    820             /*int32_t offset = */
    821         tz->getOffset((uint8_t)DATA[i+1], DATA[i+2], DATA[i+3],
    822                       DATA[i+4], (uint8_t)DATA[i+5], DATA[i+6], status);
    823         //} catch (IllegalArgumentException ex) {
    824         //   e = ex;
    825         //}
    826         if(good != U_SUCCESS(status)) {
    827             UnicodeString errMsg;
    828             if (good) {
    829                 errMsg = (UnicodeString(") threw ") + u_errorName(status));
    830             }
    831             else {
    832                 errMsg = UnicodeString(") accepts invalid args", "");
    833             }
    834             errln(UnicodeString("Fail: getOffset(") +
    835                   DATA[i+1] + ", " + DATA[i+2] + ", " + DATA[i+3] + ", " +
    836                   DATA[i+4] + ", " + DATA[i+5] + ", " + DATA[i+6] +
    837                   errMsg);
    838         }
    839         status = U_ZERO_ERROR; // reset
    840     }
    841     delete tz;
    842 }
    843 
    844 /**
    845  * @bug 4162593
    846  * TimeZone broken at midnight.  The TimeZone code fails to handle
    847  * transitions at midnight correctly.
    848  */
    849 void
    850 TimeZoneRegressionTest::Test4162593()
    851 {
    852     UErrorCode status = U_ZERO_ERROR;
    853     SimpleDateFormat *fmt = new SimpleDateFormat("z", Locale::getUS(), status);
    854     if(U_FAILURE(status)) {
    855       errcheckln(status, "Error creating calendar %s", u_errorName(status));
    856       delete fmt;
    857       return;
    858     }
    859     const int32_t ONE_HOUR = 60*60*1000;
    860 
    861     SimpleTimeZone *asuncion = new SimpleTimeZone(-4*ONE_HOUR, "America/Asuncion" /*PY%sT*/,
    862         UCAL_OCTOBER, 1, 0 /*DOM*/, 0*ONE_HOUR,
    863         UCAL_MARCH, 1, 0 /*DOM*/, 0*ONE_HOUR, 1*ONE_HOUR, status);
    864 
    865     /* Zone
    866      * Starting time
    867      * Transition expected between start+1H and start+2H
    868      */
    869     TimeZone *DATA_TZ [] = {
    870       0, 0, 0 };
    871 
    872     int32_t DATA_INT [] [5] = {
    873         // These years must be AFTER the Gregorian cutover
    874         {1998, UCAL_SEPTEMBER, 30, 22, 0},
    875         {2000, UCAL_FEBRUARY, 28, 22, 0},
    876         {2000, UCAL_FEBRUARY, 29, 22, 0},
    877      };
    878 
    879     UBool DATA_BOOL [] = {
    880         TRUE,
    881         FALSE,
    882         TRUE,
    883     };
    884 
    885     UnicodeString zone [4];// = new String[4];
    886     DATA_TZ[0] =
    887         new SimpleTimeZone(2*ONE_HOUR, "Asia/Damascus" /*EE%sT*/,
    888             UCAL_APRIL, 1, 0 /*DOM*/, 0*ONE_HOUR,
    889             UCAL_OCTOBER, 1, 0 /*DOM*/, 0*ONE_HOUR, 1*ONE_HOUR, status);
    890     DATA_TZ[1] = asuncion;  DATA_TZ[2] = asuncion;
    891 
    892     for(int32_t j = 0; j < 3; j++) {
    893         TimeZone *tz = (TimeZone*)DATA_TZ[j];
    894         TimeZone::setDefault(*tz);
    895         fmt->setTimeZone(*tz);
    896 
    897         // Must construct the Date object AFTER setting the default zone
    898         int32_t *p = (int32_t*)DATA_INT[j];
    899         UDate d = CalendarRegressionTest::makeDate(p[0], p[1], p[2], p[3], p[4]);
    900        UBool transitionExpected = DATA_BOOL[j];
    901 
    902         UnicodeString temp;
    903         logln(tz->getID(temp) + ":");
    904         for (int32_t i = 0; i < 4; ++i) {
    905             FieldPosition pos(0);
    906             zone[i].remove();
    907             zone[i] = fmt->format(d+ i*ONE_HOUR, zone[i], pos);
    908             logln(UnicodeString("") + i + ": " + d + " / " + zone[i]);
    909             //d += (double) ONE_HOUR;
    910         }
    911         if(zone[0] == zone[1] &&
    912             (zone[1] == zone[2]) != transitionExpected &&
    913             zone[2] == zone[3]) {
    914             logln(UnicodeString("Ok: transition ") + transitionExpected);
    915         }
    916         else {
    917             errln("Fail: boundary transition incorrect");
    918         }
    919     }
    920     delete fmt;
    921     delete asuncion;
    922     delete DATA_TZ[0];
    923 }
    924 
    925   /**
    926     * getDisplayName doesn't work with unusual savings/offsets.
    927     */
    928 void TimeZoneRegressionTest::Test4176686() {
    929     // Construct a zone that does not observe DST but
    930     // that does have a DST savings (which should be ignored).
    931     UErrorCode status = U_ZERO_ERROR;
    932     int32_t offset = 90 * 60000; // 1:30
    933     SimpleTimeZone* z1 = new SimpleTimeZone(offset, "_std_zone_");
    934     z1->setDSTSavings(45 * 60000, status); // 0:45
    935 
    936     // Construct a zone that observes DST for the first 6 months.
    937     SimpleTimeZone* z2 = new SimpleTimeZone(offset, "_dst_zone_");
    938     z2->setDSTSavings(45 * 60000, status); // 0:45
    939     z2->setStartRule(UCAL_JANUARY, 1, 0, status);
    940     z2->setEndRule(UCAL_JULY, 1, 0, status);
    941 
    942     // Also check DateFormat
    943     DateFormat* fmt1 = new SimpleDateFormat(UnicodeString("z"), status);
    944     if(!assertSuccess("trying to construct", status))return;
    945     fmt1->setTimeZone(*z1); // Format uses standard zone
    946     DateFormat* fmt2 = new SimpleDateFormat(UnicodeString("z"), status);
    947     if(!assertSuccess("trying to construct", status))return;
    948     fmt2->setTimeZone(*z2); // Format uses DST zone
    949     Calendar* tempcal = Calendar::createInstance(status);
    950     tempcal->clear();
    951     tempcal->set(1970, UCAL_FEBRUARY, 1);
    952     UDate dst = tempcal->getTime(status); // Time in DST
    953     tempcal->set(1970, UCAL_AUGUST, 1);
    954     UDate std = tempcal->getTime(status); // Time in standard
    955 
    956     // Description, Result, Expected Result
    957     UnicodeString a,b,c,d,e,f,g,h,i,j,k,l;
    958     UnicodeString DATA[] = {
    959         "z1->getDisplayName(false, SHORT)/std zone",
    960         z1->getDisplayName(FALSE, TimeZone::SHORT, a), "GMT+01:30",
    961         "z1->getDisplayName(false, LONG)/std zone",
    962         z1->getDisplayName(FALSE, TimeZone::LONG, b), "GMT+01:30",
    963         "z1->getDisplayName(true, SHORT)/std zone",
    964         z1->getDisplayName(TRUE, TimeZone::SHORT, c), "GMT+01:30",
    965         "z1->getDisplayName(true, LONG)/std zone",
    966         z1->getDisplayName(TRUE, TimeZone::LONG, d ), "GMT+01:30",
    967         "z2->getDisplayName(false, SHORT)/dst zone",
    968         z2->getDisplayName(FALSE, TimeZone::SHORT, e), "GMT+01:30",
    969         "z2->getDisplayName(false, LONG)/dst zone",
    970         z2->getDisplayName(FALSE, TimeZone::LONG, f ), "GMT+01:30",
    971         "z2->getDisplayName(true, SHORT)/dst zone",
    972         z2->getDisplayName(TRUE, TimeZone::SHORT, g), "GMT+02:15",
    973         "z2->getDisplayName(true, LONG)/dst zone",
    974         z2->getDisplayName(TRUE, TimeZone::LONG, h ), "GMT+02:15",
    975         "DateFormat.format(std)/std zone", fmt1->format(std, i), "GMT+01:30",
    976         "DateFormat.format(dst)/std zone", fmt1->format(dst, j), "GMT+01:30",
    977         "DateFormat.format(std)/dst zone", fmt2->format(std, k), "GMT+01:30",
    978         "DateFormat.format(dst)/dst zone", fmt2->format(dst, l), "GMT+02:15",
    979     };
    980 
    981     for (int32_t idx=0; idx<(int32_t)ARRAY_LENGTH(DATA); idx+=3) {
    982         if (DATA[idx+1]!=(DATA[idx+2])) {
    983             errln("FAIL: " + DATA[idx] + " -> " + DATA[idx+1] + ", exp " + DATA[idx+2]);
    984         }
    985     }
    986     delete z1;
    987     delete z2;
    988     delete fmt1;
    989     delete fmt2;
    990     delete tempcal;
    991 }
    992 
    993 /**
    994  * Make sure setStartRule and setEndRule set the DST savings to nonzero
    995  * if it was zero.
    996  */
    997 void TimeZoneRegressionTest::TestJ186() {
    998     UErrorCode status = U_ZERO_ERROR;
    999     // NOTE: Setting the DST savings to zero is illegal, so we
   1000     // are limited in the testing we can do here.  This is why
   1001     // lines marked //~ are commented out.
   1002     SimpleTimeZone z(0, "ID");
   1003     //~z.setDSTSavings(0, status); // Must do this!
   1004     z.setStartRule(UCAL_FEBRUARY, 1, UCAL_SUNDAY, 0, status);
   1005     failure(status, "setStartRule()");
   1006     if (z.useDaylightTime()) {
   1007         errln("Fail: useDaylightTime true with start rule only");
   1008     }
   1009     //~if (z.getDSTSavings() != 0) {
   1010     //~    errln("Fail: dst savings != 0 with start rule only");
   1011     //~}
   1012     z.setEndRule(UCAL_MARCH, -1, UCAL_SUNDAY, 0, status);
   1013     failure(status, "setStartRule()");
   1014     if (!z.useDaylightTime()) {
   1015         errln("Fail: useDaylightTime false with rules set");
   1016     }
   1017     if (z.getDSTSavings() == 0) {
   1018         errln("Fail: dst savings == 0 with rules set");
   1019     }
   1020 }
   1021 
   1022 /**
   1023  * Test to see if DateFormat understands zone equivalency groups.  It
   1024  * might seem that this should be a DateFormat test, but it's really a
   1025  * TimeZone test -- the changes to DateFormat are minor.
   1026  *
   1027  * We use two known, stable zones that shouldn't change much over time
   1028  * -- America/Vancouver and America/Los_Angeles.  However, they MAY
   1029  * change at some point -- if that happens, replace them with any two
   1030  * zones in an equivalency group where one zone has localized name
   1031  * data, and the other doesn't, in some locale.
   1032  */
   1033 void TimeZoneRegressionTest::TestJ449() {
   1034     UErrorCode status = U_ZERO_ERROR;
   1035     UnicodeString str;
   1036 
   1037     // Modify the following three as necessary.  The two IDs must
   1038     // specify two zones in the same equivalency group.  One must have
   1039     // locale data in 'loc'; the other must not.
   1040     const char* idWithLocaleData = "America/Los_Angeles";
   1041     const char* idWithoutLocaleData = "US/Pacific";
   1042     const Locale loc("en", "", "");
   1043 
   1044     TimeZone *zoneWith = TimeZone::createTimeZone(idWithLocaleData);
   1045     TimeZone *zoneWithout = TimeZone::createTimeZone(idWithoutLocaleData);
   1046     // Make sure we got valid zones
   1047     if (zoneWith->getID(str) != UnicodeString(idWithLocaleData) ||
   1048         zoneWithout->getID(str) != UnicodeString(idWithoutLocaleData)) {
   1049       dataerrln(UnicodeString("Fail: Unable to create zones - wanted ") + idWithLocaleData + ", got " + zoneWith->getID(str) + ", and wanted " + idWithoutLocaleData + " but got " + zoneWithout->getID(str));
   1050     } else {
   1051         GregorianCalendar calWith(*zoneWith, status);
   1052         GregorianCalendar calWithout(*zoneWithout, status);
   1053         SimpleDateFormat fmt("MMM d yyyy hh:mm a zzz", loc, status);
   1054         if (U_FAILURE(status)) {
   1055             errln("Fail: Unable to create GregorianCalendar/SimpleDateFormat");
   1056         } else {
   1057             UDate date = 0;
   1058             UnicodeString strWith, strWithout;
   1059             fmt.setCalendar(calWith);
   1060             fmt.format(date, strWith);
   1061             fmt.setCalendar(calWithout);
   1062             fmt.format(date, strWithout);
   1063             if (strWith == strWithout) {
   1064                 logln((UnicodeString)"Ok: " + idWithLocaleData + " -> " +
   1065                       strWith + "; " + idWithoutLocaleData + " -> " +
   1066                       strWithout);
   1067             } else {
   1068                 errln((UnicodeString)"FAIL: " + idWithLocaleData + " -> " +
   1069                       strWith + "; " + idWithoutLocaleData + " -> " +
   1070                       strWithout);
   1071             }
   1072         }
   1073     }
   1074 
   1075     delete zoneWith;
   1076     delete zoneWithout;
   1077 }
   1078 
   1079 // test new API for JDK 1.2 8/31 putback
   1080 void
   1081 TimeZoneRegressionTest::TestJDK12API()
   1082 {
   1083     // TimeZone *pst = TimeZone::createTimeZone("PST");
   1084     // TimeZone *cst1 = TimeZone::createTimeZone("CST");
   1085     UErrorCode ec = U_ZERO_ERROR;
   1086     //d,-28800,3,1,-1,120,w,9,-1,1,120,w,60
   1087     TimeZone *pst = new SimpleTimeZone(-28800*U_MILLIS_PER_SECOND,
   1088                                        "PST",
   1089                                        3,1,-1,120*U_MILLIS_PER_MINUTE,
   1090                                        SimpleTimeZone::WALL_TIME,
   1091                                        9,-1,1,120*U_MILLIS_PER_MINUTE,
   1092                                        SimpleTimeZone::WALL_TIME,
   1093                                        60*U_MILLIS_PER_MINUTE,ec);
   1094     //d,-21600,3,1,-1,120,w,9,-1,1,120,w,60
   1095     TimeZone *cst1 = new SimpleTimeZone(-21600*U_MILLIS_PER_SECOND,
   1096                                        "CST",
   1097                                        3,1,-1,120*U_MILLIS_PER_MINUTE,
   1098                                        SimpleTimeZone::WALL_TIME,
   1099                                        9,-1,1,120*U_MILLIS_PER_MINUTE,
   1100                                        SimpleTimeZone::WALL_TIME,
   1101                                        60*U_MILLIS_PER_MINUTE,ec);
   1102     if (U_FAILURE(ec)) {
   1103         errln("FAIL: SimpleTimeZone constructor");
   1104         return;
   1105     }
   1106 
   1107     SimpleTimeZone *cst = 0;
   1108 
   1109     if(cst1->getDynamicClassID() == SimpleTimeZone::getStaticClassID())
   1110         cst = (SimpleTimeZone*) cst1;
   1111 
   1112     if(pst->hasSameRules(*cst)) {
   1113         errln("FAILURE: PST and CST have same rules");
   1114     }
   1115 
   1116     UErrorCode status = U_ZERO_ERROR;
   1117     int32_t offset1 = pst->getOffset(1,
   1118         1997, UCAL_OCTOBER, 26, UCAL_SUNDAY, (2*60*60*1000), status);
   1119     failure(status, "getOffset() failed");
   1120 
   1121 
   1122     int32_t offset2 = cst->getOffset(1,
   1123         1997, UCAL_OCTOBER, 26, UCAL_SUNDAY, (2*60*60*1000), 31, status);
   1124     failure(status, "getOffset() failed");
   1125 
   1126     if(offset1 == offset2)
   1127         errln("FAILURE: Sunday Oct. 26 1997 2:00 has same offset for PST and CST");
   1128 
   1129     // verify error checking
   1130     pst->getOffset(1,
   1131         1997, UCAL_FIELD_COUNT+1, 26, UCAL_SUNDAY, (2*60*60*1000), status);
   1132     if(U_SUCCESS(status))
   1133         errln("FAILURE: getOffset() succeeded with -1 for month");
   1134 
   1135     status = U_ZERO_ERROR;
   1136     cst->setDSTSavings(60*60*1000, status);
   1137     failure(status, "setDSTSavings() failed");
   1138 
   1139     int32_t savings = cst->getDSTSavings();
   1140     if(savings != 60*60*1000) {
   1141         errln("setDSTSavings() failed");
   1142     }
   1143 
   1144     delete pst;
   1145     delete cst;
   1146 }
   1147 /**
   1148  * SimpleTimeZone allows invalid DOM values.
   1149  */
   1150 void TimeZoneRegressionTest::Test4184229() {
   1151     SimpleTimeZone* zone = NULL;
   1152     UErrorCode status = U_ZERO_ERROR;
   1153     zone = new SimpleTimeZone(0, "A", 0, -1, 0, 0, 0, 0, 0, 0, status);
   1154     if(U_SUCCESS(status)){
   1155         errln("Failed. No exception has been thrown for DOM -1 startDay");
   1156     }else{
   1157        logln("(a) " + UnicodeString( u_errorName(status)));
   1158     }
   1159     status = U_ZERO_ERROR;
   1160     delete zone;
   1161 
   1162     zone = new SimpleTimeZone(0, "A", 0, 0, 0, 0, 0, -1, 0, 0, status);
   1163     if(U_SUCCESS(status)){
   1164         errln("Failed. No exception has been thrown for DOM -1 endDay");
   1165     }else{
   1166        logln("(b) " + UnicodeString(u_errorName(status)));
   1167     }
   1168     status = U_ZERO_ERROR;
   1169     delete zone;
   1170 
   1171     zone = new SimpleTimeZone(0, "A", 0, -1, 0, 0, 0, 0, 0, 1000, status);
   1172     if(U_SUCCESS(status)){
   1173         errln("Failed. No exception has been thrown for DOM -1 startDay+savings");
   1174     }else{
   1175        logln("(c) " + UnicodeString(u_errorName(status)));
   1176     }
   1177     status = U_ZERO_ERROR;
   1178     delete zone;
   1179     zone = new SimpleTimeZone(0, "A", 0, 0, 0, 0, 0, -1, 0, 0, 1000, status);
   1180     if(U_SUCCESS(status)){
   1181         errln("Failed. No exception has been thrown for DOM -1 endDay+ savings");
   1182     }else{
   1183        logln("(d) " + UnicodeString(u_errorName(status)));
   1184     }
   1185     status = U_ZERO_ERROR;
   1186     delete zone;
   1187     // Make a valid constructor call for subsequent tests.
   1188     zone = new SimpleTimeZone(0, "A", 0, 1, 0, 0, 0, 1, 0, 0, status);
   1189 
   1190     zone->setStartRule(0, -1, 0, 0, status);
   1191     if(U_SUCCESS(status)){
   1192         errln("Failed. No exception has been thrown for DOM -1 setStartRule +savings");
   1193     } else{
   1194         logln("(e) " + UnicodeString(u_errorName(status)));
   1195     }
   1196     zone->setStartRule(0, -1, 0, status);
   1197     if(U_SUCCESS(status)){
   1198         errln("Failed. No exception has been thrown for DOM -1 setStartRule");
   1199     } else{
   1200         logln("(f) " + UnicodeString(u_errorName(status)));
   1201     }
   1202 
   1203     zone->setEndRule(0, -1, 0, 0, status);
   1204     if(U_SUCCESS(status)){
   1205         errln("Failed. No exception has been thrown for DOM -1 setEndRule+savings");
   1206     } else{
   1207         logln("(g) " + UnicodeString(u_errorName(status)));
   1208     }
   1209 
   1210     zone->setEndRule(0, -1, 0, status);
   1211     if(U_SUCCESS(status)){
   1212         errln("Failed. No exception has been thrown for DOM -1 setEndRule");
   1213     } else{
   1214         logln("(h) " + UnicodeString(u_errorName(status)));
   1215     }
   1216     delete zone;
   1217 }
   1218 
   1219 #endif /* #if !UCONFIG_NO_FORMATTING */
   1220