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