1 /*
   2  * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 /*
  25  * @test
  26  * @bug 4359204 4928615 4743587 4956232 6459836 6549953
  27  * @library /java/text/testlib
  28  * @build Koyomi
  29  * @run main GregorianCutoverTest
  30  * @summary Unit tests related to the Gregorian cutover support.
  31  */
  32 
  33 import java.util.Date;
  34 import java.util.Locale;
  35 import java.util.TimeZone;
  36 
  37 import static java.util.GregorianCalendar.*;
  38 
  39 public class GregorianCutoverTest extends IntlTest {
  40 
  41     public static void main(String[] args) throws Exception {
  42         TimeZone tz = TimeZone.getDefault();
  43         Locale lc = Locale.getDefault();
  44         try {
  45             TimeZone.setDefault(TimeZone.getTimeZone("GMT"));
  46             Locale.setDefault(Locale.US);
  47 
  48             new GregorianCutoverTest().run(args);
  49         } finally {
  50             TimeZone.setDefault(tz);
  51             Locale.setDefault(lc);
  52         }
  53     }
  54 
  55     /**
  56      * 4359204: GregorianCalendar.get(cal.DAY_OF_YEAR) is inconsistent for year 1582
  57      */
  58     public void Test4359204() {
  59         Koyomi cal = new Koyomi();
  60 
  61         cal.set(1582, JANUARY, 1);
  62         checkContinuity(cal, DAY_OF_YEAR);
  63         checkContinuity(cal, WEEK_OF_YEAR);
  64         cal.set(1582, OCTOBER, 1);
  65         checkContinuity(cal, WEEK_OF_MONTH);
  66 
  67         // JCK tests the cutover date 1970-1-1 (Epoch)
  68         cal.setGregorianChange(new Date(0));
  69         cal.set(1969, JANUARY, 1);
  70         checkContinuity(cal, DAY_OF_YEAR);
  71         checkContinuity(cal, WEEK_OF_YEAR);
  72         cal.set(1969, DECEMBER, 1);
  73         checkContinuity(cal, WEEK_OF_MONTH);
  74         cal.set(1970, JANUARY, 1);
  75         checkContinuity(cal, DAY_OF_YEAR);
  76         checkContinuity(cal, WEEK_OF_YEAR);
  77 
  78         // Use large date (year >= 50000)
  79         cal.setGregorianChange(new Date(50000-1900, JANUARY, 20));
  80         cal.set(49998, JANUARY, 1);
  81         checkContinuity(cal, DAY_OF_YEAR);
  82         checkContinuity(cal, WEEK_OF_YEAR);
  83         cal.set(49999, JANUARY, 1);
  84         checkContinuity(cal, DAY_OF_YEAR);
  85         checkContinuity(cal, WEEK_OF_YEAR);
  86         cal.set(50000, JANUARY, 20);
  87         checkContinuity(cal, DAY_OF_YEAR);
  88         checkContinuity(cal, WEEK_OF_YEAR);
  89 
  90         // Handling of "overlapping" dates may still be incorrect as
  91         // of 1.5. Also, there's no way to disambiguate "overlapping"
  92         // dates.
  93         // millis=-112033929600000: date=-1581-10-15T00:00:00.000Z
  94         cal.setGregorianChange(new Date(-112033929600000L));
  95         cal.set(ERA, AD);
  96         cal.set(-1581, JANUARY, 1);
  97         // The year should have 379 days.
  98         checkContinuity(cal, DAY_OF_YEAR);
  99         checkContinuity(cal, WEEK_OF_YEAR);
 100 
 101         logln("Default cutover");
 102         cal = new Koyomi();
 103         cal.set(1582, OCTOBER, 1);
 104         logln("  roll --DAY_OF_MONTH from 1582/10/01");
 105         cal.roll(DAY_OF_MONTH, -1);
 106         if (!cal.checkDate(1582, OCTOBER, 31)) {
 107             errln(cal.getMessage());
 108         }
 109         logln("  roll DAY_OF_MONTH+10 from 1582/10/31");
 110         cal.roll(DAY_OF_MONTH, +10);
 111         if (!cal.checkDate(1582, OCTOBER, 20)) {
 112             errln(cal.getMessage());
 113         }
 114         logln("  roll DAY_OF_MONTH-10 from 1582/10/20");
 115         cal.roll(DAY_OF_MONTH, -10);
 116         if (!cal.checkDate(1582, OCTOBER, 31)) {
 117             errln(cal.getMessage());
 118         }
 119         logln("  roll back one day further");
 120         cal.roll(DAY_OF_MONTH, +1);
 121         if (!cal.checkDate(1582, OCTOBER, 1)) {
 122             errln(cal.getMessage());
 123         }
 124 
 125         // should handle the gap between 1969/12/22 (Julian) to 1970/1/5 (Gregorian)
 126         logln("Cutover date is 1970/1/5");
 127         cal.setGregorianChange(new Date(1970-1900, JANUARY, 5));
 128         cal.set(ERA, AD);
 129         cal.set(YEAR, 1970);
 130         logln("  Set DAY_OF_YEAR to the 28th day of 1970");
 131         cal.set(DAY_OF_YEAR, 28);
 132         if (!cal.checkDate(1970, FEBRUARY, 1)) {
 133             errln(cal.getMessage());
 134         }
 135         if (!cal.checkFieldValue(WEEK_OF_YEAR, 5)) {
 136             errln(cal.getMessage());
 137         }
 138         logln("  1969/12/22 should be the 356th day of the year.");
 139         cal.set(1969, DECEMBER, 22);
 140         if (!cal.checkFieldValue(DAY_OF_YEAR, 356)) {
 141             errln(cal.getMessage());
 142         }
 143         logln("  Set DAY_OF_YEAR to autual maximum.");
 144         int actualMaxDayOfYear = cal.getActualMaximum(DAY_OF_YEAR);
 145         if (actualMaxDayOfYear != 356) {
 146             errln("actual maximum of DAY_OF_YEAR: got " + actualMaxDayOfYear + ", expected 356");
 147         }
 148         cal.set(DAY_OF_YEAR, actualMaxDayOfYear);
 149         if (!cal.checkDate(1969, DECEMBER, 22)) {
 150             errln(cal.getMessage());
 151         }
 152         cal.set(1969, DECEMBER, 22);
 153         cal.roll(DAY_OF_YEAR, +1);
 154         logln("  Set to 1969/12/22 and roll DAY_OF_YEAR++");
 155         if (!cal.checkDate(1969, JANUARY, 1)) {
 156             errln(cal.getMessage());
 157         }
 158         logln("  1970/1/5 should be the first day of the year.");
 159         cal.set(1970, JANUARY, 5);
 160         if (!cal.checkFieldValue(DAY_OF_YEAR, 1)) {
 161             errln(cal.getMessage());
 162         }
 163         logln("  roll --DAY_OF_MONTH from 1970/1/5");
 164         cal.roll(DAY_OF_MONTH, -1);
 165         if (!cal.checkDate(1970, JANUARY, 31)) {
 166             errln(cal.getMessage());
 167         }
 168         logln("  roll back one day of month");
 169         cal.roll(DAY_OF_MONTH, +1);
 170         if (!cal.checkDate(1970, JANUARY, 5)) {
 171             errln(cal.getMessage());
 172         }
 173 
 174         // Test "missing" dates in non-lenient.
 175         cal = new Koyomi(); // new instance for the default cutover
 176         cal.setLenient(false);
 177         try {
 178             // the next day of 1582/10/4 (Julian) is 1582/10/15 (Gregorian)
 179             logln("1582/10/10 doesn't exit with the default cutover.");
 180             cal.set(1582, OCTOBER, 10);
 181             cal.getTime();
 182             errln("    Didn't throw IllegalArgumentException in non-lenient.");
 183         } catch (IllegalArgumentException e) {
 184         }
 185     }
 186 
 187     private void checkContinuity(Koyomi cal, int field) {
 188         cal.getTime();
 189         logln(Koyomi.getFieldName(field) + " starting on " + cal.toDateString());
 190         int max = cal.getActualMaximum(field);
 191         for (int i = 1; i <= max; i++) {
 192             logln(i + "    " + cal.toDateString());
 193             if (!cal.checkFieldValue(field, i)) {
 194                 errln("    " + cal.toDateString() + ":\t" + cal.getMessage());
 195             }
 196             cal.add(field, +1);
 197         }
 198     }
 199 
 200     /**
 201      * 4928615: GregorianCalendar returns wrong dates after setGregorianChange
 202      */
 203     public void Test4928615() {
 204         Koyomi cal = new Koyomi();
 205         logln("Today is 2003/10/1 Gregorian.");
 206         Date x = new Date(2003-1900, 10-1, 1);
 207         cal.setTime(x);
 208 
 209         logln("  Changing the cutover date to yesterday...");
 210         cal.setGregorianChange(new Date(x.getTime() - (24*3600*1000)));
 211         if (!cal.checkDate(2003, OCTOBER, 1)) {
 212             errln("    " + cal.getMessage());
 213         }
 214         logln("  Changing the cutover date to tomorrow...");
 215         cal.setGregorianChange(new Date(x.getTime() + (24*3600*1000)));
 216         if (!cal.checkDate(2003, SEPTEMBER, 18)) {
 217             errln("    " + cal.getMessage());
 218         }
 219     }
 220 
 221     /**
 222      * 4743587: GregorianCalendar.getLeastMaximum() returns wrong values
 223      */
 224     public void Test4743587() {
 225         Koyomi cal = new Koyomi();
 226         Koyomi cal2 = (Koyomi) cal.clone();
 227         logln("getLeastMaximum should handle cutover year.\n"
 228               +"  default cutover date");
 229         if (!cal.checkLeastMaximum(DAY_OF_YEAR, 365-10)) {
 230             errln("    " + cal.getMessage());
 231         }
 232         if (!cal.checkLeastMaximum(WEEK_OF_YEAR, 52-((10+6)/7))) {
 233             errln("    " + cal.getMessage());
 234         }
 235         // Corrected for 4956232
 236         if (!cal.checkLeastMaximum(DAY_OF_MONTH, 28)) {
 237             errln("    " + cal.getMessage());
 238         }
 239         if (!cal.checkLeastMaximum(WEEK_OF_MONTH, 3)) {
 240             errln("    " + cal.getMessage());
 241         }
 242         if (!cal.checkLeastMaximum(DAY_OF_WEEK_IN_MONTH, 3)) {
 243             errln("    " + cal.getMessage());
 244         }
 245         // make sure that getLeastMaximum calls didn't affect the date
 246         if (!cal.equals(cal2)) {
 247             errln("    getLeastMaximum calls modified the object.");
 248         }
 249         if (!cal.checkGreatestMinimum(DAY_OF_MONTH, 1)) {
 250             errln("    " + cal.getMessage());
 251         }
 252 
 253         logln("  changing the date to 1582/10/20 for actual min/max tests");
 254         cal.set(1582, OCTOBER, 20);
 255         if (!cal.checkActualMinimum(DAY_OF_MONTH, 1)) {
 256             errln("    " + cal.getMessage());
 257         }
 258         if (!cal.checkActualMaximum(DAY_OF_MONTH, 31)) {
 259             errln("    " + cal.getMessage());
 260         }
 261 
 262         cal = new Koyomi();
 263         logln("Change the cutover date to 1970/1/5.");
 264         cal.setGregorianChange(new Date(1970-1900, 0, 5));
 265         if (!cal.checkLeastMaximum(DAY_OF_YEAR, 356)) {
 266             errln("    " + cal.getMessage());
 267         }
 268         if (!cal.checkLeastMaximum(DAY_OF_MONTH, 22)) {
 269             errln("    " + cal.getMessage());
 270         }
 271         if (!cal.checkGreatestMinimum(DAY_OF_MONTH, 5)) {
 272             errln("    " + cal.getMessage());
 273         }
 274         cal.set(1970, JANUARY, 10);
 275         if (!cal.checkActualMinimum(DAY_OF_MONTH, 5)) {
 276             errln("    " + cal.getMessage());
 277         }
 278         if (!cal.checkActualMaximum(DAY_OF_MONTH, 31)) {
 279             errln("    " + cal.getMessage());
 280         }
 281     }
 282 
 283     /**
 284      * 6459836: (cal) GregorianCalendar set method provides wrong result
 285      */
 286     public void Test6459836() {
 287         int hour = 13865672;
 288         Koyomi gc1 = new Koyomi();
 289         gc1.clear();
 290         gc1.set(1, gc1.JANUARY, 1, 0, 0, 0);
 291         gc1.set(gc1.HOUR_OF_DAY, hour);
 292         if (!gc1.checkDate(1582, gc1.OCTOBER, 4)) {
 293             errln("test case 1: " + gc1.getMessage());
 294         }
 295         gc1.clear();
 296         gc1.set(1, gc1.JANUARY, 1, 0, 0, 0);
 297         gc1.set(gc1.HOUR_OF_DAY, hour + 24);
 298         if (!gc1.checkDate(1582, gc1.OCTOBER, 15)) {
 299             errln("test case 2: " + gc1.getMessage());
 300         }
 301     }
 302 
 303     /**
 304      * 6549953 (cal) WEEK_OF_YEAR and DAY_OF_YEAR calculation problems around Gregorian cutover
 305      */
 306     public void Test6549953() {
 307         Koyomi cal = new Koyomi();
 308 
 309         cal.set(YEAR, 1582);
 310         cal.set(WEEK_OF_YEAR, 42);
 311         cal.set(DAY_OF_WEEK, FRIDAY);
 312         cal.checkFieldValue(WEEK_OF_YEAR, 42);
 313         cal.checkFieldValue(DAY_OF_WEEK, FRIDAY);
 314         if (!cal.checkDate(1582, OCTOBER, 29)) {
 315             errln(cal.getMessage());
 316         }
 317         cal.clear();
 318         cal.set(1582, OCTOBER, 1);
 319         cal.set(DAY_OF_YEAR, 292);
 320         if (!cal.checkDate(1582, OCTOBER, 29)) {
 321             errln(cal.getMessage());
 322         }
 323     }
 324 }