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