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