| // © 2016 and later: Unicode, Inc. and others. | 
 | // License & terms of use: http://www.unicode.org/copyright.html | 
 | /******************************************************************** | 
 |  * Copyright (c) 1997-2016, International Business Machines | 
 |  * Corporation and others. All Rights Reserved. | 
 |  ********************************************************************/ | 
 |   | 
 | #include "unicode/utypes.h" | 
 |  | 
 | #if !UCONFIG_NO_FORMATTING | 
 |  | 
 | #include "unicode/simpletz.h" | 
 | #include "unicode/smpdtfmt.h" | 
 | #include "unicode/strenum.h" | 
 | #include "unicode/gregocal.h" | 
 | #include "tzregts.h" | 
 | #include "calregts.h" | 
 | #include "cmemory.h" | 
 |  | 
 | // ***************************************************************************** | 
 | // class TimeZoneRegressionTest | 
 | // ***************************************************************************** | 
 | #define CASE(id,test) case id: name = #test; if (exec) { logln(#test "---"); logln((UnicodeString)""); test(); } break | 
 |  | 
 | void  | 
 | TimeZoneRegressionTest::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ ) | 
 | { | 
 |     // if (exec) logln((UnicodeString)"TestSuite NumberFormatRegressionTest"); | 
 |     switch (index) { | 
 |  | 
 |         CASE(0, Test4052967); | 
 |         CASE(1, Test4073209); | 
 |         CASE(2, Test4073215); | 
 |         CASE(3, Test4084933); | 
 |         CASE(4, Test4096952); | 
 |         CASE(5, Test4109314); | 
 |         CASE(6, Test4126678); | 
 |         CASE(7, Test4151406); | 
 |         CASE(8, Test4151429); | 
 |         CASE(9, Test4154537); | 
 |         CASE(10, Test4154542); | 
 |         CASE(11, Test4154650); | 
 |         CASE(12, Test4154525); | 
 |         CASE(13, Test4162593); | 
 |         CASE(14, TestJ186); | 
 |         CASE(15, TestJ449); | 
 |         CASE(16, TestJDK12API); | 
 |         CASE(17, Test4176686); | 
 |         CASE(18, Test4184229); | 
 |         CASE(19, TestNegativeDaylightSaving); | 
 |         default: name = ""; break; | 
 |     } | 
 | } | 
 |  | 
 | UBool  | 
 | TimeZoneRegressionTest::failure(UErrorCode status, const char* msg) | 
 | { | 
 |     if(U_FAILURE(status)) { | 
 |         errln(UnicodeString("FAIL: ") + msg + " failed, error " + u_errorName(status)); | 
 |         return true; | 
 |     } | 
 |  | 
 |     return false; | 
 | } | 
 |  | 
 | /** | 
 |  * @bug 4052967 | 
 |  */ | 
 | void TimeZoneRegressionTest:: Test4052967() { | 
 |     // {sfb} not applicable in C++ ? | 
 |     /*logln("*** CHECK TIMEZONE AGAINST HOST OS SETTING ***"); | 
 |     logln("user.timezone:" + System.getProperty("user.timezone", "<not set>")); | 
 |     logln(new Date().toString()); | 
 |     logln("*** THE RESULTS OF THIS TEST MUST BE VERIFIED MANUALLY ***");*/ | 
 | } | 
 |  | 
 | /** | 
 |  * @bug 4073209 | 
 |  */ | 
 | void TimeZoneRegressionTest:: Test4073209() { | 
 |     TimeZone *z1 = TimeZone::createTimeZone("PST"); | 
 |     TimeZone *z2 = TimeZone::createTimeZone("PST"); | 
 |     if (z1 == z2)  | 
 |         errln("Fail: TimeZone should return clones"); | 
 |     delete z1; | 
 |     delete z2; | 
 | } | 
 |  | 
 | UDate TimeZoneRegressionTest::findTransitionBinary(const SimpleTimeZone& tz, UDate min, UDate max) { | 
 |     UErrorCode status = U_ZERO_ERROR; | 
 |     UBool startsInDST = tz.inDaylightTime(min, status); | 
 |     if (failure(status, "SimpleTimeZone::inDaylightTime")) return 0; | 
 |     if (tz.inDaylightTime(max, status) == startsInDST) { | 
 |         logln((UnicodeString)"Error: inDaylightTime() != " + ((!startsInDST)?"true":"false")); | 
 |         return 0; | 
 |     } | 
 |     if (failure(status, "SimpleTimeZone::inDaylightTime")) return 0; | 
 |     while ((max - min) > 100) { // Min accuracy in ms | 
 |         UDate mid = (min + max) / 2; | 
 |         if (tz.inDaylightTime(mid, status) == startsInDST) { | 
 |             min = mid; | 
 |         } else { | 
 |             max = mid; | 
 |         } | 
 |         if (failure(status, "SimpleTimeZone::inDaylightTime")) return 0; | 
 |     } | 
 |     return (min + max) / 2; | 
 | } | 
 |  | 
 | UDate TimeZoneRegressionTest::findTransitionStepwise(const SimpleTimeZone& tz, UDate min, UDate max) { | 
 |     UErrorCode status = U_ZERO_ERROR; | 
 |     UBool startsInDST = tz.inDaylightTime(min, status); | 
 |     if (failure(status, "SimpleTimeZone::inDaylightTime")) return 0; | 
 |     while (min < max) { | 
 |         if (tz.inDaylightTime(min, status) != startsInDST) { | 
 |             return min; | 
 |         } | 
 |         if (failure(status, "SimpleTimeZone::inDaylightTime")) return 0; | 
 |         min += (UDate)24*60*60*1000; // one day | 
 |     } | 
 |     return 0; | 
 | } | 
 |  | 
 | /** | 
 |  * @bug 4073215 | 
 |  */ | 
 | // {sfb} will this work using a Calendar? | 
 | void TimeZoneRegressionTest:: Test4073215()  | 
 | { | 
 |     UErrorCode status = U_ZERO_ERROR; | 
 |     UnicodeString str, str2; | 
 |     LocalPointer<SimpleTimeZone> z(new SimpleTimeZone(0, "GMT"), status); | 
 |     if (U_FAILURE(status)) { | 
 |         errln("Fail: Failed to create SimpleTimeZone %s", u_errorName(status)); | 
 |         return; | 
 |     } | 
 |     if (z->useDaylightTime()) { | 
 |         errln("Fail: Fix test to start with non-DST zone"); | 
 |     } | 
 |     z->setStartRule(UCAL_FEBRUARY, 1, UCAL_SUNDAY, 0, status); | 
 |     failure(status, "z->setStartRule()"); | 
 |     z->setEndRule(UCAL_MARCH, -1, UCAL_SUNDAY, 0, status); | 
 |     failure(status, "z->setStartRule()"); | 
 |     if (!z->useDaylightTime()) { | 
 |         errln("Fail: DST not active"); | 
 |     } | 
 |  | 
 |     GregorianCalendar cal(1997, UCAL_JANUARY, 31, status); | 
 |     if(U_FAILURE(status)) { | 
 |       dataerrln("Error creating calendar %s", u_errorName(status)); | 
 |       return; | 
 |     } | 
 |     failure(status, "new GregorianCalendar"); | 
 |     cal.adoptTimeZone(z.orphan()); | 
 |  | 
 |     SimpleDateFormat sdf((UnicodeString)"E d MMM yyyy G HH:mm", status);  | 
 |     if(U_FAILURE(status)) { | 
 |       dataerrln("Error creating date format %s", u_errorName(status)); | 
 |       return; | 
 |     } | 
 |     sdf.setCalendar(cal);  | 
 |     failure(status, "new SimpleDateFormat"); | 
 |  | 
 |     UDate jan31, mar1, mar31; | 
 |      | 
 |     UBool indt = cal.getTimeZone().inDaylightTime(jan31 = cal.getTime(status), status); | 
 |     failure(status, "inDaylightTime or getTime call on Jan 31"); | 
 |     if (indt) { | 
 |         errln("Fail: Jan 31 inDaylightTime=true, exp false"); | 
 |     } | 
 |     cal.set(1997, UCAL_MARCH, 1); | 
 |     indt = cal.getTimeZone().inDaylightTime(mar1 = cal.getTime(status), status); | 
 |     failure(status, "inDaylightTime or getTime call on Mar 1"); | 
 |     if (!indt) { | 
 |         UnicodeString str; | 
 |         sdf.format(cal.getTime(status), str); | 
 |         failure(status, "getTime"); | 
 |         errln((UnicodeString)"Fail: " + str + " inDaylightTime=false, exp true"); | 
 |     } | 
 |     cal.set(1997, UCAL_MARCH, 31); | 
 |     indt = cal.getTimeZone().inDaylightTime(mar31 = cal.getTime(status), status); | 
 |     failure(status, "inDaylightTime or getTime call on Mar 31"); | 
 |     if (indt) { | 
 |         errln("Fail: Mar 31 inDaylightTime=true, exp false"); | 
 |     } | 
 |  | 
 |     /* | 
 |     cal.set(1997, Calendar::DECEMBER, 31); | 
 |     UDate dec31 = cal.getTime(status); | 
 |     failure(status, "getTime"); | 
 |     UDate trans = findTransitionStepwise(*z, jan31, dec31); | 
 |     logln((UnicodeString)"Stepwise from " + | 
 |           sdf.format(jan31, str.remove()) + "; transition at " + | 
 |           (trans?sdf.format(trans, str2.remove()):(UnicodeString)"NONE")); | 
 |     trans = findTransitionStepwise(*z, mar1, dec31); | 
 |     logln((UnicodeString)"Stepwise from " + | 
 |           sdf.format(mar1, str.remove()) + "; transition at " + | 
 |           (trans?sdf.format(trans, str2.remove()):(UnicodeString)"NONE")); | 
 |     trans = findTransitionStepwise(*z, mar31, dec31); | 
 |     logln((UnicodeString)"Stepwise from " + | 
 |           sdf.format(mar31, str.remove()) + "; transition at " + | 
 |           (trans?sdf.format(trans, str2.remove()):(UnicodeString)"NONE")); | 
 |     */ | 
 | } | 
 |  | 
 | /** | 
 |  * @bug 4084933 | 
 |  * The expected behavior of TimeZone around the boundaries is: | 
 |  * (Assume transition time of 2:00 AM) | 
 |  *    day of onset 1:59 AM STD  = display name 1:59 AM ST | 
 |  *                 2:00 AM STD  = display name 3:00 AM DT | 
 |  *    day of end   0:59 AM STD  = display name 1:59 AM DT | 
 |  *                 1:00 AM STD  = display name 1:00 AM ST | 
 |  */ | 
 | void TimeZoneRegressionTest:: Test4084933() { | 
 |     UErrorCode status = U_ZERO_ERROR; | 
 |     TimeZone *tz = TimeZone::createTimeZone("PST"); | 
 |  | 
 |     int32_t offset1 = tz->getOffset(1, | 
 |         1997, UCAL_OCTOBER, 26, UCAL_SUNDAY, (2*60*60*1000), status); | 
 |     int32_t offset2 = tz->getOffset(1, | 
 |         1997, UCAL_OCTOBER, 26, UCAL_SUNDAY, (2*60*60*1000)-1, status); | 
 |  | 
 |     int32_t offset3 = tz->getOffset(1, | 
 |         1997, UCAL_OCTOBER, 26, UCAL_SUNDAY, (1*60*60*1000), status); | 
 |     int32_t offset4 = tz->getOffset(1, | 
 |         1997, UCAL_OCTOBER, 26, UCAL_SUNDAY, (1*60*60*1000)-1, status); | 
 |  | 
 |     /* | 
 |      *  The following was added just for consistency.  It shows that going *to* Daylight | 
 |      *  Savings Time (PDT) does work at 2am. | 
 |      */ | 
 |     int32_t offset5 = tz->getOffset(1, | 
 |         1997, UCAL_APRIL, 6, UCAL_SUNDAY, (2*60*60*1000), status); | 
 |     int32_t offset6 = tz->getOffset(1, | 
 |         1997, UCAL_APRIL, 6, UCAL_SUNDAY, (2*60*60*1000)-1, status); | 
 |     int32_t offset5a = tz->getOffset(1, | 
 |         1997, UCAL_APRIL, 6, UCAL_SUNDAY, (3*60*60*1000), status); | 
 |     int32_t offset6a = tz->getOffset(1, | 
 |         1997, UCAL_APRIL, 6, UCAL_SUNDAY, (3*60*60*1000)-1, status); | 
 |     int32_t offset7 = tz->getOffset(1, | 
 |         1997, UCAL_APRIL, 6, UCAL_SUNDAY, (1*60*60*1000), status); | 
 |     int32_t offset8 = tz->getOffset(1, | 
 |         1997, UCAL_APRIL, 6, UCAL_SUNDAY, (1*60*60*1000)-1, status); | 
 |     int32_t SToffset = (int32_t)(-8 * 60*60*1000L); | 
 |     int32_t DToffset = (int32_t)(-7 * 60*60*1000L); | 
 |          | 
 | #define ERR_IF_FAIL(x) if(x) { dataerrln("FAIL: TimeZone misbehaving - %s", #x); } | 
 |  | 
 |         ERR_IF_FAIL(U_FAILURE(status)) | 
 |         ERR_IF_FAIL(offset1 != SToffset) | 
 |         ERR_IF_FAIL(offset2 != SToffset) | 
 |         ERR_IF_FAIL(offset3 != SToffset) | 
 |         ERR_IF_FAIL(offset4 != DToffset) | 
 |         ERR_IF_FAIL(offset5 != DToffset) | 
 |         ERR_IF_FAIL(offset6 != SToffset) | 
 |         ERR_IF_FAIL(offset5a != DToffset) | 
 |         ERR_IF_FAIL(offset6a != DToffset) | 
 |         ERR_IF_FAIL(offset7 != SToffset) | 
 |         ERR_IF_FAIL(offset8 != SToffset) | 
 |  | 
 | #undef ERR_IF_FAIL | 
 |  | 
 |     delete tz; | 
 | } | 
 |  | 
 | /** | 
 |  * @bug 4096952 | 
 |  */ | 
 | void TimeZoneRegressionTest:: Test4096952() { | 
 |     // {sfb} serialization not applicable | 
 | /* | 
 |     UnicodeString ZONES [] = { UnicodeString("GMT"), UnicodeString("MET"), UnicodeString("IST") }; | 
 |     UBool pass = true; | 
 |     //try { | 
 |         for (int32_t i=0; i < ZONES.length; ++i) { | 
 |             TimeZone *zone = TimeZone::createTimeZone(ZONES[i]); | 
 |             UnicodeString id; | 
 |             if (zone->getID(id) != ZONES[i]) | 
 |                 errln("Fail: Test broken; zones not instantiating"); | 
 |  | 
 |             ByteArrayOutputStream baos; | 
 |             ObjectOutputStream ostream = | 
 |                 new ObjectOutputStream(baos = new  | 
 |                                        ByteArrayOutputStream()); | 
 |             ostream.writeObject(zone); | 
 |             ostream.close(); | 
 |             baos.close(); | 
 |             ObjectInputStream istream = | 
 |                 new ObjectInputStream(new  | 
 |                                       ByteArrayInputStream(baos.toByteArray())); | 
 |             TimeZone frankenZone = (TimeZone) istream.readObject(); | 
 |             //logln("Zone:        " + zone); | 
 |             //logln("FrankenZone: " + frankenZone); | 
 |             if (!zone.equals(frankenZone)) { | 
 |                 logln("TimeZone " + zone.getID() + | 
 |                       " not equal to serialized/deserialized one"); | 
 |                 pass = false; | 
 |             } | 
 |         } | 
 |         if (!pass) errln("Fail: TimeZone serialization/equality bug"); | 
 |     } | 
 |     catch (IOException e) { | 
 |         errln("Fail: " + e); | 
 |         e.print32_tStackTrace(); | 
 |     } | 
 |     catch (ClassNotFoundException e) { | 
 |         errln("Fail: " + e); | 
 |         e.print32_tStackTrace(); | 
 |     } | 
 | */ | 
 | } | 
 |  | 
 | /** | 
 |  * @bug 4109314 | 
 |  */ | 
 | void TimeZoneRegressionTest:: Test4109314() { | 
 |     UErrorCode status = U_ZERO_ERROR; | 
 |     GregorianCalendar *testCal = (GregorianCalendar*)Calendar::createInstance(status);  | 
 |     if(U_FAILURE(status)) { | 
 |       dataerrln("Error creating calendar %s", u_errorName(status)); | 
 |       delete testCal; | 
 |       return; | 
 |     } | 
 |     failure(status, "Calendar::createInstance"); | 
 |     TimeZone *PST = TimeZone::createTimeZone("PST"); | 
 |     /*Object[] testData = { | 
 |         PST, new Date(98,Calendar.APRIL,4,22,0), new Date(98, Calendar.APRIL, 5,6,0), | 
 |         PST, new Date(98,Calendar.OCTOBER,24,22,0), new Date(98,Calendar.OCTOBER,25,6,0), | 
 |     };*/ | 
 |     UDate testData [] = { | 
 |         CalendarRegressionTest::makeDate(98,UCAL_APRIL,4,22,0),     | 
 |         CalendarRegressionTest::makeDate(98, UCAL_APRIL,5,6,0), | 
 |         CalendarRegressionTest::makeDate(98,UCAL_OCTOBER,24,22,0),  | 
 |         CalendarRegressionTest::makeDate(98,UCAL_OCTOBER,25,6,0) | 
 |     }; | 
 |     UBool pass = true; | 
 |     for (int32_t i = 0; i < 4; i+=2) { | 
 |         //testCal->setTimeZone((TimeZone) testData[i]); | 
 |         testCal->setTimeZone(*PST); | 
 |         UDate t        = testData[i]; | 
 |         UDate end    = testData[i+1]; | 
 |         while(testCal->getTime(status) < end) {  | 
 |             testCal->setTime(t, status); | 
 |             if ( ! checkCalendar314(testCal, PST)) | 
 |                 pass = false; | 
 |             t += 60*60*1000.0; | 
 |         }  | 
 |     } | 
 |     if ( ! pass)  | 
 |         errln("Fail: TZ API inconsistent"); | 
 |  | 
 |     delete testCal; | 
 |     delete PST; | 
 | }  | 
 |  | 
 | UBool  | 
 | TimeZoneRegressionTest::checkCalendar314(GregorianCalendar *testCal, TimeZone *testTZ)  | 
 | { | 
 |     UErrorCode status = U_ZERO_ERROR; | 
 |     // GregorianCalendar testCal = aCal.clone();  | 
 |  | 
 |     int32_t tzOffset, tzRawOffset;  | 
 |     float tzOffsetFloat,tzRawOffsetFloat;  | 
 |     // Here is where the user made an error.  They were passing in the value of | 
 |     // the MILLSECOND field; you need to pass in the millis in the day in STANDARD | 
 |     // time. | 
 |     UDate millis = testCal->get(UCAL_MILLISECOND, status) + | 
 |         1000.0 * (testCal->get(UCAL_SECOND, status) + | 
 |         60.0 * (testCal->get(UCAL_MINUTE, status) + | 
 |         60.0 * (testCal->get(UCAL_HOUR_OF_DAY, status)))) - | 
 |         testCal->get(UCAL_DST_OFFSET, status); | 
 |  | 
 |     /* Fix up millis to be in range.  ASSUME THAT WE ARE NOT AT THE | 
 |      * BEGINNING OR END OF A MONTH.  We must add this code because | 
 |      * getOffset() has been changed to be more strict about the parameters | 
 |      * it receives -- it turns out that this test was passing in illegal | 
 |      * values. */ | 
 |     int32_t date = testCal->get(UCAL_DATE, status); | 
 |     int32_t dow  = testCal->get(UCAL_DAY_OF_WEEK, status); | 
 |     while(millis < 0) { | 
 |         millis += U_MILLIS_PER_DAY; | 
 |         --date; | 
 |         dow = UCAL_SUNDAY + ((dow - UCAL_SUNDAY + 6) % 7); | 
 |     } | 
 |     while (millis >= U_MILLIS_PER_DAY) { | 
 |         millis -= U_MILLIS_PER_DAY; | 
 |         ++date; | 
 |         dow = UCAL_SUNDAY + ((dow - UCAL_SUNDAY + 1) % 7); | 
 |     } | 
 |  | 
 |     tzOffset = testTZ->getOffset((uint8_t)testCal->get(UCAL_ERA, status),  | 
 |                                 testCal->get(UCAL_YEAR, status),  | 
 |                                 testCal->get(UCAL_MONTH, status),  | 
 |                                 date,  | 
 |                                 (uint8_t)dow,  | 
 |                                 (int32_t)millis, | 
 |                                 status);  | 
 |     tzRawOffset = testTZ->getRawOffset();  | 
 |     tzOffsetFloat = (float)tzOffset/(float)3600000;  | 
 |     tzRawOffsetFloat = (float)tzRawOffset/(float)3600000;  | 
 |  | 
 |     UDate testDate = testCal->getTime(status);  | 
 |  | 
 |     UBool inDaylightTime = testTZ->inDaylightTime(testDate, status);  | 
 |     LocalPointer<SimpleDateFormat> sdf(new SimpleDateFormat((UnicodeString) "MM/dd/yyyy HH:mm", status), | 
 |                                        status); | 
 |     if (U_FAILURE(status)) { | 
 |         errln("Error creating SimpleDateFormat %s", u_errorName(status)); | 
 |         return false; | 
 |     } | 
 |     sdf->setCalendar(*testCal);  | 
 |     UnicodeString inDaylightTimeString;  | 
 |  | 
 |     UBool passed;  | 
 |  | 
 |     if(inDaylightTime)  | 
 |     {  | 
 |         inDaylightTimeString = " DST ";  | 
 |         passed = (tzOffset == (tzRawOffset + 3600000)); | 
 |     }  | 
 |     else  | 
 |     {  | 
 |         inDaylightTimeString = "     ";  | 
 |         passed = (tzOffset == tzRawOffset); | 
 |     }  | 
 |  | 
 |     UnicodeString output; | 
 |     FieldPosition pos(FieldPosition::DONT_CARE); | 
 |     output = testTZ->getID(output) + " " + sdf->format(testDate, output, pos) + | 
 |         " Offset(" + tzOffsetFloat + ")" + | 
 |         " RawOffset(" + tzRawOffsetFloat + ")" +  | 
 |         " " + millis/(float)3600000 + " " + | 
 |         inDaylightTimeString;  | 
 |  | 
 |     if (passed)  | 
 |         output += "     ";  | 
 |     else  | 
 |         output += "ERROR";  | 
 |  | 
 |     if (passed)  | 
 |         logln(output);  | 
 |     else  | 
 |         errln(output); | 
 |  | 
 |     return passed; | 
 | }  | 
 |  | 
 | /** | 
 |  * @bug 4126678 | 
 |  * CANNOT REPRODUDE | 
 |  * | 
 |  * Yet another _alleged_ bug in TimeZone::getOffset(), a method that never | 
 |  * should have been made public.  It's simply too hard to use correctly. | 
 |  * | 
 |  * The original test code failed to do the following: | 
 |  * (1) Call Calendar::setTime() before getting the fields! | 
 |  * (2) Use the right millis (as usual) for getOffset(); they were passing | 
 |  *     in the MILLIS field, instead of the STANDARD MILLIS IN DAY. | 
 |  * When you fix these two problems, the test passes, as expected. | 
 |  */ | 
 | void TimeZoneRegressionTest:: Test4126678()  | 
 | { | 
 |     UErrorCode status = U_ZERO_ERROR; | 
 |     Calendar *cal = Calendar::createInstance(status); | 
 |     if(U_FAILURE(status)) { | 
 |       dataerrln("Error creating calendar %s", u_errorName(status)); | 
 |       delete cal; | 
 |       return; | 
 |     } | 
 |     failure(status, "Calendar::createInstance"); | 
 |     TimeZone *tz = TimeZone::createTimeZone("PST"); | 
 |     cal->adoptTimeZone(tz); | 
 |  | 
 |     cal->set(1998, UCAL_APRIL, 5, 10, 0); | 
 |      | 
 |     if (! tz->useDaylightTime() || U_FAILURE(status)) | 
 |         dataerrln("We're not in Daylight Savings Time and we should be. - %s", u_errorName(status)); | 
 |  | 
 |     //cal.setTime(dt); | 
 |     int32_t era = cal->get(UCAL_ERA, status); | 
 |     int32_t year = cal->get(UCAL_YEAR, status); | 
 |     int32_t month = cal->get(UCAL_MONTH, status); | 
 |     int32_t day = cal->get(UCAL_DATE, status); | 
 |     int32_t dayOfWeek = cal->get(UCAL_DAY_OF_WEEK, status); | 
 |     int32_t millis = cal->get(UCAL_MILLISECOND, status) + | 
 |         (cal->get(UCAL_SECOND, status) + | 
 |          (cal->get(UCAL_MINUTE, status) + | 
 |           (cal->get(UCAL_HOUR, status) * 60) * 60) * 1000) - | 
 |         cal->get(UCAL_DST_OFFSET, status); | 
 |  | 
 |     failure(status, "cal->get"); | 
 |     int32_t offset = tz->getOffset((uint8_t)era, year, month, day, (uint8_t)dayOfWeek, millis, status); | 
 |     int32_t raw_offset = tz->getRawOffset(); | 
 |  | 
 |     if (offset == raw_offset) | 
 |         dataerrln("Offsets should match"); | 
 |  | 
 |     delete cal; | 
 | } | 
 |  | 
 | /** | 
 |  * @bug 4151406 | 
 |  * TimeZone::getAvailableIDs(int32_t) throws exception for certain values, | 
 |  * due to a faulty constant in TimeZone::java. | 
 |  */ | 
 | void TimeZoneRegressionTest:: Test4151406() { | 
 |     int32_t max = 0; | 
 |     for (int32_t h=-28; h<=30; ++h) { | 
 |         // h is in half-hours from GMT; rawoffset is in millis | 
 |         int32_t rawoffset = h * 1800000; | 
 |         int32_t hh = (h<0) ? -h : h; | 
 |         UnicodeString hname = UnicodeString((h<0) ? "GMT-" : "GMT+") + | 
 |             ((hh/2 < 10) ? "0" : "") + | 
 |             (hh/2) + ':' + | 
 |             ((hh%2==0) ? "00" : "30"); | 
 |         //try { | 
 |             UErrorCode ec = U_ZERO_ERROR; | 
 |             int32_t count; | 
 |             StringEnumeration* ids = TimeZone::createEnumerationForRawOffset(rawoffset, ec); | 
 |             if (U_FAILURE(ec)) { | 
 |                 dataerrln("Fail: TimeZone::createEnumeration(rawoffset)"); | 
 |                 continue; | 
 |             } | 
 |             count = ids->count(ec); | 
 |             if (count> max)  | 
 |                 max = count; | 
 |             if (count > 0) { | 
 |                 logln(hname + ' ' + (UnicodeString)count + (UnicodeString)" e.g. " + *ids->snext(ec)); | 
 |             } else { | 
 |                 logln(hname + ' ' + count); | 
 |             } | 
 |             // weiv 11/27/2002: why uprv_free? This should be a delete | 
 |             delete ids; | 
 |             //delete [] ids; | 
 |             //uprv_free(ids); | 
 |         /*} catch (Exception e) { | 
 |             errln(hname + ' ' + "Fail: " + e); | 
 |         }*/ | 
 |     } | 
 |     logln("Maximum zones per offset = %d", max); | 
 | } | 
 |  | 
 | /** | 
 |  * @bug 4151429 | 
 |  */ | 
 | void TimeZoneRegressionTest:: Test4151429() { | 
 |     // {sfb} silly test in C++, since we are using an enum and not an int | 
 |     //try { | 
 |         /*TimeZone *tz = TimeZone::createTimeZone("GMT"); | 
 |         UnicodeString name; | 
 |         tz->getDisplayName(true, TimeZone::LONG, | 
 |                                         Locale.getDefault(), name); | 
 |         errln("IllegalArgumentException not thrown by TimeZone::getDisplayName()");*/ | 
 |     //} catch(IllegalArgumentException e) {} | 
 | } | 
 |  | 
 | /** | 
 |  * @bug 4154537 | 
 |  * SimpleTimeZone::hasSameRules() doesn't work for zones with no DST | 
 |  * and different DST parameters. | 
 |  */ | 
 | void TimeZoneRegressionTest:: Test4154537() { | 
 |     UErrorCode status = U_ZERO_ERROR; | 
 |     // tz1 and tz2 have no DST and different rule parameters | 
 |     LocalPointer<SimpleTimeZone> tz1(new SimpleTimeZone(0, "1", 0, 0, 0, 0, 2, 0, 0, 0, status), status); | 
 |     LocalPointer<SimpleTimeZone> tz2(new SimpleTimeZone(0, "2", 1, 0, 0, 0, 3, 0, 0, 0, status), status); | 
 |     // tza and tzA have the same rule params | 
 |     LocalPointer<SimpleTimeZone> tza(new SimpleTimeZone(0, "a", 0, 1, 0, 0, 3, 2, 0, 0, status), status); | 
 |     LocalPointer<SimpleTimeZone> tzA(new SimpleTimeZone(0, "A", 0, 1, 0, 0, 3, 2, 0, 0, status), status); | 
 |     // tzb differs from tza | 
 |     LocalPointer<SimpleTimeZone> tzb(new SimpleTimeZone(0, "b", 0, 1, 0, 0, 3, 1, 0, 0, status), status); | 
 |      | 
 |     if (U_FAILURE(status)) { | 
 |         errln("Couldn't create TimeZones %s", u_errorName(status)); | 
 |         return; | 
 |     } | 
 |  | 
 |     if (tz1->useDaylightTime() || tz2->useDaylightTime() || | 
 |         !tza->useDaylightTime() || !tzA->useDaylightTime() || | 
 |         !tzb->useDaylightTime()) { | 
 |         errln("Test is broken -- rewrite it"); | 
 |     } | 
 |     if (!tza->hasSameRules(*tzA) || tza->hasSameRules(*tzb)) { | 
 |         errln("Fail: hasSameRules() broken for zones with rules"); | 
 |     } | 
 |     if (!tz1->hasSameRules(*tz2)) { | 
 |         errln("Fail: hasSameRules() returns false for zones without rules"); | 
 |         //errln("zone 1 = " + tz1); | 
 |         //errln("zone 2 = " + tz2); | 
 |     } | 
 | } | 
 |  | 
 | /** | 
 |  * @bug 4154542 | 
 |  * SimpleTimeZOne constructors, setStartRule(), and setEndRule() don't | 
 |  * check for out-of-range arguments. | 
 |  */ | 
 | void TimeZoneRegressionTest:: Test4154542()  | 
 | { | 
 |     const int32_t GOOD = 1; | 
 |     const int32_t BAD  = 0; | 
 |  | 
 |     const int32_t GOOD_MONTH       = UCAL_JANUARY; | 
 |     const int32_t GOOD_DAY         = 1; | 
 |     const int32_t GOOD_DAY_OF_WEEK = UCAL_SUNDAY; | 
 |     const int32_t GOOD_TIME        = 0; | 
 |  | 
 |     int32_t DATA [] = { | 
 |         GOOD, INT32_MIN,    0,  INT32_MAX,   INT32_MIN, | 
 |         GOOD, UCAL_JANUARY,    -5,  UCAL_SUNDAY,     0, | 
 |         GOOD, UCAL_DECEMBER,    5,  UCAL_SATURDAY,   24*60*60*1000, | 
 |         BAD,  UCAL_DECEMBER,    5,  UCAL_SATURDAY,   24*60*60*1000+1, | 
 |         BAD,  UCAL_DECEMBER,    5,  UCAL_SATURDAY,  -1, | 
 |         BAD,  UCAL_JANUARY,    -6,  UCAL_SUNDAY,     0, | 
 |         BAD,  UCAL_DECEMBER,    6,  UCAL_SATURDAY,   24*60*60*1000, | 
 |         GOOD, UCAL_DECEMBER,    1,  0,                   0, | 
 |         GOOD, UCAL_DECEMBER,   31,  0,                   0, | 
 |         BAD,  UCAL_APRIL,      31,  0,                   0, | 
 |         BAD,  UCAL_DECEMBER,   32,  0,                   0, | 
 |         BAD,  UCAL_JANUARY-1,   1,  UCAL_SUNDAY,     0, | 
 |         BAD,  UCAL_DECEMBER+1,  1,  UCAL_SUNDAY,     0, | 
 |         GOOD, UCAL_DECEMBER,   31, -UCAL_SUNDAY,     0, | 
 |         GOOD, UCAL_DECEMBER,   31, -UCAL_SATURDAY,   0, | 
 |         BAD,  UCAL_DECEMBER,   32, -UCAL_SATURDAY,   0, | 
 |         BAD,  UCAL_DECEMBER,  -32, -UCAL_SATURDAY,   0, | 
 |         BAD,  UCAL_DECEMBER,   31, -UCAL_SATURDAY-1, 0, | 
 |     }; | 
 |     UErrorCode status = U_ZERO_ERROR; | 
 |     LocalPointer<SimpleTimeZone> zone(new SimpleTimeZone(0, "Z"), status); | 
 |     if (U_FAILURE(status)) { | 
 |         errln("Fail: failed to create SimpleTimeZone %s", u_errorName(status)); | 
 |         return; | 
 |     } | 
 |  | 
 |     for (int32_t i=0; i < 18*5; i+=5) { | 
 |         UBool shouldBeGood = (DATA[i] == GOOD); | 
 |         int32_t month     = DATA[i+1]; | 
 |         int32_t day       = DATA[i+2]; | 
 |         int32_t dayOfWeek = DATA[i+3]; | 
 |         int32_t time      = DATA[i+4]; | 
 |  | 
 |         status = U_ZERO_ERROR; | 
 |  | 
 |         //Exception ex = null; | 
 |         //try { | 
 |             zone->setStartRule(month, day, dayOfWeek, time, status); | 
 |         //} catch (IllegalArgumentException e) { | 
 |         //    ex = e; | 
 |         //} | 
 |         if (U_SUCCESS(status) != shouldBeGood) { | 
 |             errln(UnicodeString("setStartRule(month=") + month + ", day=" + day + | 
 |                   ", dayOfWeek=" + dayOfWeek + ", time=" + time + | 
 |                   (shouldBeGood ? (") should work") | 
 |                    : ") should fail but doesn't")); | 
 |         } | 
 |  | 
 |         //ex = null; | 
 |         //try { | 
 |         status = U_ZERO_ERROR; | 
 |             zone->setEndRule(month, day, dayOfWeek, time, status); | 
 |         //} catch (IllegalArgumentException e) { | 
 |         //   ex = e; | 
 |         //} | 
 |         if (U_SUCCESS(status) != shouldBeGood) { | 
 |             errln(UnicodeString("setEndRule(month=") + month + ", day=" + day + | 
 |                   ", dayOfWeek=" + dayOfWeek + ", time=" + time + | 
 |                   (shouldBeGood ? (") should work") | 
 |                    : ") should fail but doesn't")); | 
 |         } | 
 |  | 
 |         //ex = null; | 
 |         //try { | 
 |         // {sfb} need to look into ctor problems! (UErrorCode vs. dst signature confusion) | 
 |         status = U_ZERO_ERROR; | 
 |             SimpleTimeZone *temp = new SimpleTimeZone(0, "Z", | 
 |                     (int8_t)month, (int8_t)day, (int8_t)dayOfWeek, time, | 
 |                     (int8_t)GOOD_MONTH, (int8_t)GOOD_DAY, (int8_t)GOOD_DAY_OF_WEEK,  | 
 |                     GOOD_TIME,status); | 
 |         if (temp == nullptr) { | 
 |             errln("Fail: failed to create SimpleTimeZone %s", u_errorName(status)); | 
 |             return; | 
 |         } | 
 |         //} catch (IllegalArgumentException e) { | 
 |         //    ex = e; | 
 |         //} | 
 |         if (U_SUCCESS(status) != shouldBeGood) { | 
 |             errln(UnicodeString("SimpleTimeZone(month=") + month + ", day=" + day + | 
 |                   ", dayOfWeek=" + dayOfWeek + ", time=" + time + | 
 |                   (shouldBeGood ? (", <end>) should work")// + ex) | 
 |                    : ", <end>) should fail but doesn't")); | 
 |         } | 
 |    | 
 |         delete temp; | 
 |         //ex = null; | 
 |         //try { | 
 |         status = U_ZERO_ERROR; | 
 |             temp = new SimpleTimeZone(0, "Z", | 
 |                     (int8_t)GOOD_MONTH, (int8_t)GOOD_DAY, (int8_t)GOOD_DAY_OF_WEEK,  | 
 |                     GOOD_TIME, | 
 |                     (int8_t)month, (int8_t)day, (int8_t)dayOfWeek, time,status); | 
 |         if (temp == nullptr) { | 
 |             errln("Fail: failed to create SimpleTimeZone %s", u_errorName(status)); | 
 |             return; | 
 |         } | 
 |         //} catch (IllegalArgumentException e) { | 
 |         //    ex = e; | 
 |         //} | 
 |         if (U_SUCCESS(status) != shouldBeGood) { | 
 |             errln(UnicodeString("SimpleTimeZone(<start>, month=") + month + ", day=" + day + | 
 |                   ", dayOfWeek=" + dayOfWeek + ", time=" + time + | 
 |                   (shouldBeGood ? (") should work")// + ex) | 
 |                    : ") should fail but doesn't")); | 
 |         }             | 
 |         delete temp; | 
 |     } | 
 | } | 
 |  | 
 |  | 
 | /** | 
 |  * @bug 4154525 | 
 |  * SimpleTimeZone accepts illegal DST savings values.  These values | 
 |  * must be non-zero.  There is no upper limit at this time. | 
 |  */ | 
 | void  | 
 | TimeZoneRegressionTest::Test4154525()  | 
 | { | 
 |     const int32_t GOOD = 1, BAD = 0; | 
 |      | 
 |     int32_t DATA [] = { | 
 |         1, GOOD, | 
 |         0, BAD, | 
 |         -1, GOOD,   // #13566 updates SimpleTimeZone to support negative DST saving amount | 
 |         60*60*1000, GOOD, | 
 |         INT32_MAX, GOOD,    // no upper limit on DST savings at this time | 
 |         INT32_MIN, GOOD     // no lower limit as well | 
 |     }; | 
 |  | 
 |     UErrorCode status = U_ZERO_ERROR; | 
 |     for(int32_t i = 0; i < 10; i+=2) { | 
 |         int32_t savings = DATA[i]; | 
 |         UBool valid = DATA[i+1] == GOOD; | 
 |         UnicodeString method; | 
 |         for(int32_t j=0; j < 2; ++j) { | 
 |             LocalPointer<SimpleTimeZone> z; | 
 |             switch (j) { | 
 |                 case 0: | 
 |                     method = "constructor"; | 
 |                     z.adoptInsteadAndCheckErrorCode(new SimpleTimeZone(0, "id", | 
 |                         UCAL_JANUARY, 1, 0, 0, | 
 |                         UCAL_MARCH, 1, 0, 0, | 
 |                         savings, status), status); // <- what we're interested in | 
 |                     break; | 
 |                 case 1: | 
 |                     method = "setDSTSavings()"; | 
 |                     z.adoptInsteadAndCheckErrorCode(new SimpleTimeZone(0, "GMT"), status); | 
 |                     if (z.isValid()) { | 
 |                         z->setDSTSavings(savings, status); | 
 |                     } | 
 |                     break; | 
 |             } | 
 |  | 
 |             if(U_FAILURE(status)) { | 
 |                 if(valid) { | 
 |                     errln(UnicodeString("Fail: DST savings of ") + savings + " to " + method + " gave " + u_errorName(status)); | 
 |                 } | 
 |                 else { | 
 |                     logln(UnicodeString("Pass: DST savings of ") + savings + " to " + method + " gave " + u_errorName(status)); | 
 |                 } | 
 |             } | 
 |             else { | 
 |                 if(valid) { | 
 |                     logln(UnicodeString("Pass: DST savings of ") + savings + " accepted by " + method); | 
 |                 }  | 
 |                 else { | 
 |                     errln(UnicodeString("Fail: DST savings of ") + savings + " accepted by " + method); | 
 |                 } | 
 |             } | 
 |             status = U_ZERO_ERROR; | 
 |         } | 
 |     } | 
 | } | 
 |  | 
 | /** | 
 |  * @bug 4154650 | 
 |  * SimpleTimeZone.getOffset accepts illegal arguments. | 
 |  */ | 
 | void  | 
 | TimeZoneRegressionTest::Test4154650()  | 
 | { | 
 |     const int32_t GOOD = 1, BAD = 0; | 
 |     const int32_t GOOD_ERA = GregorianCalendar::AD, GOOD_YEAR = 1998, GOOD_MONTH = UCAL_AUGUST; | 
 |     const int32_t GOOD_DAY = 2, GOOD_DOW = UCAL_SUNDAY, GOOD_TIME = 16*3600000; | 
 |  | 
 |     int32_t DATA []= { | 
 |         GOOD, GOOD_ERA, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, GOOD_DOW, GOOD_TIME, | 
 |  | 
 |         GOOD, GregorianCalendar::BC, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, GOOD_DOW, GOOD_TIME, | 
 |         GOOD, GregorianCalendar::AD, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, GOOD_DOW, GOOD_TIME, | 
 |         BAD,  GregorianCalendar::BC-1, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, GOOD_DOW, GOOD_TIME, | 
 |         BAD,  GregorianCalendar::AD+1, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, GOOD_DOW, GOOD_TIME, | 
 |  | 
 |         GOOD, GOOD_ERA, GOOD_YEAR, UCAL_JANUARY, GOOD_DAY, GOOD_DOW, GOOD_TIME, | 
 |         GOOD, GOOD_ERA, GOOD_YEAR, UCAL_DECEMBER, GOOD_DAY, GOOD_DOW, GOOD_TIME, | 
 |         BAD,  GOOD_ERA, GOOD_YEAR, UCAL_JANUARY-1, GOOD_DAY, GOOD_DOW, GOOD_TIME, | 
 |         BAD,  GOOD_ERA, GOOD_YEAR, UCAL_DECEMBER+1, GOOD_DAY, GOOD_DOW, GOOD_TIME, | 
 |          | 
 |         GOOD, GOOD_ERA, GOOD_YEAR, UCAL_JANUARY, 1, GOOD_DOW, GOOD_TIME, | 
 |         GOOD, GOOD_ERA, GOOD_YEAR, UCAL_JANUARY, 31, GOOD_DOW, GOOD_TIME, | 
 |         BAD,  GOOD_ERA, GOOD_YEAR, UCAL_JANUARY, 0, GOOD_DOW, GOOD_TIME, | 
 |         BAD,  GOOD_ERA, GOOD_YEAR, UCAL_JANUARY, 32, GOOD_DOW, GOOD_TIME, | 
 |  | 
 |         GOOD, GOOD_ERA, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, UCAL_SUNDAY, GOOD_TIME, | 
 |         GOOD, GOOD_ERA, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, UCAL_SATURDAY, GOOD_TIME, | 
 |         BAD,  GOOD_ERA, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, UCAL_SUNDAY-1, GOOD_TIME, | 
 |         BAD,  GOOD_ERA, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, UCAL_SATURDAY+1, GOOD_TIME, | 
 |  | 
 |         GOOD, GOOD_ERA, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, GOOD_DOW, 0, | 
 |         GOOD, GOOD_ERA, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, GOOD_DOW, 24*3600000-1, | 
 |         BAD,  GOOD_ERA, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, GOOD_DOW, -1, | 
 |         BAD,  GOOD_ERA, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, GOOD_DOW, 24*3600000, | 
 |     }; | 
 |  | 
 |     int32_t dataLen = UPRV_LENGTHOF(DATA); | 
 |  | 
 |     UErrorCode status = U_ZERO_ERROR; | 
 |     TimeZone *tz = TimeZone::createDefault(); | 
 |     for(int32_t i = 0; i < dataLen; i += 7) { | 
 |         UBool good = DATA[i] == GOOD; | 
 |         //IllegalArgumentException e = null; | 
 |         //try { | 
 |             /*int32_t offset = */ | 
 |         tz->getOffset((uint8_t)DATA[i+1], DATA[i+2], DATA[i+3], | 
 |                       DATA[i+4], (uint8_t)DATA[i+5], DATA[i+6], status);  | 
 |         //} catch (IllegalArgumentException ex) { | 
 |         //   e = ex; | 
 |         //} | 
 |         if(good != U_SUCCESS(status)) { | 
 |             UnicodeString errMsg; | 
 |             if (good) { | 
 |                 errMsg = (UnicodeString(") threw ") + u_errorName(status)); | 
 |             } | 
 |             else { | 
 |                 errMsg = UnicodeString(") accepts invalid args", ""); | 
 |             } | 
 |             errln(UnicodeString("Fail: getOffset(") + | 
 |                   DATA[i+1] + ", " + DATA[i+2] + ", " + DATA[i+3] + ", " + | 
 |                   DATA[i+4] + ", " + DATA[i+5] + ", " + DATA[i+6] + | 
 |                   errMsg); | 
 |         } | 
 |         status = U_ZERO_ERROR; // reset | 
 |     } | 
 |     delete tz; | 
 | } | 
 |  | 
 | /** | 
 |  * @bug 4162593 | 
 |  * TimeZone broken at midnight.  The TimeZone code fails to handle | 
 |  * transitions at midnight correctly. | 
 |  */ | 
 | void  | 
 | TimeZoneRegressionTest::Test4162593()  | 
 | { | 
 |     UErrorCode status = U_ZERO_ERROR; | 
 |     LocalPointer<SimpleDateFormat> fmt(new SimpleDateFormat("z", Locale::getUS(), status), status); | 
 |     if (U_FAILURE(status)) { | 
 |       dataerrln("Error creating SimpleDateFormat %s", u_errorName(status)); | 
 |       return; | 
 |     } | 
 |     const int32_t ONE_HOUR = 60*60*1000; | 
 |  | 
 |     LocalPointer<SimpleTimeZone> asuncion(new SimpleTimeZone(-4*ONE_HOUR, "America/Asuncion" /*PY%sT*/, | 
 |         UCAL_OCTOBER, 1, 0 /*DOM*/, 0*ONE_HOUR, | 
 |         UCAL_MARCH, 1, 0 /*DOM*/, 0*ONE_HOUR, 1*ONE_HOUR, status), status); | 
 |  | 
 |     if (U_FAILURE(status)) { | 
 |         dataerrln("Error creating SimpleTimeZone %s", u_errorName(status)); | 
 |         return; | 
 |     } | 
 |  | 
 |     /* Zone | 
 |      * Starting time | 
 |      * Transition expected between start+1H and start+2H | 
 |      */ | 
 |     TimeZone *DATA_TZ [] = { | 
 |       0, 0, 0 }; | 
 |  | 
 |     int32_t DATA_INT [] [5] = { | 
 |         // These years must be AFTER the Gregorian cutover | 
 |         {1998, UCAL_SEPTEMBER, 30, 22, 0}, | 
 |         {2000, UCAL_FEBRUARY, 28, 22, 0}, | 
 |         {2000, UCAL_FEBRUARY, 29, 22, 0}, | 
 |      }; | 
 |  | 
 |     bool DATA_BOOL [] = { | 
 |         true, | 
 |         false, | 
 |         true, | 
 |     }; | 
 |      | 
 |     UnicodeString zone [4];// = new String[4]; | 
 |     DATA_TZ[0] =   | 
 |         new SimpleTimeZone(2*ONE_HOUR, "Asia/Damascus" /*EE%sT*/, | 
 |             UCAL_APRIL, 1, 0 /*DOM*/, 0*ONE_HOUR, | 
 |             UCAL_OCTOBER, 1, 0 /*DOM*/, 0*ONE_HOUR, 1*ONE_HOUR, status); | 
 |     DATA_TZ[1] = asuncion.getAlias();  DATA_TZ[2] = asuncion.getAlias(); | 
 |  | 
 |     if (DATA_TZ[0] == nullptr || U_FAILURE(status)) { | 
 |         errln("Error creating DATA_TZ[0] %s", u_errorName(status)); | 
 |         return; | 
 |     } | 
 |  | 
 |     for(int32_t j = 0; j < 3; j++) { | 
 |         TimeZone *tz = (TimeZone*)DATA_TZ[j]; | 
 |         TimeZone::setDefault(*tz); | 
 |         fmt->setTimeZone(*tz); | 
 |  | 
 |         // Must construct the Date object AFTER setting the default zone | 
 |         int32_t *p = (int32_t*)DATA_INT[j]; | 
 |         UDate d = CalendarRegressionTest::makeDate(p[0], p[1], p[2], p[3], p[4]); | 
 |         bool transitionExpected = DATA_BOOL[j]; | 
 |  | 
 |         UnicodeString temp; | 
 |         logln(tz->getID(temp) + ":"); | 
 |         for (int32_t i = 0; i < 4; ++i) { | 
 |             FieldPosition pos(FieldPosition::DONT_CARE); | 
 |             zone[i].remove(); | 
 |             zone[i] = fmt->format(d+ i*ONE_HOUR, zone[i], pos); | 
 |             logln(UnicodeString("") + i + ": " + d + " / " + zone[i]); | 
 |             //d += (double) ONE_HOUR; | 
 |         } | 
 |         if(zone[0] == zone[1] && | 
 |             (zone[1] == zone[2]) != transitionExpected && | 
 |             zone[2] == zone[3]) { | 
 |             logln(UnicodeString("Ok: transition ") + transitionExpected); | 
 |         }  | 
 |         else { | 
 |             errln("Fail: boundary transition incorrect"); | 
 |         } | 
 |     } | 
 |     delete DATA_TZ[0]; | 
 | } | 
 |  | 
 |   /** | 
 |     * getDisplayName doesn't work with unusual savings/offsets. | 
 |     */ | 
 | void TimeZoneRegressionTest::Test4176686() { | 
 |     // Construct a zone that does not observe DST but | 
 |     // that does have a DST savings (which should be ignored). | 
 |     UErrorCode status = U_ZERO_ERROR; | 
 |     int32_t offset = 90 * 60000; // 1:30 | 
 |     SimpleTimeZone z1(offset, "_std_zone_"); | 
 |     z1.setDSTSavings(45 * 60000, status); // 0:45 | 
 |  | 
 |     // Construct a zone that observes DST for the first 6 months. | 
 |     SimpleTimeZone z2(offset, "_dst_zone_"); | 
 |     z2.setDSTSavings(45 * 60000, status); // 0:45 | 
 |     z2.setStartRule(UCAL_JANUARY, 1, 0, status); | 
 |     z2.setEndRule(UCAL_JULY, 1, 0, status); | 
 |  | 
 |     // Also check DateFormat | 
 |     SimpleDateFormat fmt1(UnicodeString(u"z"), status); | 
 |     if (U_FAILURE(status)) { | 
 |         dataerrln("Failure trying to construct: %s", u_errorName(status)); | 
 |         return; | 
 |     } | 
 |     fmt1.setTimeZone(z1); // Format uses standard zone | 
 |     SimpleDateFormat fmt2(UnicodeString(u"z"), status); | 
 |     if(!assertSuccess("trying to construct", status))return; | 
 |     fmt2.setTimeZone(z2); // Format uses DST zone | 
 |     LocalPointer<Calendar> tempcal(Calendar::createInstance(status)); | 
 |     tempcal->clear(); | 
 |     tempcal->set(1970, UCAL_FEBRUARY, 1); | 
 |     UDate dst = tempcal->getTime(status); // Time in DST | 
 |     tempcal->set(1970, UCAL_AUGUST, 1); | 
 |     UDate std = tempcal->getTime(status); // Time in standard | 
 |  | 
 |     // Description, Result, Expected Result | 
 |     UnicodeString a,b,c,d,e,f,g,h,i,j,k,l; | 
 |     UnicodeString DATA[] = { | 
 |         "z1.getDisplayName(false, SHORT)/std zone", | 
 |         z1.getDisplayName(false, TimeZone::SHORT, a), "GMT+1:30", | 
 |         "z1.getDisplayName(false, LONG)/std zone", | 
 |         z1.getDisplayName(false, TimeZone::LONG, b), "GMT+01:30", | 
 |         "z1.getDisplayName(true, SHORT)/std zone", | 
 |         z1.getDisplayName(true, TimeZone::SHORT, c), "GMT+1:30", | 
 |         "z1.getDisplayName(true, LONG)/std zone", | 
 |         z1.getDisplayName(true, TimeZone::LONG, d ), "GMT+01:30", | 
 |         "z2.getDisplayName(false, SHORT)/dst zone", | 
 |         z2.getDisplayName(false, TimeZone::SHORT, e), "GMT+1:30", | 
 |         "z2.getDisplayName(false, LONG)/dst zone", | 
 |         z2.getDisplayName(false, TimeZone::LONG, f ), "GMT+01:30", | 
 |         "z2.getDisplayName(true, SHORT)/dst zone", | 
 |         z2.getDisplayName(true, TimeZone::SHORT, g), "GMT+2:15", | 
 |         "z2.getDisplayName(true, LONG)/dst zone", | 
 |         z2.getDisplayName(true, TimeZone::LONG, h ), "GMT+02:15", | 
 |         "DateFormat.format(std)/std zone", fmt1.format(std, i), "GMT+1:30", | 
 |         "DateFormat.format(dst)/std zone", fmt1.format(dst, j), "GMT+1:30", | 
 |         "DateFormat.format(std)/dst zone", fmt2.format(std, k), "GMT+1:30", | 
 |         "DateFormat.format(dst)/dst zone", fmt2.format(dst, l), "GMT+2:15", | 
 |     }; | 
 |  | 
 |     for (int32_t idx=0; idx<UPRV_LENGTHOF(DATA); idx+=3) { | 
 |         if (DATA[idx+1]!=(DATA[idx+2])) { | 
 |             errln("FAIL: " + DATA[idx] + " -> " + DATA[idx+1] + ", exp " + DATA[idx+2]); | 
 |         } | 
 |     } | 
 | } | 
 |  | 
 | /** | 
 |  * Make sure setStartRule and setEndRule set the DST savings to nonzero | 
 |  * if it was zero. | 
 |  */ | 
 | void TimeZoneRegressionTest::TestJ186() { | 
 |     UErrorCode status = U_ZERO_ERROR; | 
 |     // NOTE: Setting the DST savings to zero is illegal, so we | 
 |     // are limited in the testing we can do here.  This is why | 
 |     // lines marked //~ are commented out. | 
 |     SimpleTimeZone z(0, "ID"); | 
 |     //~z.setDSTSavings(0, status); // Must do this! | 
 |     z.setStartRule(UCAL_FEBRUARY, 1, UCAL_SUNDAY, 0, status); | 
 |     failure(status, "setStartRule()"); | 
 |     if (z.useDaylightTime()) { | 
 |         errln("Fail: useDaylightTime true with start rule only"); | 
 |     } | 
 |     //~if (z.getDSTSavings() != 0) { | 
 |     //~    errln("Fail: dst savings != 0 with start rule only"); | 
 |     //~} | 
 |     z.setEndRule(UCAL_MARCH, -1, UCAL_SUNDAY, 0, status); | 
 |     failure(status, "setStartRule()"); | 
 |     if (!z.useDaylightTime()) { | 
 |         errln("Fail: useDaylightTime false with rules set"); | 
 |     } | 
 |     if (z.getDSTSavings() == 0) { | 
 |         errln("Fail: dst savings == 0 with rules set"); | 
 |     } | 
 | } | 
 |  | 
 | /** | 
 |  * Test to see if DateFormat understands zone equivalency groups.  It | 
 |  * might seem that this should be a DateFormat test, but it's really a | 
 |  * TimeZone test -- the changes to DateFormat are minor. | 
 |  * | 
 |  * We use two known, stable zones that shouldn't change much over time | 
 |  * -- America/Vancouver and America/Los_Angeles.  However, they MAY | 
 |  * change at some point -- if that happens, replace them with any two | 
 |  * zones in an equivalency group where one zone has localized name | 
 |  * data, and the other doesn't, in some locale. | 
 |  */ | 
 | void TimeZoneRegressionTest::TestJ449() { | 
 |     UErrorCode status = U_ZERO_ERROR; | 
 |     UnicodeString str; | 
 |  | 
 |     // Modify the following three as necessary.  The two IDs must | 
 |     // specify two zones in the same equivalency group.  One must have | 
 |     // locale data in 'loc'; the other must not. | 
 |     const char* idWithLocaleData = "America/Los_Angeles"; | 
 |     const char* idWithoutLocaleData = "US/Pacific"; | 
 |     const Locale loc("en", "", ""); | 
 |  | 
 |     TimeZone *zoneWith = TimeZone::createTimeZone(idWithLocaleData); | 
 |     TimeZone *zoneWithout = TimeZone::createTimeZone(idWithoutLocaleData); | 
 |     // Make sure we got valid zones | 
 |     if (zoneWith->getID(str) != UnicodeString(idWithLocaleData) || | 
 |         zoneWithout->getID(str) != UnicodeString(idWithoutLocaleData)) { | 
 |       dataerrln(UnicodeString("Fail: Unable to create zones - wanted ") + idWithLocaleData + ", got " + zoneWith->getID(str) + ", and wanted " + idWithoutLocaleData + " but got " + zoneWithout->getID(str)); | 
 |     } else { | 
 |         GregorianCalendar calWith(*zoneWith, status); | 
 |         GregorianCalendar calWithout(*zoneWithout, status); | 
 |         SimpleDateFormat fmt("MMM d yyyy hh:mm a zzz", loc, status); | 
 |         if (U_FAILURE(status)) { | 
 |             errln("Fail: Unable to create GregorianCalendar/SimpleDateFormat"); | 
 |         } else { | 
 |             UDate date = 0; | 
 |             UnicodeString strWith, strWithout; | 
 |             fmt.setCalendar(calWith); | 
 |             fmt.format(date, strWith); | 
 |             fmt.setCalendar(calWithout); | 
 |             fmt.format(date, strWithout); | 
 |             if (strWith == strWithout) { | 
 |                 logln((UnicodeString)"Ok: " + idWithLocaleData + " -> " + | 
 |                       strWith + "; " + idWithoutLocaleData + " -> " + | 
 |                       strWithout); | 
 |             } else { | 
 |                 errln((UnicodeString)"FAIL: " + idWithLocaleData + " -> " + | 
 |                       strWith + "; " + idWithoutLocaleData + " -> " + | 
 |                       strWithout); | 
 |             } | 
 |         } | 
 |     } | 
 |  | 
 |     delete zoneWith; | 
 |     delete zoneWithout; | 
 | } | 
 |  | 
 | // test new API for JDK 1.2 8/31 putback | 
 | void | 
 | TimeZoneRegressionTest::TestJDK12API() | 
 | { | 
 |     // TimeZone *pst = TimeZone::createTimeZone("PST"); | 
 |     // TimeZone *cst1 = TimeZone::createTimeZone("CST"); | 
 |     UErrorCode ec = U_ZERO_ERROR; | 
 |     //d,-28800,3,1,-1,120,w,9,-1,1,120,w,60 | 
 |     LocalPointer<TimeZone> pst(new SimpleTimeZone(-28800*U_MILLIS_PER_SECOND, | 
 |                                        "PST", | 
 |                                        3,1,-1,120*U_MILLIS_PER_MINUTE, | 
 |                                        SimpleTimeZone::WALL_TIME, | 
 |                                        9,-1,1,120*U_MILLIS_PER_MINUTE, | 
 |                                        SimpleTimeZone::WALL_TIME, | 
 |                                        60*U_MILLIS_PER_MINUTE,ec), ec); | 
 |     //d,-21600,3,1,-1,120,w,9,-1,1,120,w,60 | 
 |     LocalPointer<TimeZone> cst1(new SimpleTimeZone(-21600*U_MILLIS_PER_SECOND, | 
 |                                        "CST", | 
 |                                        3,1,-1,120*U_MILLIS_PER_MINUTE, | 
 |                                        SimpleTimeZone::WALL_TIME, | 
 |                                        9,-1,1,120*U_MILLIS_PER_MINUTE, | 
 |                                        SimpleTimeZone::WALL_TIME, | 
 |                                        60*U_MILLIS_PER_MINUTE,ec), ec); | 
 |     if (U_FAILURE(ec)) { | 
 |         errln("FAIL: SimpleTimeZone constructor"); | 
 |         return; | 
 |     } | 
 |  | 
 |     SimpleTimeZone *cst = dynamic_cast<SimpleTimeZone *>(cst1.getAlias()); | 
 |  | 
 |     if(pst->hasSameRules(*cst)) { | 
 |         errln("FAILURE: PST and CST have same rules"); | 
 |     } | 
 |  | 
 |     UErrorCode status = U_ZERO_ERROR; | 
 |     int32_t offset1 = pst->getOffset(1, | 
 |         1997, UCAL_OCTOBER, 26, UCAL_SUNDAY, (2*60*60*1000), status); | 
 |     failure(status, "getOffset() failed"); | 
 |  | 
 |  | 
 |     int32_t offset2 = cst->getOffset(1, | 
 |         1997, UCAL_OCTOBER, 26, UCAL_SUNDAY, (2*60*60*1000), 31, status); | 
 |     failure(status, "getOffset() failed"); | 
 |  | 
 |     if(offset1 == offset2) | 
 |         errln("FAILURE: Sunday Oct. 26 1997 2:00 has same offset for PST and CST"); | 
 |  | 
 |     // verify error checking | 
 |     pst->getOffset(1, | 
 |         1997, UCAL_FIELD_COUNT+1, 26, UCAL_SUNDAY, (2*60*60*1000), status); | 
 |     if(U_SUCCESS(status)) | 
 |         errln("FAILURE: getOffset() succeeded with -1 for month"); | 
 |  | 
 |     status = U_ZERO_ERROR; | 
 |     cst->setDSTSavings(60*60*1000, status); | 
 |     failure(status, "setDSTSavings() failed"); | 
 |  | 
 |     int32_t savings = cst->getDSTSavings(); | 
 |     if(savings != 60*60*1000) { | 
 |         errln("setDSTSavings() failed"); | 
 |     } | 
 | } | 
 | /** | 
 |  * SimpleTimeZone allows invalid DOM values. | 
 |  */ | 
 | void TimeZoneRegressionTest::Test4184229() { | 
 |     SimpleTimeZone* zone = NULL; | 
 |     UErrorCode status = U_ZERO_ERROR; | 
 |     zone = new SimpleTimeZone(0, "A", 0, -1, 0, 0, 0, 0, 0, 0, status); | 
 |     if(U_SUCCESS(status)){ | 
 |         errln("Failed. No exception has been thrown for DOM -1 startDay"); | 
 |     }else{ | 
 |        logln("(a) " + UnicodeString( u_errorName(status))); | 
 |     } | 
 |     status = U_ZERO_ERROR; | 
 |     delete zone; | 
 |  | 
 |     zone = new SimpleTimeZone(0, "A", 0, 0, 0, 0, 0, -1, 0, 0, status); | 
 |     if(U_SUCCESS(status)){ | 
 |         errln("Failed. No exception has been thrown for DOM -1 endDay"); | 
 |     }else{ | 
 |        logln("(b) " + UnicodeString(u_errorName(status))); | 
 |     } | 
 |     status = U_ZERO_ERROR; | 
 |     delete zone; | 
 |  | 
 |     zone = new SimpleTimeZone(0, "A", 0, -1, 0, 0, 0, 0, 0, 1000, status); | 
 |     if(U_SUCCESS(status)){ | 
 |         errln("Failed. No exception has been thrown for DOM -1 startDay+savings"); | 
 |     }else{ | 
 |        logln("(c) " + UnicodeString(u_errorName(status))); | 
 |     } | 
 |     status = U_ZERO_ERROR; | 
 |     delete zone; | 
 |     zone = new SimpleTimeZone(0, "A", 0, 0, 0, 0, 0, -1, 0, 0, 1000, status); | 
 |     if(U_SUCCESS(status)){ | 
 |         errln("Failed. No exception has been thrown for DOM -1 endDay+ savings"); | 
 |     }else{ | 
 |        logln("(d) " + UnicodeString(u_errorName(status))); | 
 |     } | 
 |     status = U_ZERO_ERROR; | 
 |     delete zone; | 
 |     // Make a valid constructor call for subsequent tests. | 
 |     zone = new SimpleTimeZone(0, "A", 0, 1, 0, 0, 0, 1, 0, 0, status); | 
 |      | 
 |     zone->setStartRule(0, -1, 0, 0, status); | 
 |     if(U_SUCCESS(status)){ | 
 |         errln("Failed. No exception has been thrown for DOM -1 setStartRule +savings"); | 
 |     } else{ | 
 |         logln("(e) " + UnicodeString(u_errorName(status))); | 
 |     } | 
 |     zone->setStartRule(0, -1, 0, status); | 
 |     if(U_SUCCESS(status)){ | 
 |         errln("Failed. No exception has been thrown for DOM -1 setStartRule"); | 
 |     } else{ | 
 |         logln("(f) " + UnicodeString(u_errorName(status))); | 
 |     } | 
 |  | 
 |     zone->setEndRule(0, -1, 0, 0, status); | 
 |     if(U_SUCCESS(status)){ | 
 |         errln("Failed. No exception has been thrown for DOM -1 setEndRule+savings"); | 
 |     } else{ | 
 |         logln("(g) " + UnicodeString(u_errorName(status))); | 
 |     }    | 
 |  | 
 |     zone->setEndRule(0, -1, 0, status); | 
 |     if(U_SUCCESS(status)){ | 
 |         errln("Failed. No exception has been thrown for DOM -1 setEndRule"); | 
 |     } else{ | 
 |         logln("(h) " + UnicodeString(u_errorName(status))); | 
 |     } | 
 |     delete zone; | 
 | } | 
 |  | 
 | void TimeZoneRegressionTest::TestNegativeDaylightSaving() { | 
 |     UErrorCode status = U_ZERO_ERROR; | 
 |     int32_t stdOff = 1 * 60*60*1000;    // Standard offset UTC+1 | 
 |     int save = -1 * 60*60*1000;     // DST saving amount -1 hour | 
 |     SimpleTimeZone stzDublin(stdOff, "Dublin-2018", | 
 |                                 UCAL_OCTOBER, -1, -UCAL_SUNDAY, 2*60*60*1000, | 
 |                                 UCAL_MARCH, -1, -UCAL_SUNDAY, 1*60*60*1000, | 
 |                                 save, status); | 
 |     failure(status, "SimpleTimeZone constructor"); | 
 |  | 
 |     if (save != stzDublin.getDSTSavings()) { | 
 |         errln((UnicodeString)"FAIL: DST saving is not " + save); | 
 |     } | 
 |  | 
 |     GregorianCalendar cal(* TimeZone::getGMT(), status); | 
 |     failure(status, "GregorianCalendar constructor"); | 
 |  | 
 |     UDate testDate; | 
 |     int32_t rawOffset; | 
 |     int32_t dstOffset; | 
 |  | 
 |     cal.set(2018, UCAL_JANUARY, 15, 0, 0, 0); | 
 |     testDate = cal.getTime(status); | 
 |     failure(status, "calendar getTime() - Jan 15"); | 
 |  | 
 |     if (!stzDublin.inDaylightTime(testDate, status)) { | 
 |         errln("FAIL: The test date (Jan 15) must be in DST."); | 
 |     } | 
 |     failure(status, "inDaylightTime() - Jan 15"); | 
 |  | 
 |     stzDublin.getOffset(testDate, false, rawOffset, dstOffset, status); | 
 |     failure(status, "getOffset() - Jan 15"); | 
 |     if (rawOffset != stdOff || dstOffset != save) { | 
 |         errln((UnicodeString)"FAIL: Expected [stdoff=" + stdOff + ",save=" + save | 
 |             + "] on the test date (Jan 15), actual[stdoff=" + rawOffset | 
 |             + ",save=" + dstOffset + "]"); | 
 |     } | 
 |  | 
 |     cal.set(2018, UCAL_JULY, 15, 0, 0, 0); | 
 |     testDate = cal.getTime(status); | 
 |     failure(status, "calendar getTime() - Jul 15"); | 
 |  | 
 |     if (stzDublin.inDaylightTime(testDate, status)) { | 
 |         errln("FAIL: The test date (Jul 15) must be in DST."); | 
 |     } | 
 |     failure(status, "inDaylightTime() - Jul 15"); | 
 |  | 
 |     stzDublin.getOffset(testDate, false, rawOffset, dstOffset, status); | 
 |     failure(status, "getOffset() - Jul 15"); | 
 |     if (rawOffset != stdOff || dstOffset != 0) { | 
 |         errln((UnicodeString)"FAIL: Expected [stdoff=" + stdOff + ",save=" + 0 | 
 |             + "] on the test date (Jul 15), actual[stdoff=" + rawOffset | 
 |             + ",save=" + dstOffset + "]"); | 
 |     } | 
 | } | 
 |  | 
 |  | 
 | #endif /* #if !UCONFIG_NO_FORMATTING */ |