1/********************************************************************
2 * Copyright (c) 1997-2013, 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
24void
25TimeZoneRegressionTest::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
53UBool
54TimeZoneRegressionTest::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 */
67void 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 */
78void 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
87UDate 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
108UDate 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?
126void 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      dataerrln("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      dataerrln("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 */
207void 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) { dataerrln("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 */
262void 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 */
309void TimeZoneRegressionTest:: Test4109314() {
310    UErrorCode status = U_ZERO_ERROR;
311    GregorianCalendar *testCal = (GregorianCalendar*)Calendar::createInstance(status);
312    if(U_FAILURE(status)) {
313      dataerrln("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
349UBool
350TimeZoneRegressionTest::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 */
450void TimeZoneRegressionTest:: Test4126678()
451{
452    UErrorCode status = U_ZERO_ERROR;
453    Calendar *cal = Calendar::createInstance(status);
454    if(U_FAILURE(status)) {
455      dataerrln("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, UCAL_APRIL, 5, 10, 0);
464
465    if (! tz->useDaylightTime() || U_FAILURE(status))
466        dataerrln("We're not in Daylight Savings Time and we should be. - %s", u_errorName(status));
467
468    //cal.setTime(dt);
469    int32_t era = cal->get(UCAL_ERA, status);
470    int32_t year = cal->get(UCAL_YEAR, status);
471    int32_t month = cal->get(UCAL_MONTH, status);
472    int32_t day = cal->get(UCAL_DATE, status);
473    int32_t dayOfWeek = cal->get(UCAL_DAY_OF_WEEK, status);
474    int32_t millis = cal->get(UCAL_MILLISECOND, status) +
475        (cal->get(UCAL_SECOND, status) +
476         (cal->get(UCAL_MINUTE, status) +
477          (cal->get(UCAL_HOUR, status) * 60) * 60) * 1000) -
478        cal->get(UCAL_DST_OFFSET, status);
479
480    failure(status, "cal->get");
481    int32_t offset = tz->getOffset((uint8_t)era, year, month, day, (uint8_t)dayOfWeek, millis, status);
482    int32_t raw_offset = tz->getRawOffset();
483
484    if (offset == raw_offset)
485        dataerrln("Offsets should match");
486
487    delete cal;
488}
489
490/**
491 * @bug 4151406
492 * TimeZone::getAvailableIDs(int32_t) throws exception for certain values,
493 * due to a faulty constant in TimeZone::java.
494 */
495void TimeZoneRegressionTest:: Test4151406() {
496    int32_t max = 0;
497    for (int32_t h=-28; h<=30; ++h) {
498        // h is in half-hours from GMT; rawoffset is in millis
499        int32_t rawoffset = h * 1800000;
500        int32_t hh = (h<0) ? -h : h;
501        UnicodeString hname = UnicodeString((h<0) ? "GMT-" : "GMT+") +
502            ((hh/2 < 10) ? "0" : "") +
503            (hh/2) + ':' +
504            ((hh%2==0) ? "00" : "30");
505        //try {
506            UErrorCode ec = U_ZERO_ERROR;
507            int32_t count;
508            StringEnumeration* ids = TimeZone::createEnumeration(rawoffset);
509            if (ids == NULL) {
510                dataerrln("Fail: TimeZone::createEnumeration(rawoffset)");
511                continue;
512            }
513            count = ids->count(ec);
514            if (count> max)
515                max = count;
516            if (count > 0) {
517                logln(hname + ' ' + (UnicodeString)count + (UnicodeString)" e.g. " + *ids->snext(ec));
518            } else {
519                logln(hname + ' ' + count);
520            }
521            // weiv 11/27/2002: why uprv_free? This should be a delete
522            delete ids;
523            //delete [] ids;
524            //uprv_free(ids);
525        /*} catch (Exception e) {
526            errln(hname + ' ' + "Fail: " + e);
527        }*/
528    }
529    logln("Maximum zones per offset = %d", max);
530}
531
532/**
533 * @bug 4151429
534 */
535void TimeZoneRegressionTest:: Test4151429() {
536    // {sfb} silly test in C++, since we are using an enum and not an int
537    //try {
538        /*TimeZone *tz = TimeZone::createTimeZone("GMT");
539        UnicodeString name;
540        tz->getDisplayName(TRUE, TimeZone::LONG,
541                                        Locale.getDefault(), name);
542        errln("IllegalArgumentException not thrown by TimeZone::getDisplayName()");*/
543    //} catch(IllegalArgumentException e) {}
544}
545
546/**
547 * @bug 4154537
548 * SimpleTimeZone::hasSameRules() doesn't work for zones with no DST
549 * and different DST parameters.
550 */
551void TimeZoneRegressionTest:: Test4154537() {
552    UErrorCode status = U_ZERO_ERROR;
553    // tz1 and tz2 have no DST and different rule parameters
554    SimpleTimeZone *tz1 = new SimpleTimeZone(0, "1", 0, 0, 0, 0, 2, 0, 0, 0, status);
555    SimpleTimeZone *tz2 = new SimpleTimeZone(0, "2", 1, 0, 0, 0, 3, 0, 0, 0, status);
556    // tza and tzA have the same rule params
557    SimpleTimeZone *tza = new SimpleTimeZone(0, "a", 0, 1, 0, 0, 3, 2, 0, 0, status);
558    SimpleTimeZone *tzA = new SimpleTimeZone(0, "A", 0, 1, 0, 0, 3, 2, 0, 0, status);
559    // tzb differs from tza
560    SimpleTimeZone *tzb = new SimpleTimeZone(0, "b", 0, 1, 0, 0, 3, 1, 0, 0, status);
561
562    if(U_FAILURE(status))
563        errln("Couldn't create TimeZones");
564
565    if (tz1->useDaylightTime() || tz2->useDaylightTime() ||
566        !tza->useDaylightTime() || !tzA->useDaylightTime() ||
567        !tzb->useDaylightTime()) {
568        errln("Test is broken -- rewrite it");
569    }
570    if (!tza->hasSameRules(*tzA) || tza->hasSameRules(*tzb)) {
571        errln("Fail: hasSameRules() broken for zones with rules");
572    }
573    if (!tz1->hasSameRules(*tz2)) {
574        errln("Fail: hasSameRules() returns false for zones without rules");
575        //errln("zone 1 = " + tz1);
576        //errln("zone 2 = " + tz2);
577    }
578
579    delete tz1;
580    delete tz2;
581    delete tza;
582    delete tzA;
583    delete tzb;
584}
585
586/**
587 * @bug 4154542
588 * SimpleTimeZOne constructors, setStartRule(), and setEndRule() don't
589 * check for out-of-range arguments.
590 */
591void TimeZoneRegressionTest:: Test4154542()
592{
593    const int32_t GOOD = 1;
594    const int32_t BAD  = 0;
595
596    const int32_t GOOD_MONTH       = UCAL_JANUARY;
597    const int32_t GOOD_DAY         = 1;
598    const int32_t GOOD_DAY_OF_WEEK = UCAL_SUNDAY;
599    const int32_t GOOD_TIME        = 0;
600
601    int32_t DATA [] = {
602        GOOD, INT32_MIN,    0,  INT32_MAX,   INT32_MIN,
603        GOOD, UCAL_JANUARY,    -5,  UCAL_SUNDAY,     0,
604        GOOD, UCAL_DECEMBER,    5,  UCAL_SATURDAY,   24*60*60*1000,
605        BAD,  UCAL_DECEMBER,    5,  UCAL_SATURDAY,   24*60*60*1000+1,
606        BAD,  UCAL_DECEMBER,    5,  UCAL_SATURDAY,  -1,
607        BAD,  UCAL_JANUARY,    -6,  UCAL_SUNDAY,     0,
608        BAD,  UCAL_DECEMBER,    6,  UCAL_SATURDAY,   24*60*60*1000,
609        GOOD, UCAL_DECEMBER,    1,  0,                   0,
610        GOOD, UCAL_DECEMBER,   31,  0,                   0,
611        BAD,  UCAL_APRIL,      31,  0,                   0,
612        BAD,  UCAL_DECEMBER,   32,  0,                   0,
613        BAD,  UCAL_JANUARY-1,   1,  UCAL_SUNDAY,     0,
614        BAD,  UCAL_DECEMBER+1,  1,  UCAL_SUNDAY,     0,
615        GOOD, UCAL_DECEMBER,   31, -UCAL_SUNDAY,     0,
616        GOOD, UCAL_DECEMBER,   31, -UCAL_SATURDAY,   0,
617        BAD,  UCAL_DECEMBER,   32, -UCAL_SATURDAY,   0,
618        BAD,  UCAL_DECEMBER,  -32, -UCAL_SATURDAY,   0,
619        BAD,  UCAL_DECEMBER,   31, -UCAL_SATURDAY-1, 0,
620    };
621    SimpleTimeZone *zone = new SimpleTimeZone(0, "Z");
622    for (int32_t i=0; i < 18*5; i+=5) {
623        UBool shouldBeGood = (DATA[i] == GOOD);
624        int32_t month     = DATA[i+1];
625        int32_t day       = DATA[i+2];
626        int32_t dayOfWeek = DATA[i+3];
627        int32_t time      = DATA[i+4];
628
629        UErrorCode status = U_ZERO_ERROR;
630
631        //Exception ex = null;
632        //try {
633            zone->setStartRule(month, day, dayOfWeek, time, status);
634        //} catch (IllegalArgumentException e) {
635        //    ex = e;
636        //}
637        if (U_SUCCESS(status) != shouldBeGood) {
638            errln(UnicodeString("setStartRule(month=") + month + ", day=" + day +
639                  ", dayOfWeek=" + dayOfWeek + ", time=" + time +
640                  (shouldBeGood ? (") should work")
641                   : ") should fail but doesn't"));
642        }
643
644        //ex = null;
645        //try {
646        status = U_ZERO_ERROR;
647            zone->setEndRule(month, day, dayOfWeek, time, status);
648        //} catch (IllegalArgumentException e) {
649        //   ex = e;
650        //}
651        if (U_SUCCESS(status) != shouldBeGood) {
652            errln(UnicodeString("setEndRule(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        // {sfb} need to look into ctor problems! (UErrorCode vs. dst signature confusion)
661        status = U_ZERO_ERROR;
662            SimpleTimeZone *temp = new SimpleTimeZone(0, "Z",
663                    (int8_t)month, (int8_t)day, (int8_t)dayOfWeek, time,
664                    (int8_t)GOOD_MONTH, (int8_t)GOOD_DAY, (int8_t)GOOD_DAY_OF_WEEK,
665                    GOOD_TIME,status);
666        //} catch (IllegalArgumentException e) {
667        //    ex = e;
668        //}
669        if (U_SUCCESS(status) != shouldBeGood) {
670            errln(UnicodeString("SimpleTimeZone(month=") + month + ", day=" + day +
671                  ", dayOfWeek=" + dayOfWeek + ", time=" + time +
672                  (shouldBeGood ? (", <end>) should work")// + ex)
673                   : ", <end>) should fail but doesn't"));
674        }
675
676        delete temp;
677        //ex = null;
678        //try {
679        status = U_ZERO_ERROR;
680            temp = new SimpleTimeZone(0, "Z",
681                    (int8_t)GOOD_MONTH, (int8_t)GOOD_DAY, (int8_t)GOOD_DAY_OF_WEEK,
682                    GOOD_TIME,
683                    (int8_t)month, (int8_t)day, (int8_t)dayOfWeek, time,status);
684        //} catch (IllegalArgumentException e) {
685        //    ex = e;
686        //}
687        if (U_SUCCESS(status) != shouldBeGood) {
688            errln(UnicodeString("SimpleTimeZone(<start>, month=") + month + ", day=" + day +
689                  ", dayOfWeek=" + dayOfWeek + ", time=" + time +
690                  (shouldBeGood ? (") should work")// + ex)
691                   : ") should fail but doesn't"));
692        }
693        delete temp;
694    }
695    delete zone;
696}
697
698
699/**
700 * @bug 4154525
701 * SimpleTimeZone accepts illegal DST savings values.  These values
702 * must be non-zero.  There is no upper limit at this time.
703 */
704void
705TimeZoneRegressionTest::Test4154525()
706{
707    const int32_t GOOD = 1, BAD = 0;
708
709    int32_t DATA [] = {
710        1, GOOD,
711        0, BAD,
712        -1, BAD,
713        60*60*1000, GOOD,
714        INT32_MIN, BAD,
715        // Integer.MAX_VALUE, ?, // no upper limit on DST savings at this time
716    };
717
718    UErrorCode status = U_ZERO_ERROR;
719    for(int32_t i = 0; i < 10; i+=2) {
720        int32_t savings = DATA[i];
721        UBool valid = DATA[i+1] == GOOD;
722        UnicodeString method;
723        for(int32_t j=0; j < 2; ++j) {
724            SimpleTimeZone *z=NULL;
725            switch (j) {
726                case 0:
727                    method = "constructor";
728                    z = new SimpleTimeZone(0, "id",
729                        UCAL_JANUARY, 1, 0, 0,
730                        UCAL_MARCH, 1, 0, 0,
731                        savings, status); // <- what we're interested in
732                    break;
733                case 1:
734                    method = "setDSTSavings()";
735                    z = new SimpleTimeZone(0, "GMT");
736                    z->setDSTSavings(savings, status);
737                    break;
738            }
739
740            if(U_FAILURE(status)) {
741                if(valid) {
742                    errln(UnicodeString("Fail: DST savings of ") + savings + " to " + method + " gave " + u_errorName(status));
743                }
744                else {
745                    logln(UnicodeString("Pass: DST savings of ") + savings + " to " + method + " gave " + u_errorName(status));
746                }
747            }
748            else {
749                if(valid) {
750                    logln(UnicodeString("Pass: DST savings of ") + savings + " accepted by " + method);
751                }
752                else {
753                    errln(UnicodeString("Fail: DST savings of ") + savings + " accepted by " + method);
754                }
755            }
756            status = U_ZERO_ERROR;
757            delete z;
758        }
759    }
760}
761
762/**
763 * @bug 4154650
764 * SimpleTimeZone.getOffset accepts illegal arguments.
765 */
766void
767TimeZoneRegressionTest::Test4154650()
768{
769    const int32_t GOOD = 1, BAD = 0;
770    const int32_t GOOD_ERA = GregorianCalendar::AD, GOOD_YEAR = 1998, GOOD_MONTH = UCAL_AUGUST;
771    const int32_t GOOD_DAY = 2, GOOD_DOW = UCAL_SUNDAY, GOOD_TIME = 16*3600000;
772
773    int32_t DATA []= {
774        GOOD, GOOD_ERA, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, GOOD_DOW, GOOD_TIME,
775
776        GOOD, GregorianCalendar::BC, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, GOOD_DOW, GOOD_TIME,
777        GOOD, GregorianCalendar::AD, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, GOOD_DOW, GOOD_TIME,
778        BAD,  GregorianCalendar::BC-1, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, GOOD_DOW, GOOD_TIME,
779        BAD,  GregorianCalendar::AD+1, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, GOOD_DOW, GOOD_TIME,
780
781        GOOD, GOOD_ERA, GOOD_YEAR, UCAL_JANUARY, GOOD_DAY, GOOD_DOW, GOOD_TIME,
782        GOOD, GOOD_ERA, GOOD_YEAR, UCAL_DECEMBER, GOOD_DAY, GOOD_DOW, GOOD_TIME,
783        BAD,  GOOD_ERA, GOOD_YEAR, UCAL_JANUARY-1, GOOD_DAY, GOOD_DOW, GOOD_TIME,
784        BAD,  GOOD_ERA, GOOD_YEAR, UCAL_DECEMBER+1, GOOD_DAY, GOOD_DOW, GOOD_TIME,
785
786        GOOD, GOOD_ERA, GOOD_YEAR, UCAL_JANUARY, 1, GOOD_DOW, GOOD_TIME,
787        GOOD, GOOD_ERA, GOOD_YEAR, UCAL_JANUARY, 31, GOOD_DOW, GOOD_TIME,
788        BAD,  GOOD_ERA, GOOD_YEAR, UCAL_JANUARY, 0, GOOD_DOW, GOOD_TIME,
789        BAD,  GOOD_ERA, GOOD_YEAR, UCAL_JANUARY, 32, GOOD_DOW, GOOD_TIME,
790
791        GOOD, GOOD_ERA, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, UCAL_SUNDAY, GOOD_TIME,
792        GOOD, GOOD_ERA, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, UCAL_SATURDAY, GOOD_TIME,
793        BAD,  GOOD_ERA, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, UCAL_SUNDAY-1, GOOD_TIME,
794        BAD,  GOOD_ERA, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, UCAL_SATURDAY+1, GOOD_TIME,
795
796        GOOD, GOOD_ERA, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, GOOD_DOW, 0,
797        GOOD, GOOD_ERA, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, GOOD_DOW, 24*3600000-1,
798        BAD,  GOOD_ERA, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, GOOD_DOW, -1,
799        BAD,  GOOD_ERA, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, GOOD_DOW, 24*3600000,
800    };
801
802    int32_t dataLen = (int32_t)(sizeof(DATA) / sizeof(DATA[0]));
803
804    UErrorCode status = U_ZERO_ERROR;
805    TimeZone *tz = TimeZone::createDefault();
806    for(int32_t i = 0; i < dataLen; i += 7) {
807        UBool good = DATA[i] == GOOD;
808        //IllegalArgumentException e = null;
809        //try {
810            /*int32_t offset = */
811        tz->getOffset((uint8_t)DATA[i+1], DATA[i+2], DATA[i+3],
812                      DATA[i+4], (uint8_t)DATA[i+5], DATA[i+6], status);
813        //} catch (IllegalArgumentException ex) {
814        //   e = ex;
815        //}
816        if(good != U_SUCCESS(status)) {
817            UnicodeString errMsg;
818            if (good) {
819                errMsg = (UnicodeString(") threw ") + u_errorName(status));
820            }
821            else {
822                errMsg = UnicodeString(") accepts invalid args", "");
823            }
824            errln(UnicodeString("Fail: getOffset(") +
825                  DATA[i+1] + ", " + DATA[i+2] + ", " + DATA[i+3] + ", " +
826                  DATA[i+4] + ", " + DATA[i+5] + ", " + DATA[i+6] +
827                  errMsg);
828        }
829        status = U_ZERO_ERROR; // reset
830    }
831    delete tz;
832}
833
834/**
835 * @bug 4162593
836 * TimeZone broken at midnight.  The TimeZone code fails to handle
837 * transitions at midnight correctly.
838 */
839void
840TimeZoneRegressionTest::Test4162593()
841{
842    UErrorCode status = U_ZERO_ERROR;
843    SimpleDateFormat *fmt = new SimpleDateFormat("z", Locale::getUS(), status);
844    if(U_FAILURE(status)) {
845      dataerrln("Error creating calendar %s", u_errorName(status));
846      delete fmt;
847      return;
848    }
849    const int32_t ONE_HOUR = 60*60*1000;
850
851    SimpleTimeZone *asuncion = new SimpleTimeZone(-4*ONE_HOUR, "America/Asuncion" /*PY%sT*/,
852        UCAL_OCTOBER, 1, 0 /*DOM*/, 0*ONE_HOUR,
853        UCAL_MARCH, 1, 0 /*DOM*/, 0*ONE_HOUR, 1*ONE_HOUR, status);
854
855    /* Zone
856     * Starting time
857     * Transition expected between start+1H and start+2H
858     */
859    TimeZone *DATA_TZ [] = {
860      0, 0, 0 };
861
862    int32_t DATA_INT [] [5] = {
863        // These years must be AFTER the Gregorian cutover
864        {1998, UCAL_SEPTEMBER, 30, 22, 0},
865        {2000, UCAL_FEBRUARY, 28, 22, 0},
866        {2000, UCAL_FEBRUARY, 29, 22, 0},
867     };
868
869    UBool DATA_BOOL [] = {
870        TRUE,
871        FALSE,
872        TRUE,
873    };
874
875    UnicodeString zone [4];// = new String[4];
876    DATA_TZ[0] =
877        new SimpleTimeZone(2*ONE_HOUR, "Asia/Damascus" /*EE%sT*/,
878            UCAL_APRIL, 1, 0 /*DOM*/, 0*ONE_HOUR,
879            UCAL_OCTOBER, 1, 0 /*DOM*/, 0*ONE_HOUR, 1*ONE_HOUR, status);
880    DATA_TZ[1] = asuncion;  DATA_TZ[2] = asuncion;
881
882    for(int32_t j = 0; j < 3; j++) {
883        TimeZone *tz = (TimeZone*)DATA_TZ[j];
884        TimeZone::setDefault(*tz);
885        fmt->setTimeZone(*tz);
886
887        // Must construct the Date object AFTER setting the default zone
888        int32_t *p = (int32_t*)DATA_INT[j];
889        UDate d = CalendarRegressionTest::makeDate(p[0], p[1], p[2], p[3], p[4]);
890       UBool transitionExpected = DATA_BOOL[j];
891
892        UnicodeString temp;
893        logln(tz->getID(temp) + ":");
894        for (int32_t i = 0; i < 4; ++i) {
895            FieldPosition pos(0);
896            zone[i].remove();
897            zone[i] = fmt->format(d+ i*ONE_HOUR, zone[i], pos);
898            logln(UnicodeString("") + i + ": " + d + " / " + zone[i]);
899            //d += (double) ONE_HOUR;
900        }
901        if(zone[0] == zone[1] &&
902            (zone[1] == zone[2]) != transitionExpected &&
903            zone[2] == zone[3]) {
904            logln(UnicodeString("Ok: transition ") + transitionExpected);
905        }
906        else {
907            errln("Fail: boundary transition incorrect");
908        }
909    }
910    delete fmt;
911    delete asuncion;
912    delete DATA_TZ[0];
913}
914
915  /**
916    * getDisplayName doesn't work with unusual savings/offsets.
917    */
918void TimeZoneRegressionTest::Test4176686() {
919    // Construct a zone that does not observe DST but
920    // that does have a DST savings (which should be ignored).
921    UErrorCode status = U_ZERO_ERROR;
922    int32_t offset = 90 * 60000; // 1:30
923    SimpleTimeZone* z1 = new SimpleTimeZone(offset, "_std_zone_");
924    z1->setDSTSavings(45 * 60000, status); // 0:45
925
926    // Construct a zone that observes DST for the first 6 months.
927    SimpleTimeZone* z2 = new SimpleTimeZone(offset, "_dst_zone_");
928    z2->setDSTSavings(45 * 60000, status); // 0:45
929    z2->setStartRule(UCAL_JANUARY, 1, 0, status);
930    z2->setEndRule(UCAL_JULY, 1, 0, status);
931
932    // Also check DateFormat
933    DateFormat* fmt1 = new SimpleDateFormat(UnicodeString("z"), status);
934    if (U_FAILURE(status)) {
935        dataerrln("Failure trying to construct: %s", u_errorName(status));
936        return;
937    }
938    fmt1->setTimeZone(*z1); // Format uses standard zone
939    DateFormat* fmt2 = new SimpleDateFormat(UnicodeString("z"), status);
940    if(!assertSuccess("trying to construct", status))return;
941    fmt2->setTimeZone(*z2); // Format uses DST zone
942    Calendar* tempcal = Calendar::createInstance(status);
943    tempcal->clear();
944    tempcal->set(1970, UCAL_FEBRUARY, 1);
945    UDate dst = tempcal->getTime(status); // Time in DST
946    tempcal->set(1970, UCAL_AUGUST, 1);
947    UDate std = tempcal->getTime(status); // Time in standard
948
949    // Description, Result, Expected Result
950    UnicodeString a,b,c,d,e,f,g,h,i,j,k,l;
951    UnicodeString DATA[] = {
952        "z1->getDisplayName(false, SHORT)/std zone",
953        z1->getDisplayName(FALSE, TimeZone::SHORT, a), "GMT+1:30",
954        "z1->getDisplayName(false, LONG)/std zone",
955        z1->getDisplayName(FALSE, TimeZone::LONG, b), "GMT+01:30",
956        "z1->getDisplayName(true, SHORT)/std zone",
957        z1->getDisplayName(TRUE, TimeZone::SHORT, c), "GMT+1:30",
958        "z1->getDisplayName(true, LONG)/std zone",
959        z1->getDisplayName(TRUE, TimeZone::LONG, d ), "GMT+01:30",
960        "z2->getDisplayName(false, SHORT)/dst zone",
961        z2->getDisplayName(FALSE, TimeZone::SHORT, e), "GMT+1:30",
962        "z2->getDisplayName(false, LONG)/dst zone",
963        z2->getDisplayName(FALSE, TimeZone::LONG, f ), "GMT+01:30",
964        "z2->getDisplayName(true, SHORT)/dst zone",
965        z2->getDisplayName(TRUE, TimeZone::SHORT, g), "GMT+2:15",
966        "z2->getDisplayName(true, LONG)/dst zone",
967        z2->getDisplayName(TRUE, TimeZone::LONG, h ), "GMT+02:15",
968        "DateFormat.format(std)/std zone", fmt1->format(std, i), "GMT+1:30",
969        "DateFormat.format(dst)/std zone", fmt1->format(dst, j), "GMT+1:30",
970        "DateFormat.format(std)/dst zone", fmt2->format(std, k), "GMT+1:30",
971        "DateFormat.format(dst)/dst zone", fmt2->format(dst, l), "GMT+2:15",
972    };
973
974    for (int32_t idx=0; idx<(int32_t)ARRAY_LENGTH(DATA); idx+=3) {
975        if (DATA[idx+1]!=(DATA[idx+2])) {
976            errln("FAIL: " + DATA[idx] + " -> " + DATA[idx+1] + ", exp " + DATA[idx+2]);
977        }
978    }
979    delete z1;
980    delete z2;
981    delete fmt1;
982    delete fmt2;
983    delete tempcal;
984}
985
986/**
987 * Make sure setStartRule and setEndRule set the DST savings to nonzero
988 * if it was zero.
989 */
990void TimeZoneRegressionTest::TestJ186() {
991    UErrorCode status = U_ZERO_ERROR;
992    // NOTE: Setting the DST savings to zero is illegal, so we
993    // are limited in the testing we can do here.  This is why
994    // lines marked //~ are commented out.
995    SimpleTimeZone z(0, "ID");
996    //~z.setDSTSavings(0, status); // Must do this!
997    z.setStartRule(UCAL_FEBRUARY, 1, UCAL_SUNDAY, 0, status);
998    failure(status, "setStartRule()");
999    if (z.useDaylightTime()) {
1000        errln("Fail: useDaylightTime true with start rule only");
1001    }
1002    //~if (z.getDSTSavings() != 0) {
1003    //~    errln("Fail: dst savings != 0 with start rule only");
1004    //~}
1005    z.setEndRule(UCAL_MARCH, -1, UCAL_SUNDAY, 0, status);
1006    failure(status, "setStartRule()");
1007    if (!z.useDaylightTime()) {
1008        errln("Fail: useDaylightTime false with rules set");
1009    }
1010    if (z.getDSTSavings() == 0) {
1011        errln("Fail: dst savings == 0 with rules set");
1012    }
1013}
1014
1015/**
1016 * Test to see if DateFormat understands zone equivalency groups.  It
1017 * might seem that this should be a DateFormat test, but it's really a
1018 * TimeZone test -- the changes to DateFormat are minor.
1019 *
1020 * We use two known, stable zones that shouldn't change much over time
1021 * -- America/Vancouver and America/Los_Angeles.  However, they MAY
1022 * change at some point -- if that happens, replace them with any two
1023 * zones in an equivalency group where one zone has localized name
1024 * data, and the other doesn't, in some locale.
1025 */
1026void TimeZoneRegressionTest::TestJ449() {
1027    UErrorCode status = U_ZERO_ERROR;
1028    UnicodeString str;
1029
1030    // Modify the following three as necessary.  The two IDs must
1031    // specify two zones in the same equivalency group.  One must have
1032    // locale data in 'loc'; the other must not.
1033    const char* idWithLocaleData = "America/Los_Angeles";
1034    const char* idWithoutLocaleData = "US/Pacific";
1035    const Locale loc("en", "", "");
1036
1037    TimeZone *zoneWith = TimeZone::createTimeZone(idWithLocaleData);
1038    TimeZone *zoneWithout = TimeZone::createTimeZone(idWithoutLocaleData);
1039    // Make sure we got valid zones
1040    if (zoneWith->getID(str) != UnicodeString(idWithLocaleData) ||
1041        zoneWithout->getID(str) != UnicodeString(idWithoutLocaleData)) {
1042      dataerrln(UnicodeString("Fail: Unable to create zones - wanted ") + idWithLocaleData + ", got " + zoneWith->getID(str) + ", and wanted " + idWithoutLocaleData + " but got " + zoneWithout->getID(str));
1043    } else {
1044        GregorianCalendar calWith(*zoneWith, status);
1045        GregorianCalendar calWithout(*zoneWithout, status);
1046        SimpleDateFormat fmt("MMM d yyyy hh:mm a zzz", loc, status);
1047        if (U_FAILURE(status)) {
1048            errln("Fail: Unable to create GregorianCalendar/SimpleDateFormat");
1049        } else {
1050            UDate date = 0;
1051            UnicodeString strWith, strWithout;
1052            fmt.setCalendar(calWith);
1053            fmt.format(date, strWith);
1054            fmt.setCalendar(calWithout);
1055            fmt.format(date, strWithout);
1056            if (strWith == strWithout) {
1057                logln((UnicodeString)"Ok: " + idWithLocaleData + " -> " +
1058                      strWith + "; " + idWithoutLocaleData + " -> " +
1059                      strWithout);
1060            } else {
1061                errln((UnicodeString)"FAIL: " + idWithLocaleData + " -> " +
1062                      strWith + "; " + idWithoutLocaleData + " -> " +
1063                      strWithout);
1064            }
1065        }
1066    }
1067
1068    delete zoneWith;
1069    delete zoneWithout;
1070}
1071
1072// test new API for JDK 1.2 8/31 putback
1073void
1074TimeZoneRegressionTest::TestJDK12API()
1075{
1076    // TimeZone *pst = TimeZone::createTimeZone("PST");
1077    // TimeZone *cst1 = TimeZone::createTimeZone("CST");
1078    UErrorCode ec = U_ZERO_ERROR;
1079    //d,-28800,3,1,-1,120,w,9,-1,1,120,w,60
1080    TimeZone *pst = new SimpleTimeZone(-28800*U_MILLIS_PER_SECOND,
1081                                       "PST",
1082                                       3,1,-1,120*U_MILLIS_PER_MINUTE,
1083                                       SimpleTimeZone::WALL_TIME,
1084                                       9,-1,1,120*U_MILLIS_PER_MINUTE,
1085                                       SimpleTimeZone::WALL_TIME,
1086                                       60*U_MILLIS_PER_MINUTE,ec);
1087    //d,-21600,3,1,-1,120,w,9,-1,1,120,w,60
1088    TimeZone *cst1 = new SimpleTimeZone(-21600*U_MILLIS_PER_SECOND,
1089                                       "CST",
1090                                       3,1,-1,120*U_MILLIS_PER_MINUTE,
1091                                       SimpleTimeZone::WALL_TIME,
1092                                       9,-1,1,120*U_MILLIS_PER_MINUTE,
1093                                       SimpleTimeZone::WALL_TIME,
1094                                       60*U_MILLIS_PER_MINUTE,ec);
1095    if (U_FAILURE(ec)) {
1096        errln("FAIL: SimpleTimeZone constructor");
1097        return;
1098    }
1099
1100    SimpleTimeZone *cst = dynamic_cast<SimpleTimeZone *>(cst1);
1101
1102    if(pst->hasSameRules(*cst)) {
1103        errln("FAILURE: PST and CST have same rules");
1104    }
1105
1106    UErrorCode status = U_ZERO_ERROR;
1107    int32_t offset1 = pst->getOffset(1,
1108        1997, UCAL_OCTOBER, 26, UCAL_SUNDAY, (2*60*60*1000), status);
1109    failure(status, "getOffset() failed");
1110
1111
1112    int32_t offset2 = cst->getOffset(1,
1113        1997, UCAL_OCTOBER, 26, UCAL_SUNDAY, (2*60*60*1000), 31, status);
1114    failure(status, "getOffset() failed");
1115
1116    if(offset1 == offset2)
1117        errln("FAILURE: Sunday Oct. 26 1997 2:00 has same offset for PST and CST");
1118
1119    // verify error checking
1120    pst->getOffset(1,
1121        1997, UCAL_FIELD_COUNT+1, 26, UCAL_SUNDAY, (2*60*60*1000), status);
1122    if(U_SUCCESS(status))
1123        errln("FAILURE: getOffset() succeeded with -1 for month");
1124
1125    status = U_ZERO_ERROR;
1126    cst->setDSTSavings(60*60*1000, status);
1127    failure(status, "setDSTSavings() failed");
1128
1129    int32_t savings = cst->getDSTSavings();
1130    if(savings != 60*60*1000) {
1131        errln("setDSTSavings() failed");
1132    }
1133
1134    delete pst;
1135    delete cst;
1136}
1137/**
1138 * SimpleTimeZone allows invalid DOM values.
1139 */
1140void TimeZoneRegressionTest::Test4184229() {
1141    SimpleTimeZone* zone = NULL;
1142    UErrorCode status = U_ZERO_ERROR;
1143    zone = new SimpleTimeZone(0, "A", 0, -1, 0, 0, 0, 0, 0, 0, status);
1144    if(U_SUCCESS(status)){
1145        errln("Failed. No exception has been thrown for DOM -1 startDay");
1146    }else{
1147       logln("(a) " + UnicodeString( u_errorName(status)));
1148    }
1149    status = U_ZERO_ERROR;
1150    delete zone;
1151
1152    zone = new SimpleTimeZone(0, "A", 0, 0, 0, 0, 0, -1, 0, 0, status);
1153    if(U_SUCCESS(status)){
1154        errln("Failed. No exception has been thrown for DOM -1 endDay");
1155    }else{
1156       logln("(b) " + UnicodeString(u_errorName(status)));
1157    }
1158    status = U_ZERO_ERROR;
1159    delete zone;
1160
1161    zone = new SimpleTimeZone(0, "A", 0, -1, 0, 0, 0, 0, 0, 1000, status);
1162    if(U_SUCCESS(status)){
1163        errln("Failed. No exception has been thrown for DOM -1 startDay+savings");
1164    }else{
1165       logln("(c) " + UnicodeString(u_errorName(status)));
1166    }
1167    status = U_ZERO_ERROR;
1168    delete zone;
1169    zone = new SimpleTimeZone(0, "A", 0, 0, 0, 0, 0, -1, 0, 0, 1000, status);
1170    if(U_SUCCESS(status)){
1171        errln("Failed. No exception has been thrown for DOM -1 endDay+ savings");
1172    }else{
1173       logln("(d) " + UnicodeString(u_errorName(status)));
1174    }
1175    status = U_ZERO_ERROR;
1176    delete zone;
1177    // Make a valid constructor call for subsequent tests.
1178    zone = new SimpleTimeZone(0, "A", 0, 1, 0, 0, 0, 1, 0, 0, status);
1179
1180    zone->setStartRule(0, -1, 0, 0, status);
1181    if(U_SUCCESS(status)){
1182        errln("Failed. No exception has been thrown for DOM -1 setStartRule +savings");
1183    } else{
1184        logln("(e) " + UnicodeString(u_errorName(status)));
1185    }
1186    zone->setStartRule(0, -1, 0, status);
1187    if(U_SUCCESS(status)){
1188        errln("Failed. No exception has been thrown for DOM -1 setStartRule");
1189    } else{
1190        logln("(f) " + UnicodeString(u_errorName(status)));
1191    }
1192
1193    zone->setEndRule(0, -1, 0, 0, status);
1194    if(U_SUCCESS(status)){
1195        errln("Failed. No exception has been thrown for DOM -1 setEndRule+savings");
1196    } else{
1197        logln("(g) " + UnicodeString(u_errorName(status)));
1198    }
1199
1200    zone->setEndRule(0, -1, 0, status);
1201    if(U_SUCCESS(status)){
1202        errln("Failed. No exception has been thrown for DOM -1 setEndRule");
1203    } else{
1204        logln("(h) " + UnicodeString(u_errorName(status)));
1205    }
1206    delete zone;
1207}
1208
1209#endif /* #if !UCONFIG_NO_FORMATTING */
1210