1/*
2 * Copyright (c) 1997, 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 4064654 4374886 4984320 4984574 4944795
27 * @summary test for Calendar
28 * @library /java/text/testlib
29 * @run main CalendarTest
30 * @key randomness
31 */
32
33import java.io.File;
34import java.io.FileInputStream;
35import java.io.FileOutputStream;
36import java.io.IOException;
37import java.io.ObjectInputStream;
38import java.io.ObjectOutput;
39import java.io.ObjectOutputStream;
40import java.util.Calendar;
41import java.util.Date;
42import java.util.GregorianCalendar;
43import java.util.Locale;
44import java.util.SimpleTimeZone;
45import java.util.TimeZone;
46
47import static java.util.Calendar.*;
48
49public class CalendarTest extends IntlTest {
50
51    static final int ONE_DAY = 24 * 60 * 60 * 1000;
52    static final int EPOCH_JULIAN = 2440588;
53
54    public static void main(String argv[]) throws Exception {
55        new CalendarTest().run(argv);
56    }
57
58    /**
59     * Test the behavior of the GregorianCalendar around the changeover.
60     */
61    public void TestGregorianChangeover() {
62        TimeZone savedZone = TimeZone.getDefault();
63        /*
64          Changeover -7 days: 1582/9/28 dow=6
65          Changeover -6 days: 1582/9/29 dow=7
66          Changeover -5 days: 1582/9/30 dow=1
67          Changeover -4 days: 1582/10/1 dow=2
68          Changeover -3 days: 1582/10/2 dow=3
69          Changeover -2 days: 1582/10/3 dow=4
70          Changeover -1 days: 1582/10/4 dow=5
71          Changeover +0 days: 1582/10/15 dow=6
72          Changeover +1 days: 1582/10/16 dow=7
73          Changeover +2 days: 1582/10/17 dow=1
74          Changeover +3 days: 1582/10/18 dow=2
75          Changeover +4 days: 1582/10/19 dow=3
76          Changeover +5 days: 1582/10/20 dow=4
77          Changeover +6 days: 1582/10/21 dow=5
78          Changeover +7 days: 1582/10/22 dow=6
79          */
80        int[] MON = {  9,  9,  9,10,10,10,10, 10, 10, 10, 10, 10, 10, 10, 10 };
81        int[] DOM = { 28, 29, 30, 1, 2, 3, 4, 15, 16, 17, 18, 19, 20, 21, 22 };
82        int[] DOW = {  6,  7,  1, 2, 3, 4, 5,  6,  7,  1,  2,  3,  4,  5,  6 };
83        //                                     ^ <-Changeover Fri Oct 15 1582
84        try {
85            TimeZone.setDefault(TimeZone.getTimeZone("GMT"));
86            @SuppressWarnings("deprecation")
87            Date co = new Date(1582 - 1900, OCTOBER, 15);
88            GregorianCalendar cal = new GregorianCalendar();
89            int j = 0;
90            for (int i = -7; i <= 7; ++i, ++j) {
91                Date d = new Date(co.getTime() + i * ONE_DAY);
92                cal.setTime(d);
93                int y = cal.get(YEAR);
94                int mon = cal.get(MONTH) + 1 - JANUARY;
95                int dom = cal.get(DATE);
96                int dow = cal.get(DAY_OF_WEEK);
97
98                logln("Changeover " + (i >= 0 ? "+" : "") + i
99                        + " days: " + y + "/" + mon + "/" + dom + " dow=" + dow);
100                if (y != 1582 || mon != MON[j] || dom != DOM[j] || dow != DOW[j]) {
101                    errln(" Fail: Above line is wrong");
102                }
103            }
104        } finally {
105            TimeZone.setDefault(savedZone);
106        }
107    }
108
109    /**
110     * Test the mapping between millis and fields.  For the purposes
111     * of this test, we don't care about timezones and week data
112     * (first day of week, minimal days in first week).
113     */
114    @SuppressWarnings("deprecation")
115    public void TestMapping() {
116        TimeZone saveZone = TimeZone.getDefault();
117        int[] DATA = {
118            // Julian#   Year      Month    DOM   JULIAN:Year  Month,   DOM
119            2440588,     1970,    JANUARY,   1,    1969,     DECEMBER,  19,
120            2415080,     1900,      MARCH,   1,    1900,     FEBRUARY,  17,
121            2451604,     2000,   FEBRUARY,  29,    2000,     FEBRUARY,  16,
122            2452269,     2001,   DECEMBER,  25,    2001,     DECEMBER,  12,
123            2416526,     1904,   FEBRUARY,  15,    1904,     FEBRUARY,   2,
124            2416656,     1904,       JUNE,  24,    1904,         JUNE,  11,
125            1721426,        1,    JANUARY,   1,       1,      JANUARY,   3,
126            2000000,      763,  SEPTEMBER,  18,     763,    SEPTEMBER,  14,
127            4000000,     6239,       JULY,  12,    6239,          MAY,  28,
128            8000000,    17191,   FEBRUARY,  26,   17190,      OCTOBER,  22,
129           10000000,    22666,   DECEMBER,  20,   22666,         JULY,   5};
130
131        try {
132            TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
133            Date PURE_GREGORIAN = new Date(Long.MIN_VALUE);
134            Date PURE_JULIAN = new Date(Long.MAX_VALUE);
135            GregorianCalendar cal = new GregorianCalendar();
136            for (int i = 0; i < DATA.length; i += 7) {
137                int julian = DATA[i];
138                int year = DATA[i + 1];
139                int month = DATA[i + 2];
140                int dom = DATA[i + 3];
141                int year2, month2, dom2;
142                long millis = ((long) julian - EPOCH_JULIAN) * ONE_DAY;
143                String s;
144
145                // Test Gregorian computation
146                cal.setGregorianChange(PURE_GREGORIAN);
147                cal.clear();
148                cal.set(year, month, dom);
149                long calMillis = cal.getTime().getTime();
150                long delta = calMillis - millis;
151                cal.setTime(new Date(millis));
152                year2 = cal.get(YEAR);
153                month2 = cal.get(MONTH);
154                dom2 = cal.get(DAY_OF_MONTH);
155                s = "G " + year + "-" + (month + 1 - JANUARY) + "-" + dom
156                        + " => " + calMillis
157                        + " (" + ((float) delta / ONE_DAY) + " day delta) => "
158                        + year2 + "-" + (month2 + 1 - JANUARY) + "-" + dom2;
159                if (delta != 0 || year != year2 || month != month2
160                        || dom != dom2) {
161                    errln(s + " FAIL");
162                } else {
163                    logln(s);
164                }
165
166                // Test Julian computation
167                year = DATA[i + 4];
168                month = DATA[i + 5];
169                dom = DATA[i + 6];
170                cal.setGregorianChange(PURE_JULIAN);
171                cal.clear();
172                cal.set(year, month, dom);
173                calMillis = cal.getTime().getTime();
174                delta = calMillis - millis;
175                cal.setTime(new Date(millis));
176                year2 = cal.get(YEAR);
177                month2 = cal.get(MONTH);
178                dom2 = cal.get(DAY_OF_MONTH);
179                s = "J " + year + "-" + (month + 1 - JANUARY) + "-" + dom
180                        + " => " + calMillis
181                        + " (" + ((float) delta / ONE_DAY) + " day delta) => "
182                        + year2 + "-" + (month2 + 1 - JANUARY) + "-" + dom2;
183                if (delta != 0 || year != year2 || month != month2
184                        || dom != dom2) {
185                    errln(s + " FAIL");
186                } else {
187                    logln(s);
188                }
189            }
190
191            cal.setGregorianChange(new Date(1582 - 1900, OCTOBER, 15));
192            auxMapping(cal, 1582, OCTOBER, 4);
193            auxMapping(cal, 1582, OCTOBER, 15);
194            auxMapping(cal, 1582, OCTOBER, 16);
195            for (int y = 800; y < 3000; y += 1 + 100 * Math.random()) {
196                for (int m = JANUARY; m <= DECEMBER; ++m) {
197                    auxMapping(cal, y, m, 15);
198                }
199            }
200        } finally {
201            TimeZone.setDefault(saveZone);
202        }
203    }
204    private void auxMapping(Calendar cal, int y, int m, int d) {
205        cal.clear();
206        cal.set(y, m, d);
207        long millis = cal.getTime().getTime();
208        cal.setTime(new Date(millis));
209        int year2 = cal.get(YEAR);
210        int month2 = cal.get(MONTH);
211        int dom2 = cal.get(DAY_OF_MONTH);
212        if (y != year2 || m != month2 || dom2 != d) {
213            errln("Round-trip failure: " + y + "-" + (m + 1) + "-" + d + " =>ms=> "
214                    + year2 + "-" + (month2 + 1) + "-" + dom2);
215        }
216    }
217
218    @SuppressWarnings("deprecation")
219    public void TestGenericAPI() {
220        Locale locale = Locale.getDefault();
221        if (!TestUtils.usesGregorianCalendar(locale)) {
222            logln("Skipping this test because locale is " + locale);
223            return;
224        }
225
226        String str;
227        Date when = new Date(90, APRIL, 15);
228
229        String tzid = "TestZone";
230        int tzoffset = 123400;
231
232        SimpleTimeZone zone = new SimpleTimeZone(tzoffset, tzid);
233        Calendar cal = Calendar.getInstance((SimpleTimeZone) zone.clone());
234
235        if (!zone.equals(cal.getTimeZone())) {
236            errln("FAIL: Calendar.getTimeZone failed");
237        }
238
239        Calendar cal2 = Calendar.getInstance(cal.getTimeZone());
240
241        cal.setTime(when);
242        cal2.setTime(when);
243
244        if (!(cal.equals(cal2))) {
245            errln("FAIL: Calendar.operator== failed");
246        }
247        // if ((*cal != *cal2))  errln("FAIL: Calendar.operator!= failed");
248        if (!cal.equals(cal2)
249                || cal.before(cal2)
250                || cal.after(cal2)) {
251            errln("FAIL: equals/before/after failed");
252        }
253
254        cal2.setTime(new Date(when.getTime() + 1000));
255        if (cal.equals(cal2)
256                || cal2.before(cal)
257                || cal.after(cal2)) {
258            errln("FAIL: equals/before/after failed");
259        }
260
261        cal.roll(SECOND, true);
262        if (!cal.equals(cal2)
263                || cal.before(cal2)
264                || cal.after(cal2)) {
265            errln("FAIL: equals/before/after failed");
266        }
267
268        // Roll back to January
269        cal.roll(MONTH, 1 + DECEMBER - cal.get(MONTH));
270        if (cal.equals(cal2)
271                || cal2.before(cal)
272                || cal.after(cal2)) {
273            errln("FAIL: equals/before/after failed");
274        }
275
276        // C++ only
277        /* TimeZone z = cal.orphanTimeZone();
278        if (z.getID(str) != tzid ||
279        z.getRawOffset() != tzoffset)
280        errln("FAIL: orphanTimeZone failed");
281        */
282        for (int i = 0; i < 2; ++i) {
283            boolean lenient = (i > 0);
284            cal.setLenient(lenient);
285            if (lenient != cal.isLenient()) {
286                errln("FAIL: setLenient/isLenient failed");
287            }
288            // Later: Check for lenient behavior
289        }
290
291        int i;
292        for (i = SUNDAY; i <= SATURDAY; ++i) {
293            cal.setFirstDayOfWeek(i);
294            if (cal.getFirstDayOfWeek() != i) {
295                errln("FAIL: set/getFirstDayOfWeek failed");
296            }
297        }
298
299        for (i = 0; i <= 7; ++i) {
300            cal.setMinimalDaysInFirstWeek(i);
301            if (cal.getMinimalDaysInFirstWeek() != i) {
302                errln("FAIL: set/getFirstDayOfWeek failed");
303            }
304        }
305
306        for (i = 0; i < FIELD_COUNT; ++i) {
307            if (cal.getMinimum(i) != cal.getGreatestMinimum(i)) {
308                errln("FAIL: getMinimum doesn't match getGreatestMinimum for field " + i);
309            }
310            if (cal.getLeastMaximum(i) > cal.getMaximum(i)) {
311                errln("FAIL: getLeastMaximum larger than getMaximum for field " + i);
312            }
313            if (cal.getMinimum(i) >= cal.getMaximum(i)) {
314                errln("FAIL: getMinimum not less than getMaximum for field " + i);
315            }
316        }
317
318        cal.setTimeZone(TimeZone.getDefault());
319        cal.clear();
320        cal.set(1984, 5, 24);
321        if (cal.getTime().getTime() != new Date(84, 5, 24).getTime()) {
322            errln("FAIL: Calendar.set(3 args) failed");
323            logln(" Got: " + cal.getTime() + "  Expected: " + new Date(84, 5, 24));
324        }
325
326        cal.clear();
327        cal.set(1985, 3, 2, 11, 49);
328        if (cal.getTime().getTime() != new Date(85, 3, 2, 11, 49).getTime()) {
329            errln("FAIL: Calendar.set(5 args) failed");
330            logln(" Got: " + cal.getTime() + "  Expected: " + new Date(85, 3, 2, 11, 49));
331        }
332
333        cal.clear();
334        cal.set(1995, 9, 12, 1, 39, 55);
335        if (cal.getTime().getTime() != new Date(95, 9, 12, 1, 39, 55).getTime()) {
336            errln("FAIL: Calendar.set(6 args) failed");
337            logln(" Got: " + cal.getTime() + "  Expected: " + new Date(95, 9, 12, 1, 39, 55));
338        }
339
340        cal.getTime();
341        for (i = 0; i < FIELD_COUNT; ++i) {
342            switch (i) {
343                case YEAR:
344                case MONTH:
345                case DATE:
346                case HOUR_OF_DAY:
347                case MINUTE:
348                case SECOND:
349                    if (!cal.isSet(i)) {
350                        errln("FAIL: !Calendar.isSet test failed: " + calendarFieldNames[i]);
351                    }
352                    break;
353                default:
354                    if (cal.isSet(i)) {
355                        errln("FAIL: Calendar.isSet test failed: " + calendarFieldNames[i]);
356                    }
357            }
358            cal.clear(i);
359            if (cal.isSet(i)) {
360                errln("FAIL: Calendar.clear/isSet failed");
361            }
362        }
363
364        // delete cal;
365        // delete cal2;
366        Locale[] loc = Calendar.getAvailableLocales();
367        long count = loc.length;
368        if (count < 1 || loc == null) {
369            errln("FAIL: getAvailableLocales failed");
370        } else {
371            for (i = 0; i < count; ++i) {
372                cal = Calendar.getInstance(loc[i]);
373                // delete cal;
374            }
375        }
376
377        cal = Calendar.getInstance(TimeZone.getDefault(), Locale.ENGLISH);
378        // delete cal;
379
380        cal = Calendar.getInstance(zone, Locale.ENGLISH);
381        // delete cal;
382
383        GregorianCalendar gc = new GregorianCalendar(zone);
384        // delete gc;
385
386        gc = new GregorianCalendar(Locale.ENGLISH);
387        // delete gc;
388
389        gc = new GregorianCalendar(Locale.ENGLISH);
390        // delete gc;
391
392        gc = new GregorianCalendar(zone, Locale.ENGLISH);
393        // delete gc;
394
395        gc = new GregorianCalendar(zone);
396        // delete gc;
397
398        gc = new GregorianCalendar(1998, 10, 14, 21, 43);
399        if (gc.getTime().getTime() != new Date(98, 10, 14, 21, 43).getTime()) {
400            errln("FAIL: new GregorianCalendar(ymdhm) failed");
401        }
402        // delete gc;
403
404        gc = new GregorianCalendar(1998, 10, 14, 21, 43, 55);
405        if (gc.getTime().getTime() != new Date(98, 10, 14, 21, 43, 55).getTime()) {
406            errln("FAIL: new GregorianCalendar(ymdhms) failed");
407        }
408
409        // C++ only:
410        // GregorianCalendar gc2 = new GregorianCalendar(Locale.ENGLISH);
411        // gc2 = gc;
412        // if (gc2 != gc || !(gc2 == gc)) errln("FAIL: GregorianCalendar assignment/operator==/operator!= failed");
413        // delete gc;
414        // delete z;
415    }
416
417    // Verify Roger Webster's bug
418    public void TestRog() {
419        GregorianCalendar gc = new GregorianCalendar();
420
421        int year = 1997, month = APRIL, date = 1;
422        gc.set(year, month, date); // April 1, 1997
423
424        gc.set(HOUR_OF_DAY, 23);
425        gc.set(MINUTE, 0);
426        gc.set(SECOND, 0);
427        gc.set(MILLISECOND, 0);
428
429        for (int i = 0; i < 9; i++, gc.add(DATE, 1)) {
430            if (gc.get(YEAR) != year
431                    || gc.get(MONTH) != month
432                    || gc.get(DATE) != (date + i)) {
433                errln("FAIL: Date " + gc.getTime() + " wrong");
434            }
435        }
436    }
437
438    // Verify DAY_OF_WEEK
439    public void TestDOW943() {
440        dowTest(false);
441        dowTest(true);
442    }
443
444    void dowTest(boolean lenient) {
445        GregorianCalendar cal = new GregorianCalendar();
446        cal.set(1997, AUGUST, 12); // Wednesday
447        cal.getTime(); // Force update
448        cal.setLenient(lenient);
449        cal.set(1996, DECEMBER, 1); // Set the date to be December 1, 1996
450        int dow = cal.get(DAY_OF_WEEK);
451        int min = cal.getMinimum(DAY_OF_WEEK);
452        int max = cal.getMaximum(DAY_OF_WEEK);
453        if (dow < min || dow > max) {
454            errln("FAIL: Day of week " + dow + " out of range");
455        }
456        if (dow != SUNDAY) {
457            errln("FAIL2: Day of week should be SUNDAY; is " + dow + ": " + cal.getTime());
458        }
459        if (min != SUNDAY || max != SATURDAY) {
460            errln("FAIL: Min/max bad");
461        }
462    }
463
464    // Verify that the clone method produces distinct objects with no
465    // unintentionally shared fields.
466    public void TestClonesUnique908() {
467        Calendar c = Calendar.getInstance();
468        Calendar d = (Calendar) c.clone();
469        c.set(MILLISECOND, 123);
470        d.set(MILLISECOND, 456);
471        if (c.get(MILLISECOND) != 123
472                || d.get(MILLISECOND) != 456) {
473            errln("FAIL: Clones share fields");
474        }
475    }
476
477    // Verify effect of Gregorian cutoff value
478    @SuppressWarnings("deprecation")
479    public void TestGregorianChange768() {
480        boolean b;
481        GregorianCalendar c = new GregorianCalendar();
482        logln("With cutoff " + c.getGregorianChange());
483        logln(" isLeapYear(1800) = " + (b = c.isLeapYear(1800)));
484        logln(" (should be FALSE)");
485        if (b != false) {
486            errln("FAIL");
487        }
488        c.setGregorianChange(new Date(0, 0, 1)); // Jan 1 1900
489        logln("With cutoff " + c.getGregorianChange());
490        logln(" isLeapYear(1800) = " + (b = c.isLeapYear(1800)));
491        logln(" (should be TRUE)");
492        if (b != true) {
493            errln("FAIL");
494        }
495    }
496
497    // Test the correct behavior of the disambiguation algorithm.
498    public void TestDisambiguation765() throws Exception {
499        Locale savedLocale = Locale.getDefault();
500        try {
501            Locale.setDefault(Locale.US);
502            Calendar c = Calendar.getInstance();
503            c.setLenient(false);
504
505            c.clear();
506            c.set(YEAR, 1997);
507            c.set(MONTH, JUNE);
508            c.set(DATE, 3);
509
510            verify765("1997 third day of June = ", c, 1997, JUNE, 3);
511
512            c.clear();
513            c.set(YEAR, 1997);
514            c.set(DAY_OF_WEEK, TUESDAY);
515            c.set(MONTH, JUNE);
516            c.set(DAY_OF_WEEK_IN_MONTH, 1);
517            verify765("1997 first Tuesday in June = ", c, 1997, JUNE, 3);
518
519            c.setLenient(true); // for 4944795
520            c.clear();
521            c.set(YEAR, 1997);
522            c.set(DAY_OF_WEEK, TUESDAY);
523            c.set(MONTH, JUNE);
524            c.set(DAY_OF_WEEK_IN_MONTH, -1);
525            verify765("1997 last Tuesday in June = ", c, 1997, JUNE, 24);
526
527            c.setLenient(false);
528            IllegalArgumentException e = null;
529            try {
530                c.clear();
531                c.set(YEAR, 1997);
532                c.set(DAY_OF_WEEK, TUESDAY);
533                c.set(MONTH, JUNE);
534                c.set(DAY_OF_WEEK_IN_MONTH, 0);
535                c.getTime();
536            } catch (IllegalArgumentException ex) {
537                e = ex;
538            }
539            verify765("1997 zero-th Tuesday in June = ", e);
540
541            c.clear();
542            c.set(YEAR, 1997);
543            c.set(DAY_OF_WEEK, TUESDAY);
544            c.set(MONTH, JUNE);
545            c.set(WEEK_OF_MONTH, 1);
546            verify765("1997 Tuesday in week 1 of June = ", c, 1997, JUNE, 3);
547
548            c.clear();
549            c.set(YEAR, 1997);
550            c.set(DAY_OF_WEEK, TUESDAY);
551            c.set(MONTH, JUNE);
552            c.set(WEEK_OF_MONTH, 4);
553            verify765("1997 Tuesday in week 4 of June = ", c, 1997, JUNE, 24);
554
555            try {
556                c.clear();
557                c.set(YEAR, 1997);
558                c.set(DAY_OF_WEEK, TUESDAY);
559                c.set(MONTH, JUNE);
560                c.set(WEEK_OF_MONTH, 1);
561                verify765("1997 Tuesday in week 0 of June = ", c, 1997, JUNE, 3);
562            } catch (IllegalArgumentException ex) {
563                errln("FAIL: Exception seen: " + ex.getMessage());
564                // ex.printStackTrace(log);
565            }
566
567            c.clear();
568            c.set(YEAR, 1997);
569            c.set(DAY_OF_WEEK, TUESDAY);
570            c.set(WEEK_OF_YEAR, 2);
571            verify765("1997 Tuesday in week 2 of year = ", c, 1997, JANUARY, 7);
572
573            c.clear();
574            c.set(YEAR, 1997);
575            c.set(DAY_OF_WEEK, TUESDAY);
576            c.set(WEEK_OF_YEAR, 10);
577            verify765("1997 Tuesday in week 10 of year = ", c, 1997, MARCH, 4);
578
579            try {
580                c.clear();
581                c.set(YEAR, 1997);
582                c.set(DAY_OF_WEEK, TUESDAY);
583                c.set(WEEK_OF_YEAR, 0);
584                verify765("1997 Tuesday in week 0 of year = ", c, 1996, DECEMBER, 24);
585                throw new Exception("Fail: WEEK_OF_YEAR 0 should be illegal");
586            } catch (IllegalArgumentException ex) {
587            }
588        } finally {
589            Locale.setDefault(savedLocale);
590        }
591    }
592
593    void verify765(String msg, Calendar c, int year, int month, int day) {
594        if (c.get(YEAR) == year
595                && c.get(MONTH) == month
596                && c.get(DATE) == day) {
597            logln("PASS: " + msg + c.getTime());
598        } else {
599            errln("FAIL: " + msg + c.getTime()
600                    + "; expected "
601                    + year + "/" + (month + 1) + "/" + day);
602        }
603    }
604
605    // Called when e expected to be non-null
606    void verify765(String msg, IllegalArgumentException e) {
607        if (e == null) {
608            errln("FAIL: No IllegalArgumentException for " + msg);
609        } else {
610            logln("PASS: " + msg + "IllegalArgument as expected");
611        }
612    }
613
614    // Test the behavior of GMT vs. local time
615    public void TestGMTvsLocal4064654() {
616        Locale locale = Locale.getDefault();
617        if (!TestUtils.usesGregorianCalendar(locale)) {
618            logln("Skipping this test because locale is " + locale);
619            return;
620        }
621
622        // Sample output 1:
623        // % /usr/local/java/jdk1.1.3/solaris/bin/java test 1997 1 1 12 0 0
624        // date = Wed Jan 01 04:00:00 PST 1997
625        // offset for Wed Jan 01 04:00:00 PST 1997= -8hr
626        test4064654(1997, 1, 1, 12, 0, 0);
627
628        // Sample output 2:
629        // % /usr/local/java/jdk1.1.3/solaris/bin/java test 1997 4 16 18 30 0
630        // date = Wed Apr 16 10:30:00 PDT 1997
631        // offset for Wed Apr 16 10:30:00 PDT 1997= -7hr
632
633        // Note that in sample output 2 according to the offset, the gmt time
634        // of the result would be 1997 4 16 17 30 0 which is different from the
635        // input of 1997 4 16 18 30 0.
636        test4064654(1997, 4, 16, 18, 30, 0);
637    }
638    void test4064654(int yr, int mo, int dt, int hr, int mn, int sc) {
639        Date date;
640        Calendar gmtcal = Calendar.getInstance();
641        gmtcal.setTimeZone(TimeZone.getTimeZone("Africa/Casablanca"));
642        gmtcal.set(yr, mo - 1, dt, hr, mn, sc);
643        gmtcal.set(MILLISECOND, 0);
644
645        date = gmtcal.getTime();
646        logln("date = " + date);
647
648        Calendar cal = Calendar.getInstance();
649        cal.setTimeZone(TimeZone.getTimeZone("America/Los_Angeles"));
650        cal.setTime(date);
651
652        int offset = cal.getTimeZone().getOffset(cal.get(ERA),
653                cal.get(YEAR),
654                cal.get(MONTH),
655                cal.get(DATE),
656                cal.get(DAY_OF_WEEK),
657                cal.get(MILLISECOND));
658
659        logln("offset for " + date + "= " + (offset / 1000 / 60 / 60.0) + "hr");
660
661        int utc = ((cal.get(HOUR_OF_DAY) * 60
662                + cal.get(MINUTE)) * 60
663                + cal.get(SECOND)) * 1000
664                + cal.get(MILLISECOND) - offset;
665
666        int expected = ((hr * 60 + mn) * 60 + sc) * 1000;
667
668        if (utc != expected) {
669            errln("FAIL: Discrepancy of "
670                    + (utc - expected) + " millis = "
671                    + ((utc - expected) / 1000 / 60 / 60.0) + " hr");
672        }
673    }
674
675    // Verify that add and set work regardless of the order in which
676    // they are called.
677    public void TestAddSetOrder621() {
678        @SuppressWarnings("deprecation")
679        Date d = new Date(97, 4, 14, 13, 23, 45);
680
681        Calendar cal = Calendar.getInstance();
682        cal.setTime(d);
683        cal.add(DATE, -5);
684        cal.set(HOUR_OF_DAY, 0);
685        cal.set(MINUTE, 0);
686        cal.set(SECOND, 0);
687        // ma feb 03 00:00:00 GMT+00:00 1997
688        String s = cal.getTime().toString();
689
690        cal = Calendar.getInstance();
691        cal.setTime(d);
692        cal.set(HOUR_OF_DAY, 0);
693        cal.set(MINUTE, 0);
694        cal.set(SECOND, 0);
695        cal.add(DATE, -5);
696        // ma feb 03 13:11:06 GMT+00:00 1997
697        String s2 = cal.getTime().toString();
698
699        if (s.equals(s2)) {
700            logln("Pass: " + s + " == " + s2);
701        } else {
702            errln("FAIL: " + s + " != " + s2);
703        }
704    }
705
706    // Verify that add works.
707    public void TestAdd520() {
708        int y = 1997, m = FEBRUARY, d = 1;
709        GregorianCalendar temp = new GregorianCalendar(y, m, d);
710        check520(temp, y, m, d);
711
712        temp.add(YEAR, 1);
713        y++;
714        check520(temp, y, m, d);
715
716        temp.add(MONTH, 1);
717        m++;
718        check520(temp, y, m, d);
719
720        temp.add(DATE, 1);
721        d++;
722        check520(temp, y, m, d);
723
724        temp.add(DATE, 2);
725        d += 2;
726        check520(temp, y, m, d);
727
728        temp.add(DATE, 28);
729        d = 1;
730        ++m;
731        check520(temp, y, m, d);
732    }
733
734    void check520(Calendar c, int y, int m, int d) {
735        if (c.get(YEAR) != y
736                || c.get(MONTH) != m
737                || c.get(DATE) != d) {
738            errln("FAILURE: Expected YEAR/MONTH/DATE of "
739                    + y + "/" + (m + 1) + "/" + d
740                    + "; got "
741                    + c.get(YEAR) + "/"
742                    + (c.get(MONTH) + 1) + "/"
743                    + c.get(DATE));
744        } else {
745            logln("Confirmed: "
746                    + y + "/" + (m + 1) + "/" + d);
747        }
748    }
749
750    // Verify that setting fields works.  This test fails when an exception is thrown.
751    public void TestFieldSet4781() {
752        try {
753            GregorianCalendar g = new GregorianCalendar();
754            GregorianCalendar g2 = new GregorianCalendar();
755            // At this point UTC value is set, various fields are not.
756            // Now set to noon.
757            g2.set(HOUR, 12);
758            g2.set(MINUTE, 0);
759            g2.set(SECOND, 0);
760            // At this point the object thinks UTC is NOT set, but fields are set.
761            // The following line will result in IllegalArgumentException because
762            // it thinks the YEAR is set and it is NOT.
763            if (g2.equals(g)) {
764                logln("Same");
765            } else {
766                logln("Different");
767            }
768        } catch (IllegalArgumentException e) {
769            errln("Unexpected exception seen: " + e);
770        }
771    }
772
773    // Test serialization of a Calendar object
774    public void TestSerialize337() {
775        Calendar cal = Calendar.getInstance();
776
777        boolean ok = false;
778
779        try {
780            FileOutputStream f = new FileOutputStream(FILENAME);
781            ObjectOutput s = new ObjectOutputStream(f);
782            s.writeObject(PREFIX);
783            s.writeObject(cal);
784            s.writeObject(POSTFIX);
785            f.close();
786
787            FileInputStream in = new FileInputStream(FILENAME);
788            ObjectInputStream t = new ObjectInputStream(in);
789            String pre = (String) t.readObject();
790            Calendar c = (Calendar) t.readObject();
791            String post = (String) t.readObject();
792            in.close();
793
794            ok = pre.equals(PREFIX)
795                    && post.equals(POSTFIX)
796                    && cal.equals(c);
797
798            File fl = new File(FILENAME);
799            fl.delete();
800        } catch (IOException e) {
801            errln("FAIL: Exception received:");
802            // e.printStackTrace(log);
803        } catch (ClassNotFoundException e) {
804            errln("FAIL: Exception received:");
805            // e.printStackTrace(log);
806        }
807
808        if (!ok) {
809            errln("Serialization of Calendar object failed.");
810        }
811    }
812    static final String PREFIX = "abc";
813    static final String POSTFIX = "def";
814    static final String FILENAME = "tmp337.bin";
815
816    // Try to zero out the seconds field
817    public void TestSecondsZero121() {
818        Calendar cal = new GregorianCalendar();
819        // Initialize with current date/time
820        cal.setTime(new Date());
821        // Round down to minute
822        cal.set(SECOND, 0);
823        Date d = cal.getTime();
824        String s = d.toString();
825        if (s.indexOf(":00 ") < 0) {
826            errln("Expected to see :00 in " + s);
827        }
828    }
829
830    // Try various sequences of add, set, and get method calls.
831    public void TestAddSetGet0610() {
832        //
833        // Error case 1:
834        // - Upon initialization calendar fields, millis = System.currentTime
835        // - After set is called fields are initialized, time is not
836        // - Addition uses millis which are still *now*
837        //
838        {
839            Calendar calendar = new GregorianCalendar();
840            calendar.set(1993, JANUARY, 4);
841            logln("1A) " + value(calendar));
842            calendar.add(DATE, 1);
843            String v = value(calendar);
844            logln("1B) " + v);
845            logln("--) 1993/0/5");
846            if (!v.equals(EXPECTED_0610)) {
847                errln("Expected " + EXPECTED_0610
848                        + "; saw " + v);
849            }
850        }
851
852        //
853        // Error case 2:
854        // - Upon initialization calendar fields set, millis = 0
855        // - Addition uses millis which are still 1970, 0, 1
856        //
857        {
858            Calendar calendar = new GregorianCalendar(1993, JANUARY, 4);
859            logln("2A) " + value(calendar));
860            calendar.add(DATE, 1);
861            String v = value(calendar);
862            logln("2B) " + v);
863            logln("--) 1993/0/5");
864            if (!v.equals(EXPECTED_0610)) {
865                errln("Expected " + EXPECTED_0610
866                        + "; saw " + v);
867            }
868        }
869
870        //
871        // Error case 3:
872        // - Upon initialization calendar fields, millis = 0
873        // - getTime( ) is called which forces the millis to be set
874        // - Addition uses millis which are correct
875        //
876        {
877            Calendar calendar = new GregorianCalendar(1993, JANUARY, 4);
878            logln("3A) " + value(calendar));
879            calendar.getTime();
880            calendar.add(DATE, 1);
881            String v = value(calendar);
882            logln("3B) " + v);
883            logln("--) 1993/0/5");
884            if (!v.equals(EXPECTED_0610)) {
885                errln("Expected " + EXPECTED_0610
886                        + "; saw " + v);
887            }
888        }
889    }
890    static String value(Calendar calendar) {
891        return (calendar.get(YEAR) + "/"
892                + calendar.get(MONTH) + "/"
893                + calendar.get(DATE));
894    }
895    static String EXPECTED_0610 = "1993/0/5";
896
897    // Test that certain fields on a certain date are as expected.
898    public void TestFields060() {
899        int year = 1997;
900        int month = OCTOBER;  //october
901        int dDate = 22;   //DAYOFWEEK should return 3 for Wednesday
902        GregorianCalendar calendar = null;
903
904        calendar = new GregorianCalendar(year, month, dDate);
905        for (int i = 0; i < EXPECTED_FIELDS.length;) {
906            int field = EXPECTED_FIELDS[i++];
907            int expected = EXPECTED_FIELDS[i++];
908            if (calendar.get(field) != expected) {
909                errln("Expected field " + field + " to have value " + expected
910                        + "; received " + calendar.get(field) + " instead");
911            }
912        }
913    }
914    static int[] EXPECTED_FIELDS = {
915        YEAR, 1997,
916        MONTH, OCTOBER,
917        DAY_OF_MONTH, 22,
918        DAY_OF_WEEK, WEDNESDAY,
919        DAY_OF_WEEK_IN_MONTH, 4,
920        DAY_OF_YEAR, 295};
921
922    static final String[] calendarFieldNames = {
923        /*  0 */ "ERA",
924        /*  1 */ "YEAR",
925        /*  2 */ "MONTH",
926        /*  3 */ "WEEK_OF_YEAR",
927        /*  4 */ "WEEK_OF_MONTH",
928        /*  5 */ "DAY_OF_MONTH",
929        /*  6 */ "DAY_OF_YEAR",
930        /*  7 */ "DAY_OF_WEEK",
931        /*  8 */ "DAY_OF_WEEK_IN_MONTH",
932        /*  9 */ "AM_PM",
933        /* 10 */ "HOUR",
934        /* 11 */ "HOUR_OF_DAY",
935        /* 12 */ "MINUTE",
936        /* 13 */ "SECOND",
937        /* 14 */ "MILLISECOND",
938        /* 15 */ "ZONE_OFFSET",
939        /* 16 */ "DST_OFFSET"};
940
941    // Verify that the fields are as expected (mostly zero) at the epoch start.
942    // Note that we adjust for the default timezone to get most things to zero.
943    public void TestEpochStartFields() {
944        String[][] lt = {
945            {"en", "US", "US/Pacific"},        /* First day = 1, Minimum day = 1 */
946            {"en", "US", "America/Anchorage"}, /* First day = 1, Minimum day = 1 */
947            {"en", "TO", "Pacific/Tongatapu"}, /* First day = 1, Minimum day = 1 */
948            {"en", "MH", "Pacific/Majuro"},    /* First day = 1, Minimum day = 1 */
949            {"ja", "JP", "Asia/Tokyo"},        /* First day = 1, Minimum day = 1 */
950            {"iw", "IL", "Asia/Jerusalem"},    /* First day = 1, Minimum day = 1 */
951            {"hi", "IN", "Asia/Jakarta"},      /* First day = 1, Minimum day = 1 */
952            {"en", "GB", "Europe/London"},     /* First day = 2, Minimum day = 1 */
953            {"en", "GB", "GMT"},               /* First day = 2, Minimum day = 1 */
954            {"de", "DE", "Europe/Berlin"},     /* First day = 2, Minimum day = 4 */
955            {"ar", "EG", "Africa/Cairo"}};     /* First day = 7, Minimum day = 1 */
956
957        int[][] goldenData = {
958            {1, 1970, 0, 1, 1, 1, 1, 5, 1, 0, 0, 0, 0, 0, 0, -28800000, 0},
959            {1, 1969, 11, 1, 5, 31, 365, 4, 5, 1, 11, 23, 0, 0, 0, -36000000, 0},
960            {1, 1970, 0, 1, 1, 1, 1, 5, 1, 0, 0, 0, 0, 0, 0, 46800000, 0},
961            {1, 1970, 0, 1, 1, 1, 1, 5, 1, 0, 0, 0, 0, 0, 0, 43200000, 0},
962            {1, 1970, 0, 1, 1, 1, 1, 5, 1, 0, 0, 0, 0, 0, 0, 32400000, 0},
963            {1, 1970, 0, 1, 1, 1, 1, 5, 1, 0, 0, 0, 0, 0, 0, 7200000, 0},
964            {1, 1970, 0, 1, 1, 1, 1, 5, 1, 0, 0, 0, 0, 0, 0, 25200000, 0},
965            {1, 1970, 0, 1, 1, 1, 1, 5, 1, 0, 1, 1, 0, 0, 0, 3600000, 0},
966            {1, 1970, 0, 1, 1, 1, 1, 5, 1, 0, 0, 0, 0, 0, 0, 0, 0},
967            {1, 1970, 0, 1, 1, 1, 1, 5, 1, 0, 0, 0, 0, 0, 0, 3600000, 0},
968            {1, 1970, 0, 1, 1, 1, 1, 5, 1, 0, 0, 0, 0, 0, 0, 7200000, 0}};
969
970        Locale savedLocale = Locale.getDefault();
971        TimeZone savedTimeZone = TimeZone.getDefault();
972
973        try {
974            for (int j = 0; j < lt.length; j++) {
975                Locale l = new Locale(lt[j][0], lt[j][1]);
976                TimeZone z = TimeZone.getTimeZone(lt[j][2]);
977                Locale.setDefault(l);
978                TimeZone.setDefault(z);
979                Calendar c = Calendar.getInstance();
980                Date d = new Date(-z.getRawOffset());
981
982                int val;
983                int[] EPOCH_FIELDS = goldenData[j];
984                c.setTime(d);
985
986                boolean err = false;
987                for (int i = 0; i < calendarFieldNames.length; ++i) {
988                    if ((val = c.get(i)) != EPOCH_FIELDS[i]) {
989                        errln("Wrong value: " + val
990                                + " for field(" + calendarFieldNames[i]
991                                + "), expected: " + EPOCH_FIELDS[i]);
992                        err = true;
993                    }
994                }
995                if (err) {
996                    errln("Failed: \n\tDate=" + d + "\n\tTimeZone=" + z
997                            + "\n\tLocale=" + l + "\n\tCalendar=" + c);
998                }
999            }
1000        } finally {
1001            Locale.setDefault(savedLocale);
1002            TimeZone.setDefault(savedTimeZone);
1003        }
1004    }
1005
1006    // Verify that as you add days to the calendar (e.g., 24 day periods),
1007    // the day of the week shifts in the expected pattern.
1008    public void TestDOWProgression() {
1009        Calendar cal
1010                = new GregorianCalendar(1972, OCTOBER, 26);
1011        marchByDelta(cal, 24); // Last parameter must be != 0 modulo 7
1012    }
1013
1014    // Supply a delta which is not a multiple of 7.
1015    void marchByDelta(Calendar cal, int delta) {
1016        Calendar cur = (Calendar) cal.clone();
1017        int initialDOW = cur.get(DAY_OF_WEEK);
1018        int DOW, newDOW = initialDOW;
1019        do {
1020            DOW = newDOW;
1021            logln("DOW = " + DOW + "  " + cur.getTime());
1022
1023            cur.add(DAY_OF_WEEK, delta);
1024            newDOW = cur.get(DAY_OF_WEEK);
1025            int expectedDOW = 1 + (DOW + delta - 1) % 7;
1026            if (newDOW != expectedDOW) {
1027                errln("Day of week should be " + expectedDOW
1028                        + " instead of " + newDOW + " on " + cur.getTime());
1029                return;
1030            }
1031        } while (newDOW != initialDOW);
1032    }
1033
1034    public void TestActualMinMax() {
1035        Calendar cal = new GregorianCalendar(1967, MARCH, 10);
1036        cal.setFirstDayOfWeek(SUNDAY);
1037        cal.setMinimalDaysInFirstWeek(3);
1038
1039        if (cal.getActualMinimum(DAY_OF_MONTH) != 1) {
1040            errln("Actual minimum date for 3/10/1967 should have been 1; got "
1041                    + cal.getActualMinimum(DAY_OF_MONTH));
1042        }
1043        if (cal.getActualMaximum(DAY_OF_MONTH) != 31) {
1044            errln("Actual maximum date for 3/10/1967 should have been 31; got "
1045                    + cal.getActualMaximum(DAY_OF_MONTH));
1046        }
1047
1048        cal.set(MONTH, FEBRUARY);
1049        if (cal.getActualMaximum(DAY_OF_MONTH) != 28) {
1050            errln("Actual maximum date for 2/10/1967 should have been 28; got "
1051                    + cal.getActualMaximum(DAY_OF_MONTH));
1052        }
1053        if (cal.getActualMaximum(DAY_OF_YEAR) != 365) {
1054            errln("Number of days in 1967 should have been 365; got "
1055                    + cal.getActualMaximum(DAY_OF_YEAR));
1056        }
1057
1058        cal.set(YEAR, 1968);
1059        if (cal.getActualMaximum(DAY_OF_MONTH) != 29) {
1060            errln("Actual maximum date for 2/10/1968 should have been 29; got "
1061                    + cal.getActualMaximum(DAY_OF_MONTH));
1062        }
1063        if (cal.getActualMaximum(DAY_OF_YEAR) != 366) {
1064            errln("Number of days in 1968 should have been 366; got "
1065                    + cal.getActualMaximum(DAY_OF_YEAR));
1066        }
1067        // Using week settings of SUNDAY/3 (see above)
1068        if (cal.getActualMaximum(WEEK_OF_YEAR) != 52) {
1069            errln("Number of weeks in 1968 should have been 52; got "
1070                    + cal.getActualMaximum(WEEK_OF_YEAR));
1071        }
1072
1073        cal.set(YEAR, 1976);
1074        // Using week settings of SUNDAY/3 (see above)
1075        if (cal.getActualMaximum(WEEK_OF_YEAR) != 53) {
1076            errln("Number of weeks in 1976 should have been 53; got "
1077                    + cal.getActualMaximum(WEEK_OF_YEAR));
1078        }
1079    }
1080
1081    public void TestRoll() {
1082        Calendar cal = new GregorianCalendar(1997, JANUARY, 31);
1083
1084        int[] dayValues = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 31};
1085
1086        for (int i = 0; i < dayValues.length; i++) {
1087            Calendar cal2 = (Calendar) cal.clone();
1088            cal2.roll(MONTH, i);
1089            if (cal2.get(DAY_OF_MONTH) != dayValues[i]) {
1090                errln("Rolling the month in 1/31/1997 up by " + i + " should have yielded "
1091                        + ((i + 1) % 12) + "/" + dayValues[i] + "/1997, but actually yielded "
1092                        + ((i + 1) % 12) + "/" + cal2.get(DAY_OF_MONTH) + "/1997.");
1093            }
1094        }
1095
1096        cal.set(1996, FEBRUARY, 29);
1097
1098        int[] monthValues = {1, 2, 2, 2, 1, 2, 2, 2, 1, 2};
1099        int[] dayValues2 = {29, 1, 1, 1, 29, 1, 1, 1, 29, 1};
1100
1101        for (int i = 0; i < dayValues2.length; i++) {
1102            Calendar cal2 = (Calendar) cal.clone();
1103            cal2.roll(YEAR, i);
1104            if (cal2.get(DAY_OF_MONTH) != dayValues2[i] || cal2.get(MONTH)
1105                    != monthValues[i]) {
1106                errln("Rolling the year in 2/29/1996 up by " + i + " should have yielded "
1107                        + (monthValues[i] + 1) + "/" + dayValues2[i] + "/"
1108                        + (1996 + i) + ", but actually yielded "
1109                        + (cal2.get(MONTH) + 1) + "/"
1110                        + cal2.get(DAY_OF_MONTH) + "/" + (1996 + i) + ".");
1111            }
1112        }
1113
1114        // Test rolling hour of day
1115        cal.set(HOUR_OF_DAY, 0);
1116        cal.roll(HOUR_OF_DAY, -2);
1117        int f = cal.get(HOUR_OF_DAY);
1118        if (f != 22) {
1119            errln("Rolling HOUR_OF_DAY=0 delta=-2 gave " + f + " Wanted 22");
1120        }
1121        cal.roll(HOUR_OF_DAY, 5);
1122        f = cal.get(HOUR_OF_DAY);
1123        if (f != 3) {
1124            errln("Rolling HOUR_OF_DAY=22 delta=5 gave " + f + " Wanted 3");
1125        }
1126        cal.roll(HOUR_OF_DAY, 21);
1127        f = cal.get(HOUR_OF_DAY);
1128        if (f != 0) {
1129            errln("Rolling HOUR_OF_DAY=3 delta=21 gave " + f + " Wanted 0");
1130        }
1131
1132        // Test rolling hour
1133        cal.set(HOUR_OF_DAY, 0);
1134        cal.roll(HOUR, -2);
1135        f = cal.get(HOUR);
1136        if (f != 10) {
1137            errln("Rolling HOUR=0 delta=-2 gave " + f + " Wanted 10");
1138        }
1139        cal.roll(HOUR, 5);
1140        f = cal.get(HOUR);
1141        if (f != 3) {
1142            errln("Rolling HOUR=10 delta=5 gave " + f + " Wanted 3");
1143        }
1144        cal.roll(HOUR, 9);
1145        f = cal.get(HOUR);
1146        if (f != 0) {
1147            errln("Rolling HOUR=3 delta=9 gave " + f + " Wanted 0");
1148        }
1149    }
1150
1151    /*
1152     * Confirm that multiple calls to Calendar.set() works correctly.
1153     */
1154    public void Test4374886() {
1155        Locale savedLocale = Locale.getDefault();
1156        TimeZone savedTimeZone = TimeZone.getDefault();
1157
1158        try {
1159            Locale.setDefault(Locale.US);
1160            TimeZone.setDefault(TimeZone.getTimeZone("PST"));
1161
1162            Calendar cal = Calendar.getInstance();
1163            cal.set(YEAR, 2001);
1164            cal.set(MONTH, OCTOBER);
1165            cal.set(WEEK_OF_YEAR, 4);
1166            cal.set(DAY_OF_WEEK, 2);
1167
1168            if (cal.get(YEAR) != 2001
1169                    || cal.get(MONTH) != JANUARY
1170                    || cal.get(DATE) != 22
1171                    || cal.get(DAY_OF_WEEK) != MONDAY) {
1172                errln("Failed : got " + cal.getTime() + ", expected Mon Jan 22, 2001");
1173            }
1174        } finally {
1175            Locale.setDefault(savedLocale);
1176            TimeZone.setDefault(savedTimeZone);
1177        }
1178    }
1179}
1180
1181//eof
1182