• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
runIndexedTest(int32_t index,UBool exec,const char * & name,char *)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
failure(UErrorCode status,const char * msg)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  */
Test4052967()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  */
Test4073209()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 
findTransitionBinary(const SimpleTimeZone & tz,UDate min,UDate max)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 
findTransitionStepwise(const SimpleTimeZone & tz,UDate min,UDate max)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?
Test4073215()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  */
Test4084933()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  */
Test4096952()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  */
Test4109314()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
checkCalendar314(GregorianCalendar * testCal,TimeZone * testTZ)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  */
Test4126678()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  */
Test4151406()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  */
Test4151429()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  */
Test4154537()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  */
Test4154542()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
Test4154525()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
Test4154650()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
Test4162593()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     */
Test4176686()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  */
TestJ186()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  */
TestJ449()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
TestJDK12API()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  */
Test4184229()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 
TestNegativeDaylightSaving()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