1/*
2 * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23
24/*
25 * @test
26 * @bug 4031502 4035301 4040996 4051765 4059654 4061476 4070502 4071197 4071385
27 * 4073929 4083167 4086724 4092362 4095407 4096231 4096539 4100311 4103271
28 * 4106136 4108764 4114578 4118384 4125881 4125892 4136399 4141665 4142933
29 * 4145158 4145983 4147269 4149677 4162587 4165343 4166109 4167060 4173516
30 * 4174361 4177484 4197699 4209071 4288792 4328747 4413980 4546637 4623997
31 * 4685354 4655637 4683492 4080631 4080631 4167995 4340146 4639407
32 * 4652815 4652830 4740554 4936355 4738710 4633646 4846659 4822110 4960642
33 * 4973919 4980088 4965624 5013094 5006864 8152077
34 * @library /java/text/testlib
35 * @run main CalendarRegression
36 */
37import java.io.ByteArrayInputStream;
38import java.io.ByteArrayOutputStream;
39import java.io.IOException;
40import java.io.ObjectInputStream;
41import java.io.ObjectOutputStream;
42import java.text.DateFormat;
43import java.text.NumberFormat;
44import java.text.SimpleDateFormat;
45import java.util.Calendar;
46import java.util.Date;
47import java.util.GregorianCalendar;
48import java.util.HashMap;
49import java.util.Locale;
50import java.util.Map;
51import java.util.SimpleTimeZone;
52import java.util.TimeZone;
53
54import static java.util.Calendar.*;
55
56public class CalendarRegression extends IntlTest {
57
58    public static void main(String[] args) throws Exception {
59        new CalendarRegression().run(args);
60    }
61
62    /*
63    Synopsis: java.sql.Timestamp constructor works wrong on Windows 95
64
65    ==== Here is the test ====
66    public static void main (String args[]) {
67    java.sql.Timestamp t= new java.sql.Timestamp(0,15,5,5,8,13,123456700);
68    logln("expected=1901-04-05 05:08:13.1234567");
69    logln(" result="+t);
70    }
71
72    ==== Here is the output of the test on Solaris or NT ====
73    expected=1901-04-05 05:08:13.1234567
74    result=1901-04-05 05:08:13.1234567
75
76    ==== Here is the output of the test on Windows95 ====
77    expected=1901-04-05 05:08:13.1234567
78    result=1901-04-05 06:08:13.1234567
79     */
80    public void Test4031502() {
81        // This bug actually occurs on Windows NT as well, and doesn't
82        // require the host zone to be set; it can be set in Java.
83        String[] ids = TimeZone.getAvailableIDs();
84        boolean bad = false;
85        for (int i = 0; i < ids.length; ++i) {
86            TimeZone zone = TimeZone.getTimeZone(ids[i]);
87            GregorianCalendar cal = new GregorianCalendar(zone);
88            cal.clear();
89            cal.set(1900, 15, 5, 5, 8, 13);
90            if (cal.get(HOUR) != 5) {
91                logln(zone.getID() + " "
92                        + //zone.useDaylightTime() + " "
93                        + cal.get(DST_OFFSET) / (60 * 60 * 1000) + " "
94                        + zone.getRawOffset() / (60 * 60 * 1000)
95                        + ": HOUR = " + cal.get(HOUR));
96                bad = true;
97            }
98        }
99        if (bad) {
100            errln("TimeZone problems with GC");
101        }
102    }
103
104    public void Test4035301() {
105        GregorianCalendar c = new GregorianCalendar(98, 8, 7);
106        GregorianCalendar d = new GregorianCalendar(98, 8, 7);
107        if (c.after(d)
108                || c.after(c)
109                || c.before(d)
110                || c.before(c)
111                || !c.equals(c)
112                || !c.equals(d)) {
113            errln("Fail");
114        }
115    }
116
117    public void Test4040996() {
118        String[] ids = TimeZone.getAvailableIDs(-8 * 60 * 60 * 1000);
119        SimpleTimeZone pdt = new SimpleTimeZone(-8 * 60 * 60 * 1000, ids[0]);
120        pdt.setStartRule(APRIL, 1, SUNDAY, 2 * 60 * 60 * 1000);
121        pdt.setEndRule(OCTOBER, -1, SUNDAY, 2 * 60 * 60 * 1000);
122        Calendar calendar = new GregorianCalendar(pdt);
123
124        calendar.set(MONTH, 3);
125        calendar.set(DAY_OF_MONTH, 18);
126        calendar.set(SECOND, 30);
127
128        logln("MONTH: " + calendar.get(MONTH));
129        logln("DAY_OF_MONTH: "
130                + calendar.get(DAY_OF_MONTH));
131        logln("MINUTE: " + calendar.get(MINUTE));
132        logln("SECOND: " + calendar.get(SECOND));
133
134        calendar.add(SECOND, 6);
135        //This will print out todays date for MONTH and DAY_OF_MONTH
136        //instead of the date it was set to.
137        //This happens when adding MILLISECOND or MINUTE also
138        logln("MONTH: " + calendar.get(MONTH));
139        logln("DAY_OF_MONTH: "
140                + calendar.get(DAY_OF_MONTH));
141        logln("MINUTE: " + calendar.get(MINUTE));
142        logln("SECOND: " + calendar.get(SECOND));
143        if (calendar.get(MONTH) != 3
144                || calendar.get(DAY_OF_MONTH) != 18
145                || calendar.get(SECOND) != 36) {
146            errln("Fail: Calendar.add misbehaves");
147        }
148    }
149
150    public void Test4051765() {
151        Calendar cal = Calendar.getInstance();
152        cal.setLenient(false);
153        cal.set(DAY_OF_WEEK, 0);
154        try {
155            cal.getTime();
156            errln("Fail: DAY_OF_WEEK 0 should be disallowed");
157        } catch (IllegalArgumentException e) {
158            return;
159        }
160    }
161
162    /* User error - no bug here
163    public void Test4059524() {
164        // Create calendar for April 10, 1997
165        GregorianCalendar calendar  = new GregorianCalendar();
166        // print out a bunch of interesting things
167        logln("ERA: " + calendar.get(calendar.ERA));
168        logln("YEAR: " + calendar.get(calendar.YEAR));
169        logln("MONTH: " + calendar.get(calendar.MONTH));
170        logln("WEEK_OF_YEAR: " +
171                           calendar.get(calendar.WEEK_OF_YEAR));
172        logln("WEEK_OF_MONTH: " +
173                           calendar.get(calendar.WEEK_OF_MONTH));
174        logln("DATE: " + calendar.get(calendar.DATE));
175        logln("DAY_OF_MONTH: " +
176                           calendar.get(calendar.DAY_OF_MONTH));
177        logln("DAY_OF_YEAR: " + calendar.get(calendar.DAY_OF_YEAR));
178        logln("DAY_OF_WEEK: " + calendar.get(calendar.DAY_OF_WEEK));
179        logln("DAY_OF_WEEK_IN_MONTH: " +
180                           calendar.get(calendar.DAY_OF_WEEK_IN_MONTH));
181        logln("AM_PM: " + calendar.get(calendar.AM_PM));
182        logln("HOUR: " + calendar.get(calendar.HOUR));
183        logln("HOUR_OF_DAY: " + calendar.get(calendar.HOUR_OF_DAY));
184        logln("MINUTE: " + calendar.get(calendar.MINUTE));
185        logln("SECOND: " + calendar.get(calendar.SECOND));
186        logln("MILLISECOND: " + calendar.get(calendar.MILLISECOND));
187        logln("ZONE_OFFSET: "
188                           + (calendar.get(calendar.ZONE_OFFSET)/(60*60*1000)));
189        logln("DST_OFFSET: "
190                           + (calendar.get(calendar.DST_OFFSET)/(60*60*1000)));
191        calendar  = new GregorianCalendar(1997,3,10);
192        calendar.getTime();
193        logln("April 10, 1997");
194        logln("ERA: " + calendar.get(calendar.ERA));
195        logln("YEAR: " + calendar.get(calendar.YEAR));
196        logln("MONTH: " + calendar.get(calendar.MONTH));
197        logln("WEEK_OF_YEAR: " +
198                           calendar.get(calendar.WEEK_OF_YEAR));
199        logln("WEEK_OF_MONTH: " +
200                           calendar.get(calendar.WEEK_OF_MONTH));
201        logln("DATE: " + calendar.get(calendar.DATE));
202        logln("DAY_OF_MONTH: " +
203                           calendar.get(calendar.DAY_OF_MONTH));
204        logln("DAY_OF_YEAR: " + calendar.get(calendar.DAY_OF_YEAR));
205        logln("DAY_OF_WEEK: " + calendar.get(calendar.DAY_OF_WEEK));
206        logln("DAY_OF_WEEK_IN_MONTH: " + calendar.get(calendar.DAY_OF_WEEK_IN_MONTH));
207        logln("AM_PM: " + calendar.get(calendar.AM_PM));
208        logln("HOUR: " + calendar.get(calendar.HOUR));
209        logln("HOUR_OF_DAY: " + calendar.get(calendar.HOUR_OF_DAY));
210        logln("MINUTE: " + calendar.get(calendar.MINUTE));
211        logln("SECOND: " + calendar.get(calendar.SECOND));
212        logln("MILLISECOND: " + calendar.get(calendar.MILLISECOND));
213        logln("ZONE_OFFSET: "
214                           + (calendar.get(calendar.ZONE_OFFSET)/(60*60*1000))); // in hours
215        logln("DST_OFFSET: "
216                           + (calendar.get(calendar.DST_OFFSET)/(60*60*1000))); // in hours
217    }
218     */
219    public void Test4059654() {
220        GregorianCalendar gc = new GregorianCalendar();
221
222        gc.set(1997, 3, 1, 15, 16, 17); // April 1, 1997
223
224        gc.set(HOUR, 0);
225        gc.set(AM_PM, AM);
226        gc.set(MINUTE, 0);
227        gc.set(SECOND, 0);
228        gc.set(MILLISECOND, 0);
229
230        Date cd = gc.getTime();
231        @SuppressWarnings("deprecation")
232        Date exp = new Date(97, 3, 1, 0, 0, 0);
233        if (!cd.equals(exp)) {
234            errln("Fail: Calendar.set broken. Got " + cd + " Want " + exp);
235        }
236    }
237
238    public void Test4061476() {
239        SimpleDateFormat fmt = new SimpleDateFormat("ddMMMyy", Locale.UK);
240        Calendar cal = GregorianCalendar.getInstance(TimeZone.getTimeZone("GMT"),
241                Locale.UK);
242        fmt.setCalendar(cal);
243        try {
244            Date date = fmt.parse("29MAY97");
245            cal.setTime(date);
246        } catch (Exception e) {
247        }
248        cal.set(HOUR_OF_DAY, 13);
249        logln("Hour: " + cal.get(HOUR_OF_DAY));
250        cal.add(HOUR_OF_DAY, 6);
251        logln("Hour: " + cal.get(HOUR_OF_DAY));
252        if (cal.get(HOUR_OF_DAY) != 19) {
253            errln("Fail: Want 19 Got " + cal.get(HOUR_OF_DAY));
254        }
255    }
256
257    public void Test4070502() {
258        @SuppressWarnings("deprecation")
259        Date d = getAssociatedDate(new Date(98, 0, 30));
260        Calendar cal = new GregorianCalendar();
261        cal.setTime(d);
262        if (cal.get(DAY_OF_WEEK) == SATURDAY
263                || cal.get(DAY_OF_WEEK) == SUNDAY) {
264            errln("Fail: Want weekday Got " + d);
265        }
266    }
267
268    /**
269     * Get the associated date starting from a specified date
270     * NOTE: the unnecessary "getTime()'s" below are a work-around for a
271     * bug in jdk 1.1.3 (and probably earlier versions also)
272     * <p>
273     * @param date The date to start from
274     */
275    public static Date getAssociatedDate(Date d) {
276        GregorianCalendar cal = new GregorianCalendar();
277        cal.setTime(d);
278        //cal.add(field, amount); //<-- PROBLEM SEEN WITH field = DATE,MONTH
279        // cal.getTime();  // <--- REMOVE THIS TO SEE BUG
280        while (true) {
281            int wd = cal.get(DAY_OF_WEEK);
282            if (wd == SATURDAY || wd == SUNDAY) {
283                cal.add(DATE, 1);
284                // cal.getTime();
285            } else {
286                break;
287            }
288        }
289        return cal.getTime();
290    }
291
292    public void Test4071197() {
293        dowTest(false);
294        dowTest(true);
295    }
296
297    void dowTest(boolean lenient) {
298        GregorianCalendar cal = new GregorianCalendar();
299        cal.set(1997, AUGUST, 12); // Wednesday
300        // cal.getTime(); // Force update
301        cal.setLenient(lenient);
302        cal.set(1996, DECEMBER, 1); // Set the date to be December 1, 1996
303        int dow = cal.get(DAY_OF_WEEK);
304        int min = cal.getMinimum(DAY_OF_WEEK);
305        int max = cal.getMaximum(DAY_OF_WEEK);
306        logln(cal.getTime().toString());
307        if (min != SUNDAY || max != SATURDAY) {
308            errln("FAIL: Min/max bad");
309        }
310        if (dow < min || dow > max) {
311            errln("FAIL: Day of week " + dow + " out of range");
312        }
313        if (dow != SUNDAY) {
314            errln("FAIL: Day of week should be SUNDAY Got " + dow);
315        }
316    }
317
318    @SuppressWarnings("deprecation")
319    public void Test4071385() {
320        Calendar cal = Calendar.getInstance();
321        cal.setTime(new Date(98, JUNE, 24));
322        cal.set(MONTH, NOVEMBER); // change a field
323        logln(cal.getTime().toString());
324        if (!cal.getTime().equals(new Date(98, NOVEMBER, 24))) {
325            errln("Fail");
326        }
327    }
328
329    public void Test4073929() {
330        GregorianCalendar foo1 = new GregorianCalendar(1997, 8, 27);
331        foo1.add(DAY_OF_MONTH, +1);
332        int testyear = foo1.get(YEAR);
333        int testmonth = foo1.get(MONTH);
334        int testday = foo1.get(DAY_OF_MONTH);
335        if (testyear != 1997
336                || testmonth != 8
337                || testday != 28) {
338            errln("Fail: Calendar not initialized");
339        }
340    }
341
342    public void Test4083167() {
343        TimeZone saveZone = TimeZone.getDefault();
344        try {
345            TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
346            Date firstDate = new Date();
347            Calendar cal = new GregorianCalendar();
348            cal.setTime(firstDate);
349            long firstMillisInDay = cal.get(HOUR_OF_DAY) * 3600000L
350                    + cal.get(MINUTE) * 60000L
351                    + cal.get(SECOND) * 1000L
352                    + cal.get(MILLISECOND);
353
354            logln("Current time: " + firstDate.toString());
355
356            for (int validity = 0; validity < 30; validity++) {
357                Date lastDate = new Date(firstDate.getTime()
358                        + (long) validity * 1000 * 24 * 60 * 60);
359                cal.setTime(lastDate);
360                long millisInDay = cal.get(HOUR_OF_DAY) * 3600000L
361                        + cal.get(MINUTE) * 60000L
362                        + cal.get(SECOND) * 1000L
363                        + cal.get(MILLISECOND);
364                if (firstMillisInDay != millisInDay) {
365                    errln("Day has shifted " + lastDate);
366                }
367            }
368        } finally {
369            TimeZone.setDefault(saveZone);
370        }
371    }
372
373    public void Test4086724() {
374        SimpleDateFormat date;
375        TimeZone saveZone = TimeZone.getDefault();
376        Locale saveLocale = Locale.getDefault();
377
378        String summerTime = "British Summer Time";
379        String standardTime = "Greenwich Mean Time";
380        try {
381            Locale.setDefault(Locale.UK);
382            TimeZone.setDefault(TimeZone.getTimeZone("Europe/London"));
383            date = new SimpleDateFormat("zzzz");
384
385            Calendar cal = Calendar.getInstance();
386            cal.set(1997, SEPTEMBER, 30);
387            Date now = cal.getTime();
388            String formattedDate = date.format(now);
389            if (!formattedDate.equals(summerTime)) {
390                errln("Wrong display name \"" + formattedDate
391                        + "\" for <" + now + ">");
392            }
393            int weekOfYear = cal.get(WEEK_OF_YEAR);
394            if (weekOfYear != 40) {
395                errln("Wrong week-of-year " + weekOfYear
396                        + " for <" + now + ">");
397            }
398
399            cal.set(1996, DECEMBER, 31);
400            now = cal.getTime();
401            formattedDate = date.format(now);
402            if (!formattedDate.equals(standardTime)) {
403                errln("Wrong display name \"" + formattedDate
404                        + "\" for <" + now + ">");
405            }
406            weekOfYear = cal.get(WEEK_OF_YEAR);
407            if (weekOfYear != 1) {
408                errln("Wrong week-of-year " + weekOfYear
409                        + " for <" + now + ">");
410            }
411
412            cal.set(1997, JANUARY, 1);
413            now = cal.getTime();
414            formattedDate = date.format(now);
415            if (!formattedDate.equals(standardTime)) {
416                errln("Wrong display name \"" + formattedDate
417                        + "\" for <" + now + ">");
418            }
419            weekOfYear = cal.get(WEEK_OF_YEAR);
420            if (weekOfYear != 1) {
421                errln("Wrong week-of-year " + weekOfYear
422                        + " for <" + now + ">");
423            }
424
425            cal.set(1997, JANUARY, 8);
426            now = cal.getTime();
427            formattedDate = date.format(now);
428            if (!formattedDate.equals(standardTime)) {
429                errln("Wrong display name \"" + formattedDate
430                        + "\" for <" + now + ">");
431            }
432            weekOfYear = cal.get(WEEK_OF_YEAR);
433            if (weekOfYear != 2) {
434                errln("Wrong week-of-year " + weekOfYear
435                        + " for <" + now + ">");
436            }
437
438        } finally {
439            Locale.setDefault(saveLocale);
440            TimeZone.setDefault(saveZone);
441        }
442    }
443
444    public void Test4092362() {
445        GregorianCalendar cal1 = new GregorianCalendar(1997, 10, 11, 10, 20, 40);
446        /*cal1.set( Calendar.YEAR, 1997 );
447        cal1.set( Calendar.MONTH, 10 );
448        cal1.set( Calendar.DATE, 11 );
449        cal1.set( Calendar.HOUR, 10 );
450        cal1.set( Calendar.MINUTE, 20 );
451        cal1.set( Calendar.SECOND, 40 ); */
452
453        logln(" Cal1 = " + cal1.getTime().getTime());
454        logln(" Cal1 time in ms = " + cal1.get(MILLISECOND));
455        for (int k = 0; k < 100; k++);
456
457        GregorianCalendar cal2 = new GregorianCalendar(1997, 10, 11, 10, 20, 40);
458        /*cal2.set( Calendar.YEAR, 1997 );
459        cal2.set( Calendar.MONTH, 10 );
460        cal2.set( Calendar.DATE, 11 );
461        cal2.set( Calendar.HOUR, 10 );
462        cal2.set( Calendar.MINUTE, 20 );
463        cal2.set( Calendar.SECOND, 40 ); */
464
465        logln(" Cal2 = " + cal2.getTime().getTime());
466        logln(" Cal2 time in ms = " + cal2.get(MILLISECOND));
467        if (!cal1.equals(cal2)) {
468            errln("Fail: Milliseconds randomized");
469        }
470    }
471
472    public void Test4095407() {
473        GregorianCalendar a = new GregorianCalendar(1997, NOVEMBER, 13);
474        int dow = a.get(DAY_OF_WEEK);
475        if (dow != THURSDAY) {
476            errln("Fail: Want THURSDAY Got " + dow);
477        }
478    }
479
480    public void Test4096231() {
481        TimeZone GMT = TimeZone.getTimeZone("GMT");
482        TimeZone PST = TimeZone.getTimeZone("PST");
483        int sec = 0, min = 0, hr = 0, day = 1, month = 10, year = 1997;
484
485        Calendar cal1 = new GregorianCalendar(PST);
486        cal1.setTime(new Date(880698639000L));
487        int p;
488        logln("PST 1 is: " + (p = cal1.get(HOUR_OF_DAY)));
489        cal1.setTimeZone(GMT);
490        // Issue 1: Changing the timezone doesn't change the
491        //          represented time.
492        int h1, h2;
493        logln("GMT 1 is: " + (h1 = cal1.get(HOUR_OF_DAY)));
494        cal1.setTime(new Date(880698639000L));
495        logln("GMT 2 is: " + (h2 = cal1.get(HOUR_OF_DAY)));
496        // Note: This test had a bug in it.  It wanted h1!=h2, when
497        // what was meant was h1!=p.  Fixed this concurrent with fix
498        // to 4177484.
499        if (p == h1 || h1 != h2) {
500            errln("Fail: Hour same in different zones");
501        }
502
503        Calendar cal2 = new GregorianCalendar(GMT);
504        Calendar cal3 = new GregorianCalendar(PST);
505        cal2.set(MILLISECOND, 0);
506        cal3.set(MILLISECOND, 0);
507
508        cal2.set(cal1.get(YEAR),
509                cal1.get(MONTH),
510                cal1.get(DAY_OF_MONTH),
511                cal1.get(HOUR_OF_DAY),
512                cal1.get(MINUTE),
513                cal1.get(SECOND));
514
515        long t1, t2, t3, t4;
516        logln("RGMT 1 is: " + (t1 = cal2.getTime().getTime()));
517        cal3.set(year, month, day, hr, min, sec);
518        logln("RPST 1 is: " + (t2 = cal3.getTime().getTime()));
519        cal3.setTimeZone(GMT);
520        logln("RGMT 2 is: " + (t3 = cal3.getTime().getTime()));
521        cal3.set(cal1.get(YEAR),
522                cal1.get(MONTH),
523                cal1.get(DAY_OF_MONTH),
524                cal1.get(HOUR_OF_DAY),
525                cal1.get(MINUTE),
526                cal1.get(SECOND));
527        // Issue 2: Calendar continues to use the timezone in its
528        //          constructor for set() conversions, regardless
529        //          of calls to setTimeZone()
530        logln("RGMT 3 is: " + (t4 = cal3.getTime().getTime()));
531        if (t1 == t2
532                || t1 != t4
533                || t2 != t3) {
534            errln("Fail: Calendar zone behavior faulty");
535        }
536    }
537
538    public void Test4096539() {
539        int[] y = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
540
541        for (int x = 0; x < 12; x++) {
542            GregorianCalendar gc = new GregorianCalendar(1997, x, y[x]);
543            int m1, m2;
544            log((m1 = gc.get(MONTH) + 1) + "/"
545                    + gc.get(DATE) + "/" + gc.get(YEAR)
546                    + " + 1mo = ");
547
548            gc.add(MONTH, 1);
549            logln((m2 = gc.get(MONTH) + 1) + "/"
550                    + gc.get(DATE) + "/" + gc.get(YEAR)
551            );
552            int m = (m1 % 12) + 1;
553            if (m2 != m) {
554                errln("Fail: Want " + m + " Got " + m2);
555            }
556        }
557
558    }
559
560    public void Test4100311() {
561        Locale locale = Locale.getDefault();
562        if (!TestUtils.usesGregorianCalendar(locale)) {
563            logln("Skipping this test because locale is " + locale);
564            return;
565        }
566
567        GregorianCalendar cal = (GregorianCalendar) Calendar.getInstance();
568        cal.set(YEAR, 1997);
569        cal.set(DAY_OF_YEAR, 1);
570        Date d = cal.getTime();             // Should be Jan 1
571        logln(d.toString());
572        if (cal.get(DAY_OF_YEAR) != 1) {
573            errln("Fail: DAY_OF_YEAR not set");
574        }
575    }
576
577    public void Test4103271() {
578        Locale locale = Locale.getDefault();
579        if (!TestUtils.usesGregorianCalendar(locale)) {
580            logln("Skipping this test because locale is " + locale);
581            return;
582        }
583
584        SimpleDateFormat sdf = new SimpleDateFormat();
585        int numYears = 40, startYear = 1997, numDays = 15;
586        String output, testDesc;
587        GregorianCalendar testCal = (GregorianCalendar) Calendar.getInstance();
588        testCal.clear();
589        sdf.setCalendar(testCal);
590        sdf.applyPattern("d MMM yyyy");
591        boolean fail = false;
592        for (int firstDay = 1; firstDay <= 2; firstDay++) {
593            for (int minDays = 1; minDays <= 7; minDays++) {
594                testCal.setMinimalDaysInFirstWeek(minDays);
595                testCal.setFirstDayOfWeek(firstDay);
596                testDesc = ("Test" + String.valueOf(firstDay) + String.valueOf(minDays));
597                logln(testDesc + " => 1st day of week="
598                        + String.valueOf(firstDay)
599                        + ", minimum days in first week="
600                        + String.valueOf(minDays));
601                for (int j = startYear; j <= startYear + numYears; j++) {
602                    testCal.set(j, 11, 25);
603                    for (int i = 0; i < numDays; i++) {
604                        testCal.add(DATE, 1);
605                        String calWOY;
606                        int actWOY = testCal.get(WEEK_OF_YEAR);
607                        if (actWOY < 1 || actWOY > 53) {
608                            Date d = testCal.getTime();
609                            calWOY = String.valueOf(actWOY);
610                            output = testDesc + " - " + sdf.format(d) + "\t";
611                            output = output + "\t" + calWOY;
612                            logln(output);
613                            fail = true;
614                        }
615                    }
616                }
617            }
618        }
619
620        int[] DATA = {
621            3, 52, 52, 52, 52, 52, 52, 52,
622            1, 1, 1, 1, 1, 1, 1,
623            2, 2, 2, 2, 2, 2, 2,
624            4, 52, 52, 52, 52, 52, 52, 52,
625            53, 53, 53, 53, 53, 53, 53,
626            1, 1, 1, 1, 1, 1, 1};
627        testCal.setFirstDayOfWeek(SUNDAY);
628        for (int j = 0; j < DATA.length; j += 22) {
629            logln("Minimal days in first week = " + DATA[j]
630                    + "  Week starts on Sunday");
631            testCal.setMinimalDaysInFirstWeek(DATA[j]);
632            testCal.set(1997, DECEMBER, 21);
633            for (int i = 0; i < 21; ++i) {
634                int woy = testCal.get(WEEK_OF_YEAR);
635                log("\t" + testCal.getTime() + " " + woy);
636                if (woy != DATA[j + 1 + i]) {
637                    log(" ERROR");
638                    fail = true;
639                } else {
640                    logln(" OK");
641                }
642
643                // Now compute the time from the fields, and make sure we
644                // get the same answer back.  This is a round-trip test.
645                Date save = testCal.getTime();
646                testCal.clear();
647                testCal.set(YEAR, DATA[j + 1 + i] < 25 ? 1998 : 1997);
648                testCal.set(WEEK_OF_YEAR, DATA[j + 1 + i]);
649                testCal.set(DAY_OF_WEEK, (i % 7) + SUNDAY);
650                if (!testCal.getTime().equals(save)) {
651                    logln("  Parse failed: " + testCal.getTime());
652                    fail = true;
653                } else {
654                    logln("  Passed");
655                }
656
657                testCal.setTime(save);
658                testCal.add(DAY_OF_MONTH, 1);
659            }
660        }
661
662        // Test field disambiguation with a few special hard-coded cases.
663        // This shouldn't fail if the above cases aren't failing.
664        @SuppressWarnings("deprecation")
665        Object[] DISAM = {
666            1998, 1, SUNDAY,
667            new Date(97, DECEMBER, 28),
668            1998, 2, SATURDAY,
669            new Date(98, JANUARY, 10),
670            1998, 53, THURSDAY,
671            new Date(98, DECEMBER, 31),
672            1998, 53, FRIDAY,
673            new Date(99, JANUARY, 1)};
674        testCal.setMinimalDaysInFirstWeek(3);
675        testCal.setFirstDayOfWeek(SUNDAY);
676        for (int i = 0; i < DISAM.length; i += 4) {
677            int y = (Integer) DISAM[i];
678            int woy = (Integer) DISAM[i + 1];
679            int dow = (Integer) DISAM[i + 2];
680            Date exp = (Date) DISAM[i + 3];
681            testCal.clear();
682            testCal.set(YEAR, y);
683            testCal.set(WEEK_OF_YEAR, woy);
684            testCal.set(DAY_OF_WEEK, dow);
685            log(y + "-W" + woy + "-DOW" + dow);
686            if (!testCal.getTime().equals(exp)) {
687                logln("  FAILED expect: " + exp + "\n            got: " + testCal.getTime());
688                fail = true;
689            } else {
690                logln("  OK");
691            }
692        }
693
694        // Now try adding and rolling
695        Object ADD = new Object();
696        Object ROLL = new Object();
697        @SuppressWarnings("deprecation")
698        Object[] ADDROLL = {
699            ADD, 1, new Date(98, DECEMBER, 25), new Date(99, JANUARY, 1),
700            ADD, 1, new Date(97, DECEMBER, 28), new Date(98, JANUARY, 4),
701            ROLL, 1, new Date(98, DECEMBER, 27), new Date(98, JANUARY, 4),
702            ROLL, 1, new Date(99, DECEMBER, 24), new Date(99, DECEMBER, 31),
703            ROLL, 1, new Date(99, DECEMBER, 25), new Date(99, JANUARY, 9)};
704        testCal.setMinimalDaysInFirstWeek(3);
705        testCal.setFirstDayOfWeek(SUNDAY);
706        for (int i = 0; i < ADDROLL.length; i += 4) {
707            int amount = (Integer) ADDROLL[i + 1];
708            Date before = (Date) ADDROLL[i + 2];
709            Date after = (Date) ADDROLL[i + 3];
710
711            testCal.setTime(before);
712            if (ADDROLL[i] == ADD) {
713                testCal.add(WEEK_OF_YEAR, amount);
714            } else {
715                testCal.roll(WEEK_OF_YEAR, amount);
716            }
717            log((ADDROLL[i] == ADD ? "add(WOY," : "roll(WOY,")
718                    + amount + ")\t     " + before
719                    + "\n\t\t  => " + testCal.getTime());
720            if (!after.equals(testCal.getTime())) {
721                logln("\tFAIL\n\t\texp: " + after);
722                fail = true;
723            } else {
724                logln("  OK");
725            }
726
727            testCal.setTime(after);
728            if (ADDROLL[i] == ADD) {
729                testCal.add(WEEK_OF_YEAR, -amount);
730            } else {
731                testCal.roll(WEEK_OF_YEAR, -amount);
732            }
733            log((ADDROLL[i] == ADD ? "add(WOY," : "roll(WOY,")
734                    + (-amount) + ")     " + after
735                    + "\n\t\t  => " + testCal.getTime());
736            if (!before.equals(testCal.getTime())) {
737                logln("\tFAIL\n\t\texp: " + before);
738                fail = true;
739            } else {
740                logln("\tOK");
741            }
742        }
743
744        if (fail) {
745            errln("Fail: Week of year misbehaving");
746        }
747    }
748
749    public void Test4106136() {
750        Locale saveLocale = Locale.getDefault();
751        try {
752            Locale[] locales = {Locale.CHINESE, Locale.CHINA};
753            for (int i = 0; i < locales.length; ++i) {
754                Locale.setDefault(locales[i]);
755                int[] n = {
756                    getAvailableLocales().length,
757                    DateFormat.getAvailableLocales().length,
758                    NumberFormat.getAvailableLocales().length};
759                for (int j = 0; j < n.length; ++j) {
760                    if (n[j] == 0) {
761                        errln("Fail: No locales for " + locales[i]);
762                    }
763                }
764            }
765        } finally {
766            Locale.setDefault(saveLocale);
767        }
768    }
769
770    @SuppressWarnings("deprecation")
771    public void Test4108764() {
772        Date d00 = new Date(97, MARCH, 15, 12, 00, 00);
773        Date d01 = new Date(97, MARCH, 15, 12, 00, 56);
774        Date d10 = new Date(97, MARCH, 15, 12, 34, 00);
775        Date d11 = new Date(97, MARCH, 15, 12, 34, 56);
776        Date epoch = new Date(70, JANUARY, 1);
777
778        Calendar cal = Calendar.getInstance();
779        cal.setTime(d11);
780
781        cal.clear(MINUTE);
782        logln(cal.getTime().toString());
783        if (!cal.getTime().equals(d01)) {
784            errln("Fail: clear(MINUTE) broken");
785        }
786
787        cal.set(SECOND, 0);
788        logln(cal.getTime().toString());
789        if (!cal.getTime().equals(d00)) {
790            errln("Fail: set(SECOND, 0) broken");
791        }
792
793        cal.setTime(d11);
794        cal.set(SECOND, 0);
795        logln(cal.getTime().toString());
796        if (!cal.getTime().equals(d10)) {
797            errln("Fail: set(SECOND, 0) broken #2");
798        }
799
800        cal.clear(MINUTE);
801        logln(cal.getTime().toString());
802        if (!cal.getTime().equals(d00)) {
803            errln("Fail: clear(MINUTE) broken #2");
804        }
805
806        cal.clear();
807        logln(cal.getTime().toString());
808        if (!cal.getTime().equals(epoch)) {
809            errln("Fail: clear() broken Want " + epoch);
810        }
811    }
812
813    @SuppressWarnings("deprecation")
814    public void Test4114578() {
815        Locale locale = Locale.getDefault();
816        if (!TestUtils.usesGregorianCalendar(locale)) {
817            logln("Skipping this test because locale is " + locale);
818            return;
819        }
820
821        int ONE_HOUR = 60 * 60 * 1000;
822        TimeZone saveZone = TimeZone.getDefault();
823        boolean fail = false;
824        try {
825            TimeZone.setDefault(TimeZone.getTimeZone("PST"));
826            Calendar cal = Calendar.getInstance();
827            long onset = new Date(98, APRIL, 5, 1, 0).getTime() + ONE_HOUR;
828            long cease = new Date(98, OCTOBER, 25, 0, 0).getTime() + 2 * ONE_HOUR;
829
830            final int ADD = 1;
831            final int ROLL = 2;
832
833            long[] DATA = {
834                // Start            Action   Amt    Expected_change
835                onset - ONE_HOUR,   ADD,      1,     ONE_HOUR,
836                onset,              ADD,     -1,    -ONE_HOUR,
837                onset - ONE_HOUR,   ROLL,     1,     ONE_HOUR,
838                onset,              ROLL,    -1,    -ONE_HOUR,
839                cease - ONE_HOUR,   ADD,      1,     ONE_HOUR,
840                cease,              ADD,     -1,    -ONE_HOUR,
841                // roll() was changed to support wall-clock-based roll (JDK-8152077). The
842                // time value may jump 2 hours by skipping non-existent wall-clock time.
843                // Note that JDK-4114578 was a problem of add(), not roll().
844                cease - ONE_HOUR,   ROLL,     1,     ONE_HOUR * 2,
845                cease,              ROLL,    -1,    -ONE_HOUR * 2};
846
847            for (int i = 0; i < DATA.length; i += 4) {
848                Date date = new Date(DATA[i]);
849                int amt = (int) DATA[i + 2];
850                long expectedChange = DATA[i + 3];
851
852                log(date.toString());
853                cal.setTime(date);
854
855                switch ((int) DATA[i + 1]) {
856                    case ADD:
857                        log(" add (HOUR," + (amt < 0 ? "" : "+") + amt + ")= ");
858                        cal.add(HOUR, amt);
859                        break;
860                    case ROLL:
861                        log(" roll(HOUR," + (amt < 0 ? "" : "+") + amt + ")= ");
862                        cal.roll(HOUR, amt);
863                        break;
864                }
865
866                log(cal.getTime().toString());
867
868                long change = cal.getTime().getTime() - date.getTime();
869                if (change != expectedChange) {
870                    fail = true;
871                    logln(" FAIL");
872                } else {
873                    logln(" OK");
874                }
875            }
876        } finally {
877            TimeZone.setDefault(saveZone);
878        }
879
880        if (fail) {
881            errln("Fail: roll/add misbehaves around DST onset/cease");
882        }
883    }
884
885    /**
886     * Make sure maximum for HOUR field is 11, not 12.
887     */
888    public void Test4118384() {
889        Calendar cal = Calendar.getInstance();
890        if (cal.getMaximum(HOUR) != 11
891                || cal.getLeastMaximum(HOUR) != 11
892                || cal.getActualMaximum(HOUR) != 11) {
893            errln("Fail: maximum of HOUR field should be 11");
894        }
895    }
896
897    /**
898     * Check isLeapYear for BC years.
899     */
900    public void Test4125881() {
901        Locale locale = Locale.getDefault();
902        if (!TestUtils.usesGregorianCalendar(locale)) {
903            logln("Skipping this test because locale is " + locale);
904            return;
905        }
906
907        GregorianCalendar cal = (GregorianCalendar) Calendar.getInstance();
908        DateFormat fmt = new SimpleDateFormat("MMMM d, yyyy G");
909        cal.clear();
910        for (int y = -20; y <= 10; ++y) {
911            cal.set(ERA, y < 1 ? GregorianCalendar.BC : GregorianCalendar.AD);
912            cal.set(YEAR, y < 1 ? 1 - y : y);
913            logln(y + " = " + fmt.format(cal.getTime()) + " "
914                    + cal.isLeapYear(y));
915            if (cal.isLeapYear(y) != ((y + 40) % 4 == 0)) {
916                errln("Leap years broken");
917            }
918        }
919    }
920
921    /**
922     * Prove that GregorianCalendar is proleptic (it used to cut off
923     * at 45 BC, and not have leap years before then).
924     */
925    public void Test4125892() {
926        Locale locale = Locale.getDefault();
927        if (!TestUtils.usesGregorianCalendar(locale)) {
928            logln("Skipping this test because locale is " + locale);
929            return;
930        }
931
932        GregorianCalendar cal = (GregorianCalendar) Calendar.getInstance();
933        DateFormat fmt = new SimpleDateFormat("MMMM d, yyyy G");
934        cal.clear();
935        cal.set(ERA, GregorianCalendar.BC);
936        cal.set(YEAR, 81); // 81 BC is a leap year (proleptically)
937        cal.set(MONTH, FEBRUARY);
938        cal.set(DATE, 28);
939        cal.add(DATE, 1);
940        if (cal.get(DATE) != 29
941                || !cal.isLeapYear(-80)) { // -80 == 81 BC
942            errln("Calendar not proleptic");
943        }
944    }
945
946    /**
947     * Calendar and GregorianCalendar hashCode() methods need improvement.
948     * Calendar needs a good implementation that subclasses can override,
949     * and GregorianCalendar should use that implementation.
950     */
951    public void Test4136399() {
952        /* Note: This test is actually more strict than it has to be.
953        * Technically, there is no requirement that unequal objects have
954        * unequal hashes.  We only require equal objects to have equal hashes.
955        * It is desirable for unequal objects to have distributed hashes, but
956        * there is no hard requirement here.
957        *
958        * In this test we make assumptions about certain attributes of calendar
959        * objects getting represented in the hash, which need not always be the
960        * case (although it does work currently with the given test). */
961        Calendar a = Calendar.getInstance();
962        Calendar b = (Calendar) a.clone();
963        if (a.hashCode() != b.hashCode()) {
964            errln("Calendar hash code unequal for cloned objects");
965        }
966
967        b.setMinimalDaysInFirstWeek(7 - a.getMinimalDaysInFirstWeek());
968        if (a.hashCode() == b.hashCode()) {
969            errln("Calendar hash code ignores minimal days in first week");
970        }
971        b.setMinimalDaysInFirstWeek(a.getMinimalDaysInFirstWeek());
972
973        b.setFirstDayOfWeek((a.getFirstDayOfWeek() % 7) + 1); // Next day
974        if (a.hashCode() == b.hashCode()) {
975            errln("Calendar hash code ignores first day of week");
976        }
977        b.setFirstDayOfWeek(a.getFirstDayOfWeek());
978
979        b.setLenient(!a.isLenient());
980        if (a.hashCode() == b.hashCode()) {
981            errln("Calendar hash code ignores lenient setting");
982        }
983        b.setLenient(a.isLenient());
984
985        // Assume getTimeZone() returns a reference, not a clone
986        // of a reference -- this is true as of this writing
987        b.getTimeZone().setRawOffset(a.getTimeZone().getRawOffset() + 60 * 60 * 1000);
988        if (a.hashCode() == b.hashCode()) {
989            errln("Calendar hash code ignores zone");
990        }
991        b.getTimeZone().setRawOffset(a.getTimeZone().getRawOffset());
992
993        GregorianCalendar c = new GregorianCalendar();
994        GregorianCalendar d = (GregorianCalendar) c.clone();
995        if (c.hashCode() != d.hashCode()) {
996            errln("GregorianCalendar hash code unequal for clones objects");
997        }
998        Date cutover = c.getGregorianChange();
999        d.setGregorianChange(new Date(cutover.getTime() + 24 * 60 * 60 * 1000));
1000        if (c.hashCode() == d.hashCode()) {
1001            errln("GregorianCalendar hash code ignores cutover");
1002        }
1003    }
1004
1005    /**
1006     * GregorianCalendar.equals() ignores cutover date
1007     */
1008    public void Test4141665() {
1009        GregorianCalendar cal = new GregorianCalendar();
1010        GregorianCalendar cal2 = (GregorianCalendar) cal.clone();
1011        Date cut = cal.getGregorianChange();
1012        Date cut2 = new Date(cut.getTime() + 100 * 24 * 60 * 60 * 1000L); // 100 days later
1013        if (!cal.equals(cal2)) {
1014            errln("Cloned GregorianCalendars not equal");
1015        }
1016        cal2.setGregorianChange(cut2);
1017        if (cal.equals(cal2)) {
1018            errln("GregorianCalendar.equals() ignores cutover");
1019        }
1020    }
1021
1022    /**
1023     * Bug states that ArrayIndexOutOfBoundsException is thrown by GregorianCalendar.roll()
1024     * when IllegalArgumentException should be.
1025     */
1026    public void Test4142933() {
1027        GregorianCalendar calendar = new GregorianCalendar();
1028        try {
1029            calendar.roll(-1, true);
1030            errln("Test failed, no exception trown");
1031        } catch (IllegalArgumentException e) {
1032            // OK: Do nothing
1033            // logln("Test passed");
1034        } catch (Exception e) {
1035            errln("Test failed. Unexpected exception is thrown: " + e);
1036            e.printStackTrace();
1037        }
1038    }
1039
1040    /**
1041     * GregorianCalendar handling of Dates Long.MIN_VALUE and Long.MAX_VALUE is
1042     * confusing; unless the time zone has a raw offset of zero, one or the
1043     * other of these will wrap.  We've modified the test given in the bug
1044     * report to therefore only check the behavior of a calendar with a zero raw
1045     * offset zone.
1046     */
1047    public void Test4145158() {
1048        GregorianCalendar calendar = new GregorianCalendar();
1049
1050        calendar.setTimeZone(TimeZone.getTimeZone("GMT"));
1051
1052        calendar.setTime(new Date(Long.MIN_VALUE));
1053        int year1 = calendar.get(YEAR);
1054        int era1 = calendar.get(ERA);
1055
1056        calendar.setTime(new Date(Long.MAX_VALUE));
1057        int year2 = calendar.get(YEAR);
1058        int era2 = calendar.get(ERA);
1059
1060        if (year1 == year2 && era1 == era2) {
1061            errln("Fail: Long.MIN_VALUE or Long.MAX_VALUE wrapping around");
1062        }
1063    }
1064
1065    /**
1066     * Maximum value for YEAR field wrong.
1067     */
1068    public void Test4145983() {
1069        GregorianCalendar calendar = new GregorianCalendar();
1070        calendar.setTimeZone(TimeZone.getTimeZone("GMT"));
1071        Date[] DATES = {new Date(Long.MAX_VALUE), new Date(Long.MIN_VALUE)};
1072        for (int i = 0; i < DATES.length; ++i) {
1073            calendar.setTime(DATES[i]);
1074            int year = calendar.get(YEAR);
1075            int maxYear = calendar.getMaximum(YEAR);
1076            if (year > maxYear) {
1077                errln("Failed for " + DATES[i].getTime() + " ms: year="
1078                        + year + ", maxYear=" + maxYear);
1079            }
1080        }
1081    }
1082
1083    /**
1084     * This is a bug in the validation code of GregorianCalendar.  As reported,
1085     * the bug seems worse than it really is, due to a bug in the way the bug
1086     * report test was written.  In reality the bug is restricted to the DAY_OF_YEAR
1087     * field. - liu 6/29/98
1088     */
1089    public void Test4147269() {
1090        final String[] fieldName = {
1091            "ERA",
1092            "YEAR",
1093            "MONTH",
1094            "WEEK_OF_YEAR",
1095            "WEEK_OF_MONTH",
1096            "DAY_OF_MONTH",
1097            "DAY_OF_YEAR",
1098            "DAY_OF_WEEK",
1099            "DAY_OF_WEEK_IN_MONTH",
1100            "AM_PM",
1101            "HOUR",
1102            "HOUR_OF_DAY",
1103            "MINUTE",
1104            "SECOND",
1105            "MILLISECOND",
1106            "ZONE_OFFSET",
1107            "DST_OFFSET"};
1108        GregorianCalendar calendar = new GregorianCalendar();
1109        calendar.setLenient(false);
1110        @SuppressWarnings("deprecation")
1111        Date date = new Date(1996 - 1900, JANUARY, 3); // Arbitrary date
1112        for (int field = 0; field < FIELD_COUNT; field++) {
1113            calendar.setTime(date);
1114            // Note: In the bug report, getActualMaximum() was called instead
1115            // of getMaximum() -- this was an error.  The validation code doesn't
1116            // use getActualMaximum(), since that's too costly.
1117            int max = calendar.getMaximum(field);
1118            int value = max + 1;
1119            calendar.set(field, value);
1120            try {
1121                calendar.getTime(); // Force time computation
1122                // We expect an exception to be thrown. If we fall through
1123                // to the next line, then we have a bug.
1124                errln("Test failed with field " + fieldName[field]
1125                        + ", date before: " + date
1126                        + ", date after: " + calendar.getTime()
1127                        + ", value: " + value + " (max = " + max + ")");
1128            } catch (IllegalArgumentException e) {
1129            }
1130        }
1131    }
1132
1133    /**
1134     * Reported bug is that a GregorianCalendar with a cutover of Date(Long.MAX_VALUE)
1135     * doesn't behave as a pure Julian calendar.
1136     * CANNOT REPRODUCE THIS BUG
1137     */
1138    public void Test4149677() {
1139        TimeZone[] zones = {TimeZone.getTimeZone("GMT"),
1140            TimeZone.getTimeZone("PST"),
1141            TimeZone.getTimeZone("EAT")};
1142        for (int i = 0; i < zones.length; ++i) {
1143            GregorianCalendar calendar = new GregorianCalendar(zones[i]);
1144
1145            // Make sure extreme values don't wrap around
1146            calendar.setTime(new Date(Long.MIN_VALUE));
1147            if (calendar.get(ERA) != GregorianCalendar.BC) {
1148                errln("Fail: Date(Long.MIN_VALUE) has an AD year in " + zones[i]);
1149            }
1150            calendar.setTime(new Date(Long.MAX_VALUE));
1151            if (calendar.get(ERA) != GregorianCalendar.AD) {
1152                errln("Fail: Date(Long.MAX_VALUE) has a BC year in " + zones[i]);
1153            }
1154
1155            calendar.setGregorianChange(new Date(Long.MAX_VALUE));
1156            // to obtain a pure Julian calendar
1157
1158            boolean is100Leap = calendar.isLeapYear(100);
1159            if (!is100Leap) {
1160                errln("test failed with zone " + zones[i].getID());
1161                errln(" cutover date is Date(Long.MAX_VALUE)");
1162                errln(" isLeapYear(100) returns: " + is100Leap);
1163            }
1164        }
1165    }
1166
1167    /**
1168     * Calendar and Date HOUR broken.  If HOUR is out-of-range, Calendar
1169     * and Date classes will misbehave.
1170     */
1171    public void Test4162587() {
1172        TimeZone savedTz = TimeZone.getDefault();
1173        TimeZone tz = TimeZone.getTimeZone("PST");
1174        TimeZone.setDefault(tz);
1175        GregorianCalendar cal = new GregorianCalendar(tz);
1176        Date d;
1177
1178        try {
1179            for (int i = 0; i < 5; ++i) {
1180                if (i > 0) {
1181                    logln("---");
1182                }
1183
1184                cal.clear();
1185                cal.set(1998, APRIL, 5, i, 0);
1186                d = cal.getTime();
1187                String s0 = d.toString();
1188                logln("0 " + i + ": " + s0);
1189
1190                cal.clear();
1191                cal.set(1998, APRIL, 4, i + 24, 0);
1192                d = cal.getTime();
1193                String sPlus = d.toString();
1194                logln("+ " + i + ": " + sPlus);
1195
1196                cal.clear();
1197                cal.set(1998, APRIL, 6, i - 24, 0);
1198                d = cal.getTime();
1199                String sMinus = d.toString();
1200                logln("- " + i + ": " + sMinus);
1201
1202                if (!s0.equals(sPlus) || !s0.equals(sMinus)) {
1203                    errln("Fail: All three lines must match");
1204                }
1205            }
1206        } finally {
1207            TimeZone.setDefault(savedTz);
1208        }
1209    }
1210
1211    /**
1212     * Adding 12 months behaves differently from adding 1 year
1213     */
1214    public void Test4165343() {
1215        GregorianCalendar calendar = new GregorianCalendar(1996, FEBRUARY, 29);
1216        Date start = calendar.getTime();
1217        logln("init date: " + start);
1218        calendar.add(MONTH, 12);
1219        Date date1 = calendar.getTime();
1220        logln("after adding 12 months: " + date1);
1221        calendar.setTime(start);
1222        calendar.add(YEAR, 1);
1223        Date date2 = calendar.getTime();
1224        logln("after adding one year : " + date2);
1225        if (date1.equals(date2)) {
1226            logln("Test passed");
1227        } else {
1228            errln("Test failed");
1229        }
1230    }
1231
1232    /**
1233     * GregorianCalendar.getActualMaximum() does not account for first day of week.
1234     */
1235    public void Test4166109() {
1236        /* Test month:
1237        *
1238        *      March 1998
1239        * Su Mo Tu We Th Fr Sa
1240        *  1  2  3  4  5  6  7
1241        *  8  9 10 11 12 13 14
1242        * 15 16 17 18 19 20 21
1243        * 22 23 24 25 26 27 28
1244        * 29 30 31
1245         */
1246        boolean passed = true;
1247        int field = WEEK_OF_MONTH;
1248
1249        GregorianCalendar calendar = new GregorianCalendar(Locale.US);
1250        calendar.set(1998, MARCH, 1);
1251        calendar.setMinimalDaysInFirstWeek(1);
1252        logln("Date:  " + calendar.getTime());
1253
1254        int firstInMonth = calendar.get(DAY_OF_MONTH);
1255
1256        for (int firstInWeek = SUNDAY; firstInWeek <= SATURDAY; firstInWeek++) {
1257            calendar.setFirstDayOfWeek(firstInWeek);
1258            int returned = calendar.getActualMaximum(field);
1259            int expected = (31 + ((firstInMonth - firstInWeek + 7) % 7) + 6) / 7;
1260
1261            logln("First day of week = " + firstInWeek
1262                    + "  getActualMaximum(WEEK_OF_MONTH) = " + returned
1263                    + "  expected = " + expected
1264                    + ((returned == expected) ? "  ok" : "  FAIL"));
1265
1266            if (returned != expected) {
1267                passed = false;
1268            }
1269        }
1270        if (!passed) {
1271            errln("Test failed");
1272        }
1273    }
1274
1275    /**
1276     * Calendar.getActualMaximum(YEAR) works wrong.
1277     *
1278     * Note: Before 1.5, this test case assumed that
1279     * setGregorianChange didn't change object's date. But it was
1280     * changed. See 4928615.
1281     */
1282    public void Test4167060() {
1283        int field = YEAR;
1284        DateFormat format = new SimpleDateFormat("EEE MMM dd HH:mm:ss zzz yyyy G",
1285                Locale.US);
1286
1287        int[][] dates = {
1288            // year, month, day of month
1289            {100, NOVEMBER, 1},
1290            {-99 /*100BC*/, JANUARY, 1},
1291            {1996, FEBRUARY, 29}};
1292
1293        String[] id = {"Hybrid", "Gregorian", "Julian"};
1294
1295        for (int k = 0; k < 3; ++k) {
1296            logln("--- " + id[k] + " ---");
1297
1298            for (int j = 0; j < dates.length; ++j) {
1299                GregorianCalendar calendar = new GregorianCalendar();
1300                if (k == 1) {
1301                    calendar.setGregorianChange(new Date(Long.MIN_VALUE));
1302                } else if (k == 2) {
1303                    calendar.setGregorianChange(new Date(Long.MAX_VALUE));
1304                }
1305                calendar.set(dates[j][0], dates[j][1], dates[j][2]);
1306                format.setCalendar((Calendar) calendar.clone());
1307
1308                Date dateBefore = calendar.getTime();
1309
1310                int maxYear = calendar.getActualMaximum(field);
1311                logln("maxYear: " + maxYear + " for " + format.format(calendar.getTime()));
1312                logln("date before: " + format.format(dateBefore));
1313
1314                int[] years = {2000, maxYear - 1, maxYear, maxYear + 1};
1315
1316                for (int i = 0; i < years.length; i++) {
1317                    boolean valid = years[i] <= maxYear;
1318                    calendar.set(field, years[i]);
1319                    Date dateAfter = calendar.getTime();
1320                    int newYear = calendar.get(field);
1321                    calendar.setTime(dateBefore); // restore calendar for next use
1322
1323                    logln(" Year " + years[i] + (valid ? " ok " : " bad")
1324                            + " => " + format.format(dateAfter));
1325                    if (valid && newYear != years[i]) {
1326                        errln("  FAIL: " + newYear + " should be valid; date, month and time shouldn't change");
1327                    } else if (!valid && newYear == years[i]) {
1328                        errln("  FAIL: " + newYear + " should be invalid");
1329                    }
1330                }
1331            }
1332        }
1333    }
1334
1335    /**
1336     * Calendar.roll broken
1337     * This bug relies on the TimeZone bug 4173604 to also be fixed.
1338     */
1339    public void Test4173516() {
1340        Locale locale = Locale.getDefault();
1341        if (!TestUtils.usesGregorianCalendar(locale)) {
1342            logln("Skipping this test because locale is " + locale);
1343            return;
1344        }
1345
1346        int[][] fieldsList = {
1347            {1997, FEBRUARY, 1, 10, 45, 15, 900},
1348            {1999, DECEMBER, 22, 23, 59, 59, 999},
1349            // test case for 4960642 with default cutover
1350            {1582, OCTOBER, 4, 23, 59, 59, 999}};
1351        String[] fieldNames = {
1352            "ERA", "YEAR", "MONTH", "WEEK_OF_YEAR", "WEEK_OF_MONTH",
1353            "DAY_OF_MONTH", "DAY_OF_YEAR", "DAY_OF_WEEK", "DAY_OF_WEEK_IN_MONTH",
1354            "AM_PM", "HOUR", "HOUR_OF_DAY", "MINUTE", "SECOND", "MILLISECOND",
1355            "ZONE_OFFSET", "DST_OFFSET"};
1356
1357        Locale savedLocale = Locale.getDefault();
1358        Locale.setDefault(Locale.US);
1359        int limit = 40;
1360
1361        try {
1362            GregorianCalendar cal = new GregorianCalendar();
1363
1364            cal.setTime(new Date(0));
1365            cal.roll(HOUR, 0x7F000000);
1366            cal.roll(HOUR, -0x7F000000);
1367            if (cal.getTime().getTime() != 0) {
1368                errln("Hour rolling broken. expected 0, got " + cal.getTime().getTime());
1369            }
1370
1371            for (int op = 0; op < 2; ++op) {
1372                logln("Testing GregorianCalendar " + (op == 0 ? "add" : "roll"));
1373
1374                for (int field = 0; field < FIELD_COUNT; ++field) {
1375                    if (field != ZONE_OFFSET
1376                            && field != DST_OFFSET) {
1377                        for (int j = 0; j < fieldsList.length; ++j) {
1378                            int[] fields = fieldsList[j];
1379                            cal.clear();
1380                            cal.set(fields[0], fields[1], fields[2],
1381                                    fields[3], fields[4], fields[5]);
1382                            cal.set(MILLISECOND, fields[6]);
1383                            for (int i = 0; i < 2 * limit; i++) {
1384                                if (op == 0) {
1385                                    cal.add(field, i < limit ? 1 : -1);
1386                                } else {
1387                                    cal.roll(field, i < limit ? 1 : -1);
1388                                }
1389                            }
1390
1391                            if (cal.get(YEAR) != fields[0]
1392                                    || cal.get(MONTH) != fields[1]
1393                                    || cal.get(DATE) != fields[2]
1394                                    || cal.get(HOUR_OF_DAY) != fields[3]
1395                                    || cal.get(MINUTE) != fields[4]
1396                                    || cal.get(SECOND) != fields[5]
1397                                    || cal.get(MILLISECOND) != fields[6]) {
1398                                errln("Field " + field
1399                                        + " (" + fieldNames[field]
1400                                        + ") FAIL, expected "
1401                                        + fields[0]
1402                                        + "/" + (fields[1] + 1)
1403                                        + "/" + fields[2]
1404                                        + " " + fields[3]
1405                                        + ":" + fields[4]
1406                                        + ":" + fields[5]
1407                                        + "." + fields[6]
1408                                        + ", got " + cal.get(YEAR)
1409                                        + "/" + (cal.get(MONTH) + 1)
1410                                        + "/" + cal.get(DATE)
1411                                        + " " + cal.get(HOUR_OF_DAY)
1412                                        + ":" + cal.get(MINUTE)
1413                                        + ":" + cal.get(SECOND)
1414                                        + "." + cal.get(MILLISECOND));
1415
1416                                cal.clear();
1417                                cal.set(fields[0], fields[1], fields[2],
1418                                        fields[3], fields[4], fields[5]);
1419                                cal.set(MILLISECOND, fields[6]);
1420                                errln(cal.get(YEAR)
1421                                        + "/" + (cal.get(MONTH) + 1)
1422                                        + "/" + cal.get(DATE)
1423                                        + " " + cal.get(HOUR_OF_DAY)
1424                                        + ":" + cal.get(MINUTE)
1425                                        + ":" + cal.get(SECOND)
1426                                        + "." + cal.get(MILLISECOND));
1427
1428                                long prev = cal.getTime().getTime();
1429                                for (int i = 0; i < 2 * limit; i++) {
1430                                    if (op == 0) {
1431                                        cal.add(field, i < limit ? 1 : -1);
1432                                    } else {
1433                                        cal.roll(field, i < limit ? 1 : -1);
1434                                    }
1435                                    long t = cal.getTime().getTime();
1436                                    long delta = t - prev;
1437                                    prev = t;
1438                                    errln((op == 0 ? "add(" : "roll(")
1439                                            + fieldNames[field] + ", "
1440                                            + (i < limit ? "+" : "-") + "1) => "
1441                                            + cal.get(YEAR)
1442                                            + "/" + (cal.get(MONTH) + 1)
1443                                            + "/" + cal.get(DATE)
1444                                            + " " + cal.get(HOUR_OF_DAY)
1445                                            + ":" + cal.get(MINUTE)
1446                                            + ":" + cal.get(SECOND)
1447                                            + "." + cal.get(MILLISECOND)
1448                                            + " d=" + delta);
1449                                }
1450                            }
1451                        }
1452                    }
1453                }
1454            }
1455        } finally {
1456            Locale.setDefault(savedLocale);
1457        }
1458    }
1459
1460    public void Test4174361() {
1461        GregorianCalendar calendar = new GregorianCalendar(1996, 1, 29);
1462
1463        calendar.add(MONTH, 10);
1464        Date date1 = calendar.getTime();
1465        int d1 = calendar.get(DAY_OF_MONTH);
1466
1467        calendar = new GregorianCalendar(1996, 1, 29);
1468        calendar.add(MONTH, 11);
1469        Date date2 = calendar.getTime();
1470        int d2 = calendar.get(DAY_OF_MONTH);
1471
1472        if (d1 != d2) {
1473            errln("adding months to Feb 29 broken");
1474        }
1475    }
1476
1477    /**
1478     * Calendar does not update field values when setTimeZone is called.
1479     */
1480    public void Test4177484() {
1481        TimeZone PST = TimeZone.getTimeZone("PST");
1482        TimeZone EST = TimeZone.getTimeZone("EST");
1483
1484        Calendar cal = Calendar.getInstance(PST, Locale.US);
1485        cal.clear();
1486        cal.set(1999, 3, 21, 15, 5, 0); // Arbitrary
1487        int h1 = cal.get(HOUR_OF_DAY);
1488        cal.setTimeZone(EST);
1489        int h2 = cal.get(HOUR_OF_DAY);
1490        if (h1 == h2) {
1491            errln("FAIL: Fields not updated after setTimeZone");
1492        }
1493
1494        // getTime() must NOT change when time zone is changed.
1495        // getTime() returns zone-independent time in ms.
1496        cal.clear();
1497        cal.setTimeZone(PST);
1498        cal.set(HOUR_OF_DAY, 10);
1499        Date pst10 = cal.getTime();
1500        cal.setTimeZone(EST);
1501        Date est10 = cal.getTime();
1502        if (!pst10.equals(est10)) {
1503            errln("FAIL: setTimeZone changed time");
1504        }
1505    }
1506
1507    /**
1508     * Week of year is wrong at the start and end of the year.
1509     */
1510    public void Test4197699() {
1511        GregorianCalendar cal = new GregorianCalendar();
1512        cal.setFirstDayOfWeek(MONDAY);
1513        cal.setMinimalDaysInFirstWeek(4);
1514        DateFormat fmt = new SimpleDateFormat("E dd MMM yyyy  'DOY='D 'WOY='w");
1515        fmt.setCalendar(cal);
1516
1517        int[] DATA = {
1518            2000, JANUARY, 1, 52,
1519            2001, DECEMBER, 31, 1};
1520
1521        for (int i = 0; i < DATA.length;) {
1522            cal.set(DATA[i++], DATA[i++], DATA[i++]);
1523            int expWOY = DATA[i++];
1524            int actWOY = cal.get(WEEK_OF_YEAR);
1525            if (expWOY == actWOY) {
1526                logln("Ok: " + fmt.format(cal.getTime()));
1527            } else {
1528                errln("FAIL: " + fmt.format(cal.getTime())
1529                        + ", expected WOY=" + expWOY);
1530                cal.add(DATE, -8);
1531                for (int j = 0; j < 14; ++j) {
1532                    cal.add(DATE, 1);
1533                    logln(fmt.format(cal.getTime()));
1534                }
1535            }
1536        }
1537    }
1538
1539    /**
1540     * Calendar DAY_OF_WEEK_IN_MONTH fields->time broken.  The problem
1541     * is in the field disambiguation code in GregorianCalendar.  This
1542     * code is supposed to choose the most recent set of fields
1543     * among the following:
1544     *
1545     *   MONTH + DAY_OF_MONTH
1546     *   MONTH + WEEK_OF_MONTH + DAY_OF_WEEK
1547     *   MONTH + DAY_OF_WEEK_IN_MONTH + DAY_OF_WEEK
1548     *   DAY_OF_YEAR
1549     *   WEEK_OF_YEAR + DAY_OF_WEEK
1550     */
1551    @SuppressWarnings("deprecation")
1552    public void Test4209071() {
1553        Calendar cal = Calendar.getInstance(Locale.US);
1554
1555        // General field setting test
1556        int Y = 1995 - 1900;
1557
1558        Object[] FIELD_DATA = {
1559            // Add new test cases as needed.
1560
1561            // 0
1562            new int[]{}, new Date(Y, JANUARY, 1),
1563            // 1
1564            new int[]{MONTH, MARCH},
1565            new Date(Y, MARCH, 1),
1566            // 2
1567            new int[]{DAY_OF_WEEK, WEDNESDAY},
1568            new Date(Y, JANUARY, 4),
1569            // 3
1570            new int[]{DAY_OF_WEEK, THURSDAY,
1571                DAY_OF_MONTH, 18,},
1572            new Date(Y, JANUARY, 18),
1573            // 4
1574            new int[]{DAY_OF_MONTH, 18,
1575                DAY_OF_WEEK, THURSDAY,},
1576            new Date(Y, JANUARY, 18),
1577            // 5  (WOM -1 is in previous month)
1578            new int[]{DAY_OF_MONTH, 18,
1579                WEEK_OF_MONTH, -1,
1580                DAY_OF_WEEK, THURSDAY,},
1581            new Date(Y - 1, DECEMBER, 22),
1582            // 6
1583            new int[]{DAY_OF_MONTH, 18,
1584                WEEK_OF_MONTH, 4,
1585                DAY_OF_WEEK, THURSDAY,},
1586            new Date(Y, JANUARY, 26),
1587            // 7  (DIM -1 is in same month)
1588            new int[]{DAY_OF_MONTH, 18,
1589                DAY_OF_WEEK_IN_MONTH, -1,
1590                DAY_OF_WEEK, THURSDAY,},
1591            new Date(Y, JANUARY, 26),
1592            // 8
1593            new int[]{WEEK_OF_YEAR, 9,
1594                DAY_OF_WEEK, WEDNESDAY,},
1595            new Date(Y, MARCH, 1),
1596            // 9
1597            new int[]{MONTH, OCTOBER,
1598                DAY_OF_WEEK_IN_MONTH, 1,
1599                DAY_OF_WEEK, FRIDAY,},
1600            new Date(Y, OCTOBER, 6),
1601            // 10
1602            new int[]{MONTH, OCTOBER,
1603                WEEK_OF_MONTH, 2,
1604                DAY_OF_WEEK, FRIDAY,},
1605            new Date(Y, OCTOBER, 13),
1606            // 11
1607            new int[]{MONTH, OCTOBER,
1608                DAY_OF_MONTH, 15,
1609                DAY_OF_YEAR, 222,},
1610            new Date(Y, AUGUST, 10),
1611            // 12
1612            new int[]{DAY_OF_WEEK, THURSDAY,
1613                MONTH, DECEMBER,},
1614            new Date(Y, DECEMBER, 7)};
1615
1616        for (int i = 0; i < FIELD_DATA.length; i += 2) {
1617            int[] fields = (int[]) FIELD_DATA[i];
1618            Date exp = (Date) FIELD_DATA[i + 1];
1619
1620            cal.clear();
1621            cal.set(YEAR, Y + 1900);
1622            for (int j = 0; j < fields.length; j += 2) {
1623                cal.set(fields[j], fields[j + 1]);
1624            }
1625
1626            Date act = cal.getTime();
1627            if (!act.equals(exp)) {
1628                errln("FAIL: Test " + (i / 2) + " got " + act
1629                        + ", want " + exp
1630                        + " (see test/java/util/Calendar/CalendarRegression.java");
1631            }
1632        }
1633
1634        // Test specific failure reported in bug
1635        @SuppressWarnings("deprecation")
1636        Object[] DATA = {
1637            1, new Date(1997 - 1900, JANUARY, 5),
1638            4, new Date(1997 - 1900, JANUARY, 26),
1639            8, new Date(1997 - 1900, FEBRUARY, 23),
1640            -1, new Date(1997 - 1900, JANUARY, 26),
1641            -4, new Date(1997 - 1900, JANUARY, 5),
1642            -8, new Date(1996 - 1900, DECEMBER, 8)};
1643        for (int i = 0; i < DATA.length; i += 2) {
1644            cal.clear();
1645            cal.set(DAY_OF_WEEK_IN_MONTH,
1646                    ((Number) DATA[i]).intValue());
1647            cal.set(DAY_OF_WEEK, SUNDAY);
1648            cal.set(MONTH, JANUARY);
1649            cal.set(YEAR, 1997);
1650            Date actual = cal.getTime();
1651            if (!actual.equals(DATA[i + 1])) {
1652                errln("FAIL: Sunday " + DATA[i]
1653                        + " of Jan 1997 -> " + actual
1654                        + ", want " + DATA[i + 1]);
1655            }
1656        }
1657    }
1658
1659    public void Test4288792() throws Exception {
1660        TimeZone savedTZ = TimeZone.getDefault();
1661        TimeZone.setDefault(TimeZone.getTimeZone("GMT"));
1662        GregorianCalendar cal = new GregorianCalendar();
1663        try {
1664            for (int i = 1900; i < 2100; i++) {
1665                for (int j1 = 1; j1 <= 7; j1++) {
1666                    // Loop for MinimalDaysInFirstWeek: 1..7
1667                    for (int j = SUNDAY; j <= SATURDAY; j++) {
1668                        // Loop for FirstDayOfWeek: SUNDAY..SATURDAY
1669                        cal.clear();
1670                        cal.setMinimalDaysInFirstWeek(j1);
1671                        cal.setFirstDayOfWeek(j);
1672                        cal.set(YEAR, i);
1673                        int maxWeek = cal.getActualMaximum(WEEK_OF_YEAR);
1674                        cal.set(WEEK_OF_YEAR, maxWeek);
1675                        cal.set(DAY_OF_WEEK, j);
1676
1677                        for (int k = 1; k < 7; k++) {
1678                            cal.add(DATE, 1);
1679                            int WOY = cal.get(WEEK_OF_YEAR);
1680                            if (WOY != maxWeek) {
1681                                errln(cal.getTime() + ",got=" + WOY
1682                                        + ",expected=" + maxWeek
1683                                        + ",min=" + j1 + ",first=" + j);
1684                            }
1685                        }
1686
1687                        cal.add(DATE, 1);
1688                        int WOY = cal.get(WEEK_OF_YEAR);
1689                        if (WOY != 1) {
1690                            errln(cal.getTime() + ",got=" + WOY
1691                                    + ",expected=1,min=" + j1 + ",first" + j);
1692                        }
1693                    }
1694                }
1695            }
1696        } finally {
1697            TimeZone.setDefault(savedTZ);
1698        }
1699    }
1700
1701    public void Test4328747() throws Exception {
1702        Calendar c = Calendar.getInstance(Locale.US);
1703        c.clear();
1704        c.set(1966, 0, 1); // 1 jan 1966
1705
1706        // serialize
1707        ByteArrayOutputStream out = new ByteArrayOutputStream();
1708        ObjectOutputStream s = new ObjectOutputStream(out);
1709        s.writeObject(c);
1710        s.flush();
1711
1712        // deserialize
1713        ObjectInputStream t = new ObjectInputStream(new ByteArrayInputStream(out.toByteArray()));
1714        Calendar result = (Calendar) t.readObject();
1715
1716        // let recalculate fields with the same UTC time
1717        result.setTime(result.getTime());
1718        // Bug gives 1965 11 19
1719        if ((result.get(YEAR) != 1966) || (result.get(MONTH) != 0)
1720                || (result.get(DATE) != 1)) {
1721            errln("deserialized Calendar returned wrong date field(s): "
1722                    + result.get(YEAR) + "/" + result.get(MONTH) + "/" + result.get(DATE)
1723                    + ", expected 1966/0/1");
1724        }
1725    }
1726
1727    /**
1728     * Test whether Calendar can be serialized/deserialized correctly
1729     * even if invalid/customized TimeZone is used.
1730     */
1731    public void Test4413980() {
1732        TimeZone savedTimeZone = TimeZone.getDefault();
1733        try {
1734            boolean pass = true;
1735            String[] IDs = new String[]{"Undefined", "PST", "US/Pacific",
1736                "GMT+3:00", "GMT-01:30"};
1737            for (int i = 0; i < IDs.length; i++) {
1738                TimeZone tz = TimeZone.getTimeZone(IDs[i]);
1739                TimeZone.setDefault(tz);
1740
1741                Calendar c = Calendar.getInstance();
1742
1743                // serialize
1744                ByteArrayOutputStream out = new ByteArrayOutputStream();
1745                ObjectOutputStream s = new ObjectOutputStream(out);
1746                s.writeObject(c);
1747                s.flush();
1748
1749                // deserialize
1750                ObjectInputStream t = new ObjectInputStream(new ByteArrayInputStream(out.toByteArray()));
1751
1752                if (!c.equals(t.readObject())) {
1753                    pass = false;
1754                    logln("Calendar instance which uses TimeZone <"
1755                            + IDs[i] + "> is incorrectly serialized/deserialized.");
1756                } else {
1757                    logln("Calendar instance which uses TimeZone <"
1758                            + IDs[i] + "> is correctly serialized/deserialized.");
1759                }
1760            }
1761            if (!pass) {
1762                errln("Fail: Calendar serialization/equality bug");
1763            }
1764        } catch (IOException | ClassNotFoundException e) {
1765            errln("Fail: " + e);
1766            e.printStackTrace();
1767        } finally {
1768            TimeZone.setDefault(savedTimeZone);
1769        }
1770    }
1771
1772    /**
1773     * 4546637: Incorrect WEEK_OF_MONTH after changing First Day Of Week
1774     */
1775    public void Test4546637() {
1776        GregorianCalendar day = new GregorianCalendar(2001, NOVEMBER, 04);
1777        day.setMinimalDaysInFirstWeek(1);
1778        int wom = day.get(WEEK_OF_MONTH);
1779
1780        day.setFirstDayOfWeek(MONDAY);
1781        if (day.get(WEEK_OF_MONTH) != 1) {
1782            errln("Fail: 2001/11/4 must be the first week of the month.");
1783        }
1784    }
1785
1786    /**
1787     * 4623997: GregorianCalendar returns bad WEEK_OF_YEAR
1788     */
1789    public void Test4623997() {
1790        GregorianCalendar cal = new GregorianCalendar(2000, JANUARY, 1);
1791
1792        int dow = cal.get(DAY_OF_WEEK);
1793
1794        cal.setFirstDayOfWeek(MONDAY);
1795        cal.setMinimalDaysInFirstWeek(4);
1796
1797        if (cal.get(WEEK_OF_YEAR) != 52) {
1798            errln("Fail: 2000/1/1 must be the 52nd week of the year.");
1799        }
1800    }
1801
1802    /**
1803     * 4685354: Handling of Calendar fields setting state is broken
1804     *
1805     * <p>Need to use SimpleDateFormat to test because a call to
1806     * get(int) changes internal states of a Calendar.
1807     */
1808    public void Test4685354() {
1809        Locale locale = Locale.getDefault();
1810        if (!TestUtils.usesAsciiDigits(locale)
1811                || !TestUtils.usesGregorianCalendar(locale)) {
1812            logln("Skipping this test because locale is " + locale);
1813            return;
1814        }
1815
1816        Calendar calendar = Calendar.getInstance(Locale.US);
1817        DateFormat df = new SimpleDateFormat("yyyy/MM/dd", Locale.US);
1818        String expected = "1999/12/31";
1819        Date t;
1820        String s;
1821
1822        try {
1823            calendar.setTime(df.parse(expected));
1824        } catch (Exception e) {
1825            throw new RuntimeException("Unexpected parse exception", e);
1826        }
1827
1828        t = calendar.getTime();
1829        calendar.set(DAY_OF_MONTH, 33);
1830        t = calendar.getTime();
1831        calendar.set(DAY_OF_MONTH, 0);
1832        s = df.format(calendar.getTime());
1833        if (!expected.equals(s)) {
1834            errln("DAY_OF_MONTH w/o ZONE_OFFSET: expected: " + expected + ", got: " + s);
1835        }
1836
1837        // The same thing must work with ZONE_OFFSET set
1838        try {
1839            calendar.setTime(df.parse(expected));
1840        } catch (Exception e) {
1841            throw new RuntimeException("Unexpected parse exception", e);
1842        }
1843        t = calendar.getTime();
1844        calendar.set(ZONE_OFFSET, calendar.get(ZONE_OFFSET));
1845        calendar.set(DAY_OF_MONTH, 33);
1846        t = calendar.getTime();
1847        calendar.set(DAY_OF_MONTH, 0);
1848        s = df.format(calendar.getTime());
1849        if (!expected.equals(s)) {
1850            errln("DAY_OF_MONTH: expected: " + expected + ", got: " + s);
1851        }
1852
1853        expected = "1999/12/24"; // 0th week of 2000
1854        calendar.clear();
1855        Date initialDate = null;
1856        try {
1857            initialDate = df.parse(expected);
1858            calendar.setTime(initialDate);
1859        } catch (Exception e) {
1860            throw new RuntimeException("Unexpected parse exception", e);
1861        }
1862        t = calendar.getTime();
1863        calendar.set(ZONE_OFFSET, calendar.get(ZONE_OFFSET));
1864        // jump to the next year
1865        calendar.set(WEEK_OF_YEAR, 100);
1866        t = calendar.getTime();
1867        calendar.set(WEEK_OF_YEAR, 0);
1868        s = df.format(calendar.getTime());
1869        if (!expected.equals(s)) {
1870            errln("WEEK_OF_YEAR: expected: " + expected + ", got: " + s);
1871        }
1872        // change the state back
1873        calendar.clear();
1874        calendar.setTime(initialDate);
1875        calendar.set(ZONE_OFFSET, calendar.get(ZONE_OFFSET));
1876        // jump to next month
1877        calendar.set(WEEK_OF_MONTH, 7);
1878        t = calendar.getTime();
1879        calendar.set(WEEK_OF_MONTH, 0);
1880        s = df.format(calendar.getTime());
1881        if (!expected.equals(s)) {
1882            errln("WEEK_OF_MONTH: expected: " + expected + ", got: " + s);
1883        }
1884
1885        // Make sure the time fields work correctly.
1886        calendar.clear();
1887        df = new SimpleDateFormat("HH:mm:ss");
1888        TimeZone tz = TimeZone.getTimeZone("GMT");
1889        df.setTimeZone(tz);
1890        calendar.setTimeZone(tz);
1891        expected = "22:59:59";
1892        try {
1893            calendar.setTime(df.parse(expected));
1894        } catch (Exception e) {
1895            throw new RuntimeException("Unexpected parse exception", e);
1896        }
1897        t = calendar.getTime();
1898        // time should be 22:59:59.
1899        calendar.set(MINUTE, 61);
1900        // time should be 23:01:59.
1901        t = calendar.getTime();
1902        calendar.set(MINUTE, -1);
1903        // time should be back to 22:59:59.
1904        s = df.format(calendar.getTime());
1905        if (!expected.equals(s)) {
1906            errln("MINUTE: expected: " + expected + ", got: " + s);
1907        }
1908    }
1909
1910    /**
1911     * 4655637: Calendar.set() for DAY_OF_WEEK does not return the right value
1912     *
1913     * <p>Need to use SimpleDateFormat to test because a call to
1914     * get(int) changes internal states of a Calendar.
1915     */
1916    public void Test4655637() {
1917        Locale locale = Locale.getDefault();
1918        if (!TestUtils.usesGregorianCalendar(locale)) {
1919            logln("Skipping this test because locale is " + locale);
1920            return;
1921        }
1922
1923        Calendar cal = Calendar.getInstance();
1924        cal.setTime(new Date(1029814211523L));
1925        cal.set(YEAR, 2001);
1926        Date t = cal.getTime();
1927        cal.set(MONTH, JANUARY);
1928        t = cal.getTime();
1929
1930        cal.set(DAY_OF_MONTH, 8);
1931        t = cal.getTime();
1932
1933        cal.set(DAY_OF_WEEK, MONDAY);
1934        DateFormat df = new SimpleDateFormat("yyyy/MM/dd", Locale.US);
1935        String expected = "2001/01/08";
1936        String s = df.format(cal.getTime());
1937        if (!expected.equals(s)) {
1938            errln("expected: " + expected + ", got: " + s);
1939        }
1940    }
1941
1942    /**
1943     * 4683492: Invalid value for MONTH in GregorianCalendar causes exception in getTime().
1944     *
1945     * <p>Need to use SimpleDateFormat to test because a call to
1946     * get(int) changes internal states of a Calendar.
1947     *
1948     * <p>This test case throws ArrayIndexOutOfBoundsException without the fix.
1949     */
1950    public void Test4683492() {
1951        Calendar cal = new GregorianCalendar(2002, 3, 29, 10, 0, 0);
1952        cal.set(DAY_OF_WEEK, FRIDAY);
1953        cal.set(DAY_OF_WEEK_IN_MONTH, -1);
1954        cal.set(MONTH, 12);
1955        DateFormat df = new SimpleDateFormat("yyyy/MM/dd", Locale.US);
1956        String expected = "2003/01/31";
1957        String s = df.format(cal.getTime());
1958        if (!expected.equals(s)) {
1959            errln("expected: " + expected + ", got: " + s);
1960        }
1961    }
1962
1963    /**
1964     * 4080631: Calendar.hashCode is amazingly bad
1965     */
1966    public void Test4080631() {
1967        Calendar cal = Calendar.getInstance();
1968        int h1 = cal.hashCode();
1969        cal.add(SECOND, +1);
1970        int h2 = cal.hashCode();
1971        Calendar cal2 = (Calendar) cal.clone();
1972        cal.add(MILLISECOND, +1);
1973        int h3 = cal.hashCode();
1974        logln("hash code: h1=" + h1 + ", h2=" + h2 + ", h3=" + h3);
1975        if (h1 == h2 || h1 == h3 || h2 == h3) {
1976            errln("hash code is poor: hashCode=" + h1);
1977        }
1978        h2 = cal2.hashCode();
1979        cal.add(MILLISECOND, -1);
1980        int h4 = cal.hashCode();
1981        logln("hash code: h2=" + h2 + ", h4=" + h4);
1982        if (cal.equals(cal2) && h2 != h4) {
1983            errln("broken hash code: h2=" + h2 + ", h4=" + h4);
1984        }
1985        int x = cal.getFirstDayOfWeek() + 3;
1986        if (x > SATURDAY) {
1987            x -= 7;
1988        }
1989        cal.setFirstDayOfWeek(x);
1990        int h5 = cal.hashCode();
1991        logln("hash code: h4=" + h4 + ", h5=" + h5);
1992        if (h4 == h5) {
1993            errln("has code is poor with first day of week param: hashCode=" + h4);
1994        }
1995    }
1996
1997    /**
1998     * 4125161: RFE: GregorianCalendar needs more era names (BCE and CE)
1999     */
2000    /*
2001    public void Test4125161() throws Exception {
2002        Class gc = GregorianCalendar.class;
2003        Field f;
2004        int mod;
2005        f = gc.getDeclaredField("BCE");
2006        mod = f.getModifiers();
2007        if (!Modifier.isStatic(mod) || !Modifier.isFinal(mod)) {
2008            errln("BCE: wrong modifiers: " + mod);
2009        }
2010        f = gc.getDeclaredField("CE");
2011        mod = f.getModifiers();
2012        if (!Modifier.isStatic(mod) || !Modifier.isFinal(mod)) {
2013            errln("CE: wrong modifiers: " + mod);
2014        }
2015        if (GregorianCalendar.BCE != GregorianCalendar.BC
2016            || GregorianCalendar.CE != GregorianCalendar.AD) {
2017            errln("Wrong BCE and/or CE values");
2018        }
2019    }
2020     */
2021    /**
2022     * 4167995: GregorianCalendar.setGregorianChange() not to spec
2023     */
2024    public void Test4167995() {
2025        Koyomi gc = new Koyomi(TimeZone.getTimeZone("GMT"));
2026        logln("Hybrid: min date");
2027        gc.setTime(new Date(Long.MIN_VALUE));
2028        if (!gc.checkDate(292269055, DECEMBER, 2, SUNDAY)
2029                || !gc.checkFieldValue(ERA, GregorianCalendar.BC)) {
2030            errln(gc.getMessage());
2031        }
2032        logln("Hybrid: max date");
2033        gc.setTime(new Date(Long.MAX_VALUE));
2034        if (!gc.checkDate(292278994, AUGUST, 17, SUNDAY)
2035                || !gc.checkFieldValue(ERA, GregorianCalendar.AD)) {
2036            errln(gc.getMessage());
2037        }
2038
2039        gc.setGregorianChange(new Date(Long.MIN_VALUE));
2040        logln("Gregorian: min date");
2041        gc.setTime(new Date(Long.MIN_VALUE));
2042        if (!gc.checkDate(292275056, MAY, 16, SUNDAY)
2043                || !gc.checkFieldValue(ERA, GregorianCalendar.BC)) {
2044            errln(gc.getMessage());
2045        }
2046        logln("Gregorian: max date");
2047        gc.setTime(new Date(Long.MAX_VALUE));
2048        if (!gc.checkDate(292278994, AUGUST, 17, SUNDAY)
2049                || !gc.checkFieldValue(ERA, GregorianCalendar.AD)) {
2050            errln(gc.getMessage());
2051        }
2052
2053        gc.setGregorianChange(new Date(Long.MAX_VALUE));
2054        logln("Julian: min date");
2055        gc.setTime(new Date(Long.MIN_VALUE));
2056        if (!gc.checkDate(292269055, DECEMBER, 2, SUNDAY)
2057                || !gc.checkFieldValue(ERA, GregorianCalendar.BC)) {
2058            errln(gc.getMessage());
2059        }
2060        logln("Julian: max date");
2061        gc.setTime(new Date(Long.MAX_VALUE));
2062        if (!gc.checkDate(292272993, JANUARY, 4, SUNDAY)
2063                || !gc.checkFieldValue(ERA, GregorianCalendar.AD)) {
2064            errln(gc.getMessage());
2065        }
2066    }
2067
2068    /**
2069     * 4340146: Calendar.equals modifies state
2070     */
2071    public void Test4340146() {
2072        Koyomi cal = new Koyomi();
2073        cal.clear();
2074        cal.set(2003, OCTOBER, 32);
2075        cal.equals(new Koyomi());
2076        if (!cal.checkInternalDate(2003, OCTOBER, 32)) {
2077            errln(cal.getMessage());
2078        }
2079        new Koyomi().equals(cal);
2080        if (!cal.checkInternalDate(2003, OCTOBER, 32)) {
2081            errln(cal.getMessage());
2082        }
2083    }
2084
2085    /**
2086     * 4639407: GregorianCalendar doesn't work in non-lenient due to timezone bounds checking
2087     */
2088    public void Test4639407() {
2089        // The following operations in non-lenient mode shouldn't
2090        // throw IllegalArgumentException.
2091        Koyomi cal = new Koyomi(TimeZone.getTimeZone("Pacific/Kiritimati"));
2092        cal.setLenient(false);
2093        cal.set(2003, OCTOBER, 10);
2094        cal.getTime();
2095        cal.setTimeZone(TimeZone.getTimeZone("Pacific/Tongatapu"));
2096        cal.set(2003, OCTOBER, 10);
2097        cal.getTime();
2098    }
2099
2100    /**
2101     * 4652815: rolling week-of-year back hundreds of weeks changes year
2102     */
2103    public void Test4652815() {
2104        Koyomi cal = new Koyomi(Locale.US);
2105        testRoll(cal, 2003, SEPTEMBER, 29);
2106        testRoll(cal, 2003, DECEMBER, 24);
2107        testRoll(cal, 1582, DECEMBER, 19);
2108        testRoll(cal, 1582, DECEMBER, 20);
2109    }
2110
2111    private void testRoll(Koyomi cal, int year, int month, int dayOfMonth) {
2112        cal.clear();
2113        cal.set(year, month, dayOfMonth);
2114        cal.getTime(); // normalize fields
2115        logln("Roll backwards from " + cal.toDateString());
2116        for (int i = 0; i < 1000; i++) {
2117            cal.roll(WEEK_OF_YEAR, -i);
2118            if (!cal.checkFieldValue(YEAR, year)) {
2119                errln(cal.getMessage());
2120            }
2121        }
2122        logln("Roll forewards from " + cal.toDateString());
2123        for (int i = 0; i < 1000; i++) {
2124            cal.roll(WEEK_OF_YEAR, +i);
2125            if (!cal.checkFieldValue(YEAR, year)) {
2126                errln(cal.getMessage());
2127            }
2128        }
2129    }
2130
2131    /**
2132     * 4652830: GregorianCalendar roll behaves unexpectedly for dates in BC era
2133     */
2134    public void Test4652830() {
2135        Koyomi cal = new Koyomi(Locale.US);
2136        cal.clear();
2137        logln("BCE 9-2-28 (leap year) roll DAY_OF_MONTH++ twice");
2138        cal.set(ERA, GregorianCalendar.BC);
2139        cal.set(9, FEBRUARY, 28);
2140        if (cal.getActualMaximum(DAY_OF_YEAR) != 366) {
2141            errln("    wrong actual max of DAY_OF_YEAR: got "
2142                    + cal.getActualMaximum(DAY_OF_YEAR) + " expected " + 366);
2143        }
2144        cal.roll(DAY_OF_MONTH, +1);
2145        if (!cal.checkFieldValue(ERA, GregorianCalendar.BC)
2146                || !cal.checkDate(9, FEBRUARY, 29)) {
2147            errln(cal.getMessage());
2148        }
2149        cal.roll(DAY_OF_MONTH, +1);
2150        if (!cal.checkFieldValue(ERA, GregorianCalendar.BC)
2151                || !cal.checkDate(9, FEBRUARY, 1)) {
2152            errln(cal.getMessage());
2153        }
2154    }
2155
2156    /**
2157     * 4740554: GregorianCalendar.getActualMaximum is inconsistent with normalization
2158     */
2159    public void Test4740554() {
2160        logln("1999/(Feb+12)/1 should be normalized to 2000/Feb/1 for getActualMaximum");
2161        Koyomi cal = new Koyomi(Locale.US);
2162        cal.clear();
2163        cal.set(1999, FEBRUARY + 12, 1);
2164        if (!cal.checkActualMaximum(DAY_OF_YEAR, 366)) {
2165            errln(cal.getMessage());
2166        }
2167        if (!cal.checkActualMaximum(DAY_OF_MONTH, 29)) {
2168            errln(cal.getMessage());
2169        }
2170    }
2171
2172    /**
2173     * 4936355: GregorianCalendar causes overflow/underflow with time of day calculation
2174     */
2175    public void Test4936355() {
2176        Koyomi cal = new Koyomi(TimeZone.getTimeZone("GMT"));
2177        cal.clear();
2178        cal.set(1970, JANUARY, 1);
2179        checkTimeCalculation(cal, HOUR_OF_DAY, Integer.MAX_VALUE,
2180                (long) Integer.MAX_VALUE * 60 * 60 * 1000);
2181
2182        cal.clear();
2183        cal.set(1970, JANUARY, 1);
2184        checkTimeCalculation(cal, HOUR, Integer.MAX_VALUE,
2185                (long) Integer.MAX_VALUE * 60 * 60 * 1000);
2186
2187        cal.clear();
2188        cal.set(1970, JANUARY, 1);
2189        checkTimeCalculation(cal, MINUTE, Integer.MAX_VALUE,
2190                (long) Integer.MAX_VALUE * 60 * 1000);
2191
2192        cal.clear();
2193        // Make sure to use Gregorian dates (before and after the
2194        // set() call) for testing
2195        cal.set(250000, JANUARY, 1);
2196        checkTimeCalculation(cal, HOUR_OF_DAY, Integer.MIN_VALUE,
2197                (long) Integer.MIN_VALUE * 60 * 60 * 1000);
2198
2199        cal.clear();
2200        cal.set(250000, JANUARY, 1);
2201        checkTimeCalculation(cal, HOUR, Integer.MIN_VALUE,
2202                (long) Integer.MIN_VALUE * 60 * 60 * 1000);
2203
2204        cal.clear();
2205        cal.set(250000, JANUARY, 1);
2206        checkTimeCalculation(cal, MINUTE, Integer.MIN_VALUE,
2207                (long) Integer.MIN_VALUE * 60 * 1000);
2208    }
2209
2210    private void checkTimeCalculation(Koyomi cal, int field, int value, long expectedDelta) {
2211        long time = cal.getTimeInMillis();
2212        cal.set(field, value);
2213        long time2 = cal.getTimeInMillis();
2214        if ((time + expectedDelta) != time2) {
2215            String s = value == Integer.MAX_VALUE ? "Integer.MAX_VALUE" : "Integer.MIN_VALUE";
2216            errln("set(" + Koyomi.getFieldName(field) + ", " + s + ") failed." + " got " + time2
2217                    + ", expected " + (time + expectedDelta));
2218        }
2219    }
2220
2221    /**
2222     * 4722650: Calendar.equals can throw an exception in non-lenient
2223     * (piggy-back tests for compareTo() which is new in 1.5)
2224     */
2225    public void Test4722650() {
2226        Calendar cal1 = new GregorianCalendar();
2227        cal1.clear();
2228        Calendar cal2 = new GregorianCalendar();
2229        cal2.clear();
2230        cal2.setLenient(false);
2231
2232        cal1.set(2003, OCTOBER, 31);
2233        cal2.set(2003, OCTOBER, 31);
2234        try {
2235            if (cal1.equals(cal2)) {
2236                errln("lenient and non-lenient shouldn't be equal. (2003/10/31)");
2237            }
2238            if (cal1.compareTo(cal2) != 0) {
2239                errln("cal1 and cal2 should represent the same time. (2003/10/31)");
2240            }
2241        } catch (IllegalArgumentException e) {
2242            errln("equals threw IllegalArugumentException with non-lenient");
2243        }
2244
2245        cal1.set(2003, OCTOBER, 32);
2246        cal2.set(2003, OCTOBER, 32);
2247        try {
2248            if (cal1.equals(cal2)) {
2249                errln("lenient and non-lenient shouldn't be equal. (2003/10/32)");
2250            }
2251            if (cal1.compareTo(cal2) != 0) {
2252                errln("cal1 and cal2 should represent the same time. (2003/10/32)");
2253            }
2254        } catch (IllegalArgumentException e) {
2255            errln("equals threw IllegalArugumentException with non-lenient");
2256        }
2257
2258        cal1 = Calendar.getInstance(new Locale("th", "TH"));
2259        cal1.setTimeInMillis(0L);
2260        cal2 = Calendar.getInstance(Locale.US);
2261        cal2.setTimeInMillis(0L);
2262        if (cal1.equals(cal2)) {
2263            errln("Buddhist.equals(Gregorian) shouldn't be true. (millis=0)");
2264        }
2265        if (cal1.compareTo(cal2) != 0) {
2266            errln("cal1 (Buddhist) and cal2 (Gregorian) should represent the same time. (millis=0)");
2267        }
2268    }
2269
2270    /**
2271     * 4738710: API: Calendar comparison methods should be improved
2272     */
2273    public void Test4738710() {
2274        Calendar cal0 = new GregorianCalendar(2003, SEPTEMBER, 30);
2275        Comparable<Calendar> cal1 = new GregorianCalendar(2003, OCTOBER, 1);
2276        Calendar cal2 = new GregorianCalendar(2003, OCTOBER, 2);
2277        if (!(cal1.compareTo(cal0) > 0)) {
2278            errln("!(cal1 > cal0)");
2279        }
2280        if (!(cal1.compareTo(cal2) < 0)) {
2281            errln("!(cal1 < cal2)");
2282        }
2283        if (cal1.compareTo(new GregorianCalendar(2003, OCTOBER, 1)) != 0) {
2284            errln("cal1 != new GregorianCalendar(2003, OCTOBER, 1)");
2285        }
2286
2287        if (cal0.after(cal2)) {
2288            errln("cal0 shouldn't be after cal2");
2289        }
2290        if (cal2.before(cal0)) {
2291            errln("cal2 shouldn't be before cal0");
2292        }
2293
2294        if (cal0.after(0)) {
2295            errln("cal0.after() returned true with an Integer.");
2296        }
2297        if (cal0.before(0)) {
2298            errln("cal0.before() returned true with an Integer.");
2299        }
2300        if (cal0.after(null)) {
2301            errln("cal0.after() returned true with null.");
2302        }
2303        if (cal0.before(null)) {
2304            errln("cal0.before() returned true with null.");
2305        }
2306    }
2307
2308    /**
2309     * 4633646: Setting WEEK_OF_MONTH to 1 results in incorrect date
2310     */
2311    @SuppressWarnings("deprecation")
2312    public void Test4633646() {
2313        Koyomi cal = new Koyomi(Locale.US);
2314        cal.setTime(new Date(2002 - 1900, 1 - 1, 28));
2315        sub4633646(cal);
2316
2317        cal.setLenient(false);
2318        cal.setTime(new Date(2002 - 1900, 1 - 1, 28));
2319        sub4633646(cal);
2320
2321        cal = new Koyomi(Locale.US);
2322        cal.clear();
2323        cal.set(2002, JANUARY, 28);
2324        sub4633646(cal);
2325
2326        cal.clear();
2327        cal.setLenient(false);
2328        cal.set(2002, JANUARY, 28);
2329        sub4633646(cal);
2330    }
2331
2332    void sub4633646(Koyomi cal) {
2333        cal.getTime();
2334        cal.set(WEEK_OF_MONTH, 1);
2335        if (cal.isLenient()) {
2336            if (!cal.checkDate(2001, DECEMBER, 31)) {
2337                errln(cal.getMessage());
2338            }
2339            if (!cal.checkFieldValue(WEEK_OF_MONTH, 6)) {
2340                errln(cal.getMessage());
2341            }
2342        } else {
2343            try {
2344                Date d = cal.getTime();
2345                errln("didn't throw IllegalArgumentException in non-lenient");
2346            } catch (IllegalArgumentException e) {
2347            }
2348        }
2349    }
2350
2351    /**
2352     * 4846659: Calendar: Both set() and roll() don't work for AM_PM time field
2353     * (Partially fixed only roll as of 1.5)
2354     */
2355    public void Test4846659() {
2356        Koyomi cal = new Koyomi();
2357        cal.clear();
2358        cal.set(2003, OCTOBER, 31, 10, 30, 30);
2359        cal.getTime();
2360        // Test roll()
2361        cal.roll(AM_PM, +1); // should turn to PM
2362        if (!cal.checkFieldValue(HOUR_OF_DAY, 10 + 12)) {
2363            errln("roll: AM_PM didn't change to PM");
2364        }
2365
2366        cal.clear();
2367        cal.set(2003, OCTOBER, 31, 10, 30, 30);
2368        cal.getTime();
2369        // Test set()
2370        cal.set(AM_PM, PM); // should turn to PM
2371        if (!cal.checkFieldValue(HOUR_OF_DAY, 10 + 12)) {
2372            errln("set: AM_PM didn't change to PM");
2373        }
2374
2375        cal.clear();
2376        cal.set(2003, OCTOBER, 31, 10, 30, 30);
2377        cal.getTime();
2378        cal.set(AM_PM, PM);
2379        cal.set(HOUR, 9);
2380        if (!cal.checkFieldValue(HOUR_OF_DAY, 9 + 12)) {
2381            errln("set: both AM_PM and HOUT didn't change to PM");
2382        }
2383    }
2384
2385    /**
2386     * 4822110: GregorianCalendar.get() returns an incorrect date after setFirstDayOfWeek()
2387     */
2388    public void Test4822110() {
2389        Koyomi cal = new Koyomi(Locale.US);
2390        //    June 2003
2391        //  S  M Tu  W Th  F  S
2392        //  1  2  3  4  5  6  7
2393        //  8  9 10 11 12 13 14
2394        // 15 16 17 18 19 20 21
2395        // 22 23 24 25 26 27 28
2396        // 29 30
2397        cal.clear();
2398        // 6/1 to 6/7 should be the 1st week of June.
2399        cal.set(2003, JUNE, 2);
2400        cal.getTime();                  // Let cal calculate time.
2401        cal.setFirstDayOfWeek(MONDAY);
2402        // Now 6/2 to 6/8 should be the 2nd week of June. Sunday of
2403        // that week is 6/8.
2404        logln("1: " + cal.get(WEEK_OF_MONTH) + ", " + cal.get(DAY_OF_MONTH));
2405        cal.set(DAY_OF_WEEK, SUNDAY);
2406        logln("1st Sunday of June 2003 with FirstDayOfWeek=MONDAY");
2407        if (!cal.checkDate(2003, JUNE, 8)) {
2408            errln(cal.getMessage());
2409        }
2410    }
2411
2412    /**
2413     * 4973919: Inconsistent GregorianCalendar hashCode before and after serialization
2414     */
2415    public void Test4966499() throws Exception {
2416        GregorianCalendar date1 = new GregorianCalendar(2004, JANUARY, 7);
2417
2418        // Serialize date1
2419        ByteArrayOutputStream baos = new ByteArrayOutputStream();
2420        ObjectOutputStream oos = new ObjectOutputStream(baos);
2421        oos.writeObject(date1);
2422
2423        byte[] buffer = baos.toByteArray();
2424
2425        // Deserialize it
2426        ByteArrayInputStream bais = new ByteArrayInputStream(buffer);
2427        ObjectInputStream ois = new ObjectInputStream(bais);
2428        GregorianCalendar date2 = (GregorianCalendar) ois.readObject();
2429
2430        if (!date1.equals(date2)) {
2431            errln("date1.equals(date2) != true");
2432        }
2433        if (date1.hashCode() != date2.hashCode()) {
2434            errln("inconsistent hashCode() value (before=0x"
2435                    + Integer.toHexString(date1.hashCode())
2436                    + ", after=0x" + Integer.toHexString(date2.hashCode()) + ")");
2437        }
2438    }
2439
2440    /**
2441     * 4980088: GregorianCalendar.getActualMaximum doesn't throw exception
2442     */
2443    public void Test4980088() {
2444        GregorianCalendar cal = new GregorianCalendar();
2445        try {
2446            int x = cal.getMaximum(100);
2447            errln("getMaximum(100) didn't throw an exception.");
2448        } catch (IndexOutOfBoundsException e) {
2449            logln("getMaximum: " + e.getClass().getName() + ": " + e.getMessage());
2450        }
2451
2452        try {
2453            int x = cal.getLeastMaximum(100);
2454            errln("getLeastMaximum(100) didn't throw an exception.");
2455        } catch (IndexOutOfBoundsException e) {
2456            logln("getLeastMaximum: " + e.getClass().getName() + ": " + e.getMessage());
2457        }
2458
2459        try {
2460            int x = cal.getActualMaximum(100);
2461            errln("getActualMaximum(100) didn't throw an exception.");
2462        } catch (IndexOutOfBoundsException e) {
2463            logln("getActualMaximum: " + e.getClass().getName() + ": " + e.getMessage());
2464        }
2465
2466        try {
2467            int x = cal.getMinimum(100);
2468            errln("getMinimum(100) didn't throw an exception.");
2469        } catch (IndexOutOfBoundsException e) {
2470            logln("getMinimum: " + e.getClass().getName() + ": " + e.getMessage());
2471        }
2472
2473        try {
2474            int x = cal.getGreatestMinimum(100);
2475            errln("getGreatestMinimum(100) didn't throw an exception.");
2476        } catch (IndexOutOfBoundsException e) {
2477            logln("getGreatestMinimum: " + e.getClass().getName() + ": " + e.getMessage());
2478        }
2479
2480        try {
2481            int x = cal.getActualMinimum(100);
2482            errln("getActualMinimum(100) didn't throw an exception.");
2483        } catch (IndexOutOfBoundsException e) {
2484            logln("getActualMinimum: " + e.getClass().getName() + ": " + e.getMessage());
2485        }
2486    }
2487
2488    /**
2489     * 4965624: GregorianCalendar.isLeapYear(1000) returns incorrect value
2490     */
2491    public void Test4965624() {
2492        // 5013094: This test case needs to use "GMT" to specify
2493        // Gregorian cutover dates.
2494        TimeZone savedZone = TimeZone.getDefault();
2495        TimeZone.setDefault(TimeZone.getTimeZone("GMT"));
2496        try {
2497            Map<Date, Boolean> data = new HashMap<>();
2498            data.put(getGregorianDate(999, OCTOBER, 1), Boolean.FALSE);
2499            data.put(getGregorianDate(1000, JANUARY, 1), Boolean.FALSE);
2500            data.put(getGregorianDate(1000, FEBRUARY, 1), Boolean.FALSE);
2501            data.put(getGregorianDate(1000, FEBRUARY, 28), Boolean.FALSE);
2502            data.put(getGregorianDate(1000, MARCH, 1), Boolean.TRUE);
2503            data.put(getGregorianDate(1001, JANUARY, 1), Boolean.TRUE);
2504            data.put(getGregorianDate(1001, JANUARY, 6), Boolean.TRUE);
2505            data.put(getGregorianDate(1001, MARCH, 1), Boolean.TRUE);
2506
2507            data.keySet().forEach(d -> {
2508                boolean expected = data.get(d);
2509                GregorianCalendar cal = new GregorianCalendar();
2510                cal.setGregorianChange(d);
2511                if (cal.isLeapYear(1000) != expected) {
2512                    errln("isLeapYear(1000) returned " + cal.isLeapYear(1000)
2513                            + " with cutover date (Julian) " + d);
2514                }
2515            });
2516        } finally {
2517            TimeZone.setDefault(savedZone);
2518        }
2519    }
2520
2521    // Note that we can't use Date to produce Gregorian calendar dates
2522    // before the default cutover date.
2523    static Date getGregorianDate(int year, int month, int dayOfMonth) {
2524        GregorianCalendar g = new GregorianCalendar();
2525        // Make g a pure Gregorian calendar
2526        g.setGregorianChange(new Date(Long.MIN_VALUE));
2527        g.clear();
2528        g.set(year, month, dayOfMonth);
2529        return g.getTime();
2530    }
2531
2532    /**
2533     * 5006864: Define the minimum value of DAY_OF_WEEK_IN_MONTH as 1
2534     */
2535    public void Test5006864() {
2536        GregorianCalendar cal = new GregorianCalendar();
2537        int min = cal.getMinimum(DAY_OF_WEEK_IN_MONTH);
2538        if (min != 1) {
2539            errln("GregorianCalendar.getMinimum(DAY_OF_WEEK_IN_MONTH) returned "
2540                    + min + ", expected 1.");
2541        }
2542        min = cal.getGreatestMinimum(DAY_OF_WEEK_IN_MONTH);
2543        if (min != 1) {
2544            errln("GregorianCalendar.getGreatestMinimum(DAY_OF_WEEK_IN_MONTH) returned "
2545                    + min + ", expected 1.");
2546        }
2547    }
2548}
2549