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