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