1/* 2 * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24/** 25 * @test 26 * @bug 4033662 27 * @summary test for limit on Calendar 28 * @library /java/text/testlib 29 * @run main CalendarLimitTest -verbose 30 */ 31 32import java.util.*; 33import java.text.*; 34 35/** 36 * This test verifies the behavior of Calendar around the very earliest limits 37 * which it can handle. It also verifies the behavior for large values of millis. 38 * 39 * Note: There used to be a limit, due to a bug, for early times. There is 40 * currently no limit. 41 * 42 * March 17, 1998: Added code to make sure big + dates are big + AD years, and 43 * big - dates are big + BC years. 44 */ 45public class CalendarLimitTest extends IntlTest 46{ 47 // This number determined empirically; this is the old limit, 48 // which we test for to make sure it isn't there anymore. 49 static final long EARLIEST_SUPPORTED_MILLIS = -210993120000000L; 50 51 static final int EPOCH_JULIAN_DAY = 2440588; // Jaunary 1, 1970 (Gregorian) 52 static final int JAN_1_1_JULIAN_DAY = 1721426; // January 1, year 1 (Gregorian) 53 54 // Useful millisecond constants 55 static final int ONE_SECOND = 1000; 56 static final int ONE_MINUTE = 60*ONE_SECOND; 57 static final int ONE_HOUR = 60*ONE_MINUTE; 58 static final int ONE_DAY = 24*ONE_HOUR; 59 static final int ONE_WEEK = 7*ONE_DAY; 60 static final long ONE_YEAR = (long)(365.2425 * ONE_DAY); 61 62 static long ORIGIN; // This is the *approximate* point at which BC switches to AD 63 64 public static void main(String argv[]) throws Exception { 65 Locale locale = Locale.getDefault(); 66 if (!TestUtils.usesGregorianCalendar(locale)) { 67 System.out.println("Skipping this test because locale is " + locale); 68 return; 69 } 70 71 new CalendarLimitTest().run(argv); 72 } 73 74 /** 75 * Converts Julian day to time as milliseconds. 76 * @param julian the given Julian day number. 77 * @return time as milliseconds. 78 */ 79 private static final long julianDayToMillis(long julian) { 80 return (julian - EPOCH_JULIAN_DAY) * ONE_DAY; 81 } 82 83 /** 84 * Verify that the given time is processed without problem. 85 * @return the adjust year, with 0 = 1 BC, -1 = 2 BC, etc. 86 */ 87 int test(long millis, Calendar cal, DateFormat fmt) 88 { 89 Exception exception = null; 90 String theDate = ""; 91 try { 92 Date d= new Date(millis); 93 cal.setTime(d); 94 theDate = fmt.format(d); 95 } 96 catch (IllegalArgumentException e) { 97 exception = e; 98 } 99 String s = "0x" + Long.toHexString(millis) + " " + theDate; 100 101 int era=cal.get(Calendar.ERA), year=cal.get(Calendar.YEAR), 102 dom=cal.get(Calendar.DATE), mon=cal.get(Calendar.MONTH); 103 104 cal.clear(); 105 cal.set(year, mon, dom); 106 cal.set(Calendar.ERA, era); 107 Date rt = cal.getTime(); 108 109 boolean ok = true; 110 if (exception != null) { 111 errln("FAIL: Exception " + s); 112 ok = false; 113 } 114 if (((millis >= ORIGIN) && (era != GregorianCalendar.AD)) || 115 ((millis < ORIGIN) && (era != GregorianCalendar.BC)) || 116 (year < 1)) { 117 errln("FAIL: Bad year/era " + s); 118 ok = false; 119 } 120 if (dom<1 || dom>31) { 121 errln("FAIL: Bad DOM " + s); 122 ok = false; 123 } 124 if (Math.abs(millis - rt.getTime()) > ONE_DAY) { 125 errln("FAIL: RT fail " + s + " -> 0x" + 126 Long.toHexString(rt.getTime()) + " " + 127 fmt.format(rt)); 128 ok = false; 129 } 130 if (ok) logln(s); 131 if (era==GregorianCalendar.BC) year = 1-year; 132 return year; 133 } 134 135 public void TestCalendarLimit() 136 { 137 ORIGIN = julianDayToMillis(JAN_1_1_JULIAN_DAY); 138 139 Calendar cal = Calendar.getInstance(); 140 // You must set the time zone to GMT+0 or the edge cases like 141 // Long.MIN_VALUE, Long.MAX_VALUE, and right around the threshold 142 // won't work, since before converting to fields the calendar code 143 // will add the offset for the zone. 144 cal.setTimeZone(TimeZone.getTimeZone("Africa/Casablanca")); 145 146 DateFormat dateFormat = DateFormat.getDateInstance(); 147 dateFormat.setCalendar(cal); // Make sure you do this -- same reason as above 148 ((SimpleDateFormat)dateFormat).applyPattern("MMM d, yyyy G"); 149 150 // Don't expect any failure for positive longs 151 int lastYear=0; 152 boolean first=true; 153 for (long m = Long.MAX_VALUE; m > 0; m >>= 1) 154 { 155 int y = test(m, cal, dateFormat); 156 if (!first && y > lastYear) 157 errln("FAIL: Years should be decreasing " + lastYear + " " + y); 158 first = false; 159 lastYear = y; 160 } 161 162 // Expect failures for negative millis below threshold 163 first = true; 164 for (long m = Long.MIN_VALUE; m < 0; m /= 2) // Don't use m >>= 1 165 { 166 int y = test(m, cal, dateFormat); 167 if (!first && y < lastYear) 168 errln("FAIL: Years should be increasing " + lastYear + " " + y); 169 first = false; 170 lastYear = y; 171 } 172 173 // Test right around the threshold 174 test(EARLIEST_SUPPORTED_MILLIS, cal, dateFormat); 175 test(EARLIEST_SUPPORTED_MILLIS-1, cal, dateFormat); 176 177 // Test a date that should work 178 test(Long.MIN_VALUE + ONE_DAY, cal, dateFormat); 179 180 // Try hours in the earliest day or two 181 // JUST FOR DEBUGGING: 182 if (false) { 183 ((SimpleDateFormat)dateFormat).applyPattern("H:mm MMM d, yyyy G"); 184 for (int dom=2; dom<=3; ++dom) { 185 for (int h=0; h<24; ++h) { 186 cal.clear(); 187 cal.set(Calendar.ERA, GregorianCalendar.BC); 188 cal.set(292269055, Calendar.DECEMBER, dom, h, 0); 189 Date d = cal.getTime(); 190 cal.setTime(d); 191 logln("" + h + ":00 Dec "+dom+", 292269055 BC -> " + 192 Long.toHexString(d.getTime()) + " -> " + 193 dateFormat.format(cal.getTime())); 194 } 195 } 196 // Other way 197 long t = 0x80000000018c5c00L; // Dec 3, 292269055 BC 198 while (t<0) { 199 cal.setTime(new Date(t)); 200 logln("0x" + Long.toHexString(t) + " -> " + 201 dateFormat.format(cal.getTime())); 202 t -= ONE_HOUR; 203 } 204 } 205 } 206} 207 208//eof 209