Showing the changes to java/pkg/sun/util/calendar/BaseCalendar.java (1 of 18352 files). Show all
Unified · Split
| @@ -0,0 +1,538 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2003, 2004, 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. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package sun.util.calendar; | |
| 27 | + | |
| 28 | +import java.util.Locale; | |
| 29 | +import java.util.TimeZone; | |
| 30 | + | |
| 31 | +/** | |
| 32 | + * The <code>BaseCalendar</code> provides basic calendar calculation | |
| 33 | + * functions to support the Julian, Gregorian, and Gregorian-based | |
| 34 | + * calendar systems. | |
| 35 | + * | |
| 36 | + * @author Masayoshi Okutsu | |
| 37 | + * @since 1.5 | |
| 38 | + */ | |
| 39 | + | |
| 40 | +public abstract class BaseCalendar extends AbstractCalendar { | |
| 41 | + | |
| 42 | + public static final int JANUARY = 1; | |
| 43 | + public static final int FEBRUARY = 2; | |
| 44 | + public static final int MARCH = 3; | |
| 45 | + public static final int APRIL = 4; | |
| 46 | + public static final int MAY = 5; | |
| 47 | + public static final int JUNE = 6; | |
| 48 | + public static final int JULY = 7; | |
| 49 | + public static final int AUGUST = 8; | |
| 50 | + public static final int SEPTEMBER = 9; | |
| 51 | + public static final int OCTOBER = 10; | |
| 52 | + public static final int NOVEMBER = 11; | |
| 53 | + public static final int DECEMBER = 12; | |
| 54 | + | |
| 55 | + // day of week constants | |
| 56 | + public static final int SUNDAY = 1; | |
| 57 | + public static final int MONDAY = 2; | |
| 58 | + public static final int TUESDAY = 3; | |
| 59 | + public static final int WEDNESDAY = 4; | |
| 60 | + public static final int THURSDAY = 5; | |
| 61 | + public static final int FRIDAY = 6; | |
| 62 | + public static final int SATURDAY = 7; | |
| 63 | + | |
| 64 | + // The base Gregorian year of FIXED_DATES[] | |
| 65 | + private static final int BASE_YEAR = 1970; | |
| 66 | + | |
| 67 | + // Pre-calculated fixed dates of January 1 from BASE_YEAR | |
| 68 | + // (Gregorian). This table covers all the years that can be | |
| 69 | + // supported by the POSIX time_t (32-bit) after the Epoch. Note | |
| 70 | + // that the data type is int[]. | |
| 71 | + private static final int[] FIXED_DATES = { | |
| 72 | + 719163, // 1970 | |
| 73 | + 719528, // 1971 | |
| 74 | + 719893, // 1972 | |
| 75 | + 720259, // 1973 | |
| 76 | + 720624, // 1974 | |
| 77 | + 720989, // 1975 | |
| 78 | + 721354, // 1976 | |
| 79 | + 721720, // 1977 | |
| 80 | + 722085, // 1978 | |
| 81 | + 722450, // 1979 | |
| 82 | + 722815, // 1980 | |
| 83 | + 723181, // 1981 | |
| 84 | + 723546, // 1982 | |
| 85 | + 723911, // 1983 | |
| 86 | + 724276, // 1984 | |
| 87 | + 724642, // 1985 | |
| 88 | + 725007, // 1986 | |
| 89 | + 725372, // 1987 | |
| 90 | + 725737, // 1988 | |
| 91 | + 726103, // 1989 | |
| 92 | + 726468, // 1990 | |
| 93 | + 726833, // 1991 | |
| 94 | + 727198, // 1992 | |
| 95 | + 727564, // 1993 | |
| 96 | + 727929, // 1994 | |
| 97 | + 728294, // 1995 | |
| 98 | + 728659, // 1996 | |
| 99 | + 729025, // 1997 | |
| 100 | + 729390, // 1998 | |
| 101 | + 729755, // 1999 | |
| 102 | + 730120, // 2000 | |
| 103 | + 730486, // 2001 | |
| 104 | + 730851, // 2002 | |
| 105 | + 731216, // 2003 | |
| 106 | + 731581, // 2004 | |
| 107 | + 731947, // 2005 | |
| 108 | + 732312, // 2006 | |
| 109 | + 732677, // 2007 | |
| 110 | + 733042, // 2008 | |
| 111 | + 733408, // 2009 | |
| 112 | + 733773, // 2010 | |
| 113 | + 734138, // 2011 | |
| 114 | + 734503, // 2012 | |
| 115 | + 734869, // 2013 | |
| 116 | + 735234, // 2014 | |
| 117 | + 735599, // 2015 | |
| 118 | + 735964, // 2016 | |
| 119 | + 736330, // 2017 | |
| 120 | + 736695, // 2018 | |
| 121 | + 737060, // 2019 | |
| 122 | + 737425, // 2020 | |
| 123 | + 737791, // 2021 | |
| 124 | + 738156, // 2022 | |
| 125 | + 738521, // 2023 | |
| 126 | + 738886, // 2024 | |
| 127 | + 739252, // 2025 | |
| 128 | + 739617, // 2026 | |
| 129 | + 739982, // 2027 | |
| 130 | + 740347, // 2028 | |
| 131 | + 740713, // 2029 | |
| 132 | + 741078, // 2030 | |
| 133 | + 741443, // 2031 | |
| 134 | + 741808, // 2032 | |
| 135 | + 742174, // 2033 | |
| 136 | + 742539, // 2034 | |
| 137 | + 742904, // 2035 | |
| 138 | + 743269, // 2036 | |
| 139 | + 743635, // 2037 | |
| 140 | + 744000, // 2038 | |
| 141 | + 744365, // 2039 | |
| 142 | + }; | |
| 143 | + | |
| 144 | + public abstract static class Date extends CalendarDate { | |
| 145 | + protected Date() { | |
| 146 | + super(); | |
| 147 | + } | |
| 148 | + protected Date(TimeZone zone) { | |
| 149 | + super(zone); | |
| 150 | + } | |
| 151 | + | |
| 152 | + public Date setNormalizedDate(int normalizedYear, int month, int dayOfMonth) { | |
| 153 | + setNormalizedYear(normalizedYear); | |
| 154 | + setMonth(month).setDayOfMonth(dayOfMonth); | |
| 155 | + return this; | |
| 156 | + } | |
| 157 | + | |
| 158 | + public abstract int getNormalizedYear(); | |
| 159 | + | |
| 160 | + public abstract void setNormalizedYear(int normalizedYear); | |
| 161 | + | |
| 162 | + // Cache for the fixed date of January 1 and year length of the | |
| 163 | + // cachedYear. A simple benchmark showed 7% performance | |
| 164 | + // improvement with >90% cache hit. The initial values are for Gregorian. | |
| 165 | + int cachedYear = 2004; | |
| 166 | + long cachedFixedDateJan1 = 731581L; | |
| 167 | + long cachedFixedDateNextJan1 = cachedFixedDateJan1 + 366; | |
| 168 | + | |
| 169 | + protected final boolean hit(int year) { | |
| 170 | + return year == cachedYear; | |
| 171 | + } | |
| 172 | + | |
| 173 | + protected final boolean hit(long fixedDate) { | |
| 174 | + return (fixedDate >= cachedFixedDateJan1 && | |
| 175 | + fixedDate < cachedFixedDateNextJan1); | |
| 176 | + } | |
| 177 | + protected int getCachedYear() { | |
| 178 | + return cachedYear; | |
| 179 | + } | |
| 180 | + | |
| 181 | + protected long getCachedJan1() { | |
| 182 | + return cachedFixedDateJan1; | |
| 183 | + } | |
| 184 | + | |
| 185 | + protected void setCache(int year, long jan1, int len) { | |
| 186 | + cachedYear = year; | |
| 187 | + cachedFixedDateJan1 = jan1; | |
| 188 | + cachedFixedDateNextJan1 = jan1 + len; | |
| 189 | + } | |
| 190 | + } | |
| 191 | + | |
| 192 | + public boolean validate(CalendarDate date) { | |
| 193 | + Date bdate = (Date) date; | |
| 194 | + if (bdate.isNormalized()) { | |
| 195 | + return true; | |
| 196 | + } | |
| 197 | + int month = bdate.getMonth(); | |
| 198 | + if (month < JANUARY || month > DECEMBER) { | |
| 199 | + return false; | |
| 200 | + } | |
| 201 | + int d = bdate.getDayOfMonth(); | |
| 202 | + if (d <= 0 || d > getMonthLength(bdate.getNormalizedYear(), month)) { | |
| 203 | + return false; | |
| 204 | + } | |
| 205 | + int dow = bdate.getDayOfWeek(); | |
| 206 | + if (dow != bdate.FIELD_UNDEFINED && dow != getDayOfWeek(bdate)) { | |
| 207 | + return false; | |
| 208 | + } | |
| 209 | + | |
| 210 | + if (!validateTime(date)) { | |
| 211 | + return false; | |
| 212 | + } | |
| 213 | + | |
| 214 | + bdate.setNormalized(true); | |
| 215 | + return true; | |
| 216 | + } | |
| 217 | + | |
| 218 | + public boolean normalize(CalendarDate date) { | |
| 219 | + if (date.isNormalized()) { | |
| 220 | + return true; | |
| 221 | + } | |
| 222 | + | |
| 223 | + Date bdate = (Date) date; | |
| 224 | + TimeZone zi = bdate.getZone(); | |
| 225 | + | |
| 226 | + // If the date has a time zone, then we need to recalculate | |
| 227 | + // the calendar fields. Let getTime() do it. | |
| 228 | + if (zi != null) { | |
| 229 | + getTime(date); | |
| 230 | + return true; | |
| 231 | + } | |
| 232 | + | |
| 233 | + int days = normalizeTime(bdate); | |
| 234 | + normalizeMonth(bdate); | |
| 235 | + long d = (long)bdate.getDayOfMonth() + days; | |
| 236 | + int m = bdate.getMonth(); | |
| 237 | + int y = bdate.getNormalizedYear(); | |
| 238 | + int ml = getMonthLength(y, m); | |
| 239 | + | |
| 240 | + if (!(d > 0 && d <= ml)) { | |
| 241 | + if (d <= 0 && d > -28) { | |
| 242 | + ml = getMonthLength(y, --m); | |
| 243 | + d += ml; | |
| 244 | + bdate.setDayOfMonth((int) d); | |
| 245 | + if (m == 0) { | |
| 246 | + m = DECEMBER; | |
| 247 | + bdate.setNormalizedYear(y - 1); | |
| 248 | + } | |
| 249 | + bdate.setMonth(m); | |
| 250 | + } else if (d > ml && d < (ml + 28)) { | |
| 251 | + d -= ml; | |
| 252 | + ++m; | |
| 253 | + bdate.setDayOfMonth((int)d); | |
| 254 | + if (m > DECEMBER) { | |
| 255 | + bdate.setNormalizedYear(y + 1); | |
| 256 | + m = JANUARY; | |
| 257 | + } | |
| 258 | + bdate.setMonth(m); | |
| 259 | + } else { | |
| 260 | + long fixedDate = d + getFixedDate(y, m, 1, bdate) - 1L; | |
| 261 | + getCalendarDateFromFixedDate(bdate, fixedDate); | |
| 262 | + } | |
| 263 | + } else { | |
| 264 | + bdate.setDayOfWeek(getDayOfWeek(bdate)); | |
| 265 | + } | |
| 266 | + date.setLeapYear(isLeapYear(bdate.getNormalizedYear())); | |
| 267 | + date.setZoneOffset(0); | |
| 268 | + date.setDaylightSaving(0); | |
| 269 | + bdate.setNormalized(true); | |
| 270 | + return true; | |
| 271 | + } | |
| 272 | + | |
| 273 | + void normalizeMonth(CalendarDate date) { | |
| 274 | + Date bdate = (Date) date; | |
| 275 | + int year = bdate.getNormalizedYear(); | |
| 276 | + long month = bdate.getMonth(); | |
| 277 | + if (month <= 0) { | |
| 278 | + long xm = 1L - month; | |
| 279 | + year -= (int)((xm / 12) + 1); | |
| 280 | + month = 13 - (xm % 12); | |
| 281 | + bdate.setNormalizedYear(year); | |
| 282 | + bdate.setMonth((int) month); | |
| 283 | + } else if (month > DECEMBER) { | |
| 284 | + year += (int)((month - 1) / 12); | |
| 285 | + month = ((month - 1)) % 12 + 1; | |
| 286 | + bdate.setNormalizedYear(year); | |
| 287 | + bdate.setMonth((int) month); | |
| 288 | + } | |
| 289 | + } | |
| 290 | + | |
| 291 | + /** | |
| 292 | + * Returns 366 if the specified date is in a leap year, or 365 | |
| 293 | + * otherwise This method does not perform the normalization with | |
| 294 | + * the specified <code>CalendarDate</code>. The | |
| 295 | + * <code>CalendarDate</code> must be normalized to get a correct | |
| 296 | + * value. | |
| 297 | + * | |
| 298 | + * @param a <code>CalendarDate</code> | |
| 299 | + * @return a year length in days | |
| 300 | + * @throws ClassCastException if the specified date is not a | |
| 301 | + * {@link BaseCalendar.Date} | |
| 302 | + */ | |
| 303 | + public int getYearLength(CalendarDate date) { | |
| 304 | + return isLeapYear(((Date)date).getNormalizedYear()) ? 366 : 365; | |
| 305 | + } | |
| 306 | + | |
| 307 | + public int getYearLengthInMonths(CalendarDate date) { | |
| 308 | + return 12; | |
| 309 | + } | |
| 310 | + | |
| 311 | + static final int[] DAYS_IN_MONTH | |
| 312 | + // 12 1 2 3 4 5 6 7 8 9 10 11 12 | |
| 313 | + = { 31, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; | |
| 314 | + static final int[] ACCUMULATED_DAYS_IN_MONTH | |
| 315 | + // 12/1 1/1 2/1 3/1 4/1 5/1 6/1 7/1 8/1 9/1 10/1 11/1 12/1 | |
| 316 | + = { -30, 0, 31, 59, 90,120,151,181,212,243, 273, 304, 334}; | |
| 317 | + | |
| 318 | + static final int[] ACCUMULATED_DAYS_IN_MONTH_LEAP | |
| 319 | + // 12/1 1/1 2/1 3/1 4/1 5/1 6/1 7/1 8/1 9/1 10/1 11/1 12/1 | |
| 320 | + = { -30, 0, 31, 59+1, 90+1,120+1,151+1,181+1,212+1,243+1, 273+1, 304+1, 334+1}; | |
| 321 | + | |
| 322 | + public int getMonthLength(CalendarDate date) { | |
| 323 | + Date gdate = (Date) date; | |
| 324 | + int month = gdate.getMonth(); | |
| 325 | + if (month < JANUARY || month > DECEMBER) { | |
| 326 | + throw new IllegalArgumentException("Illegal month value: " + month); | |
| 327 | + } | |
| 328 | + return getMonthLength(gdate.getNormalizedYear(), month); | |
| 329 | + } | |
| 330 | + | |
| 331 | + // accepts 0 (December in the previous year) to 12. | |
| 332 | + private final int getMonthLength(int year, int month) { | |
| 333 | + int days = DAYS_IN_MONTH[month]; | |
| 334 | + if (month == FEBRUARY && isLeapYear(year)) { | |
| 335 | + days++; | |
| 336 | + } | |
| 337 | + return days; | |
| 338 | + } | |
| 339 | + | |
| 340 | + public long getDayOfYear(CalendarDate date) { | |
| 341 | + return getDayOfYear(((Date)date).getNormalizedYear(), | |
| 342 | + date.getMonth(), | |
| 343 | + date.getDayOfMonth()); | |
| 344 | + } | |
| 345 | + | |
| 346 | + final long getDayOfYear(int year, int month, int dayOfMonth) { | |
| 347 | + return (long) dayOfMonth | |
| 348 | + + (isLeapYear(year) ? | |
| 349 | + ACCUMULATED_DAYS_IN_MONTH_LEAP[month] : ACCUMULATED_DAYS_IN_MONTH[month]); | |
| 350 | + } | |
| 351 | + | |
| 352 | + // protected | |
| 353 | + public long getFixedDate(CalendarDate date) { | |
| 354 | + if (!date.isNormalized()) { | |
| 355 | + normalizeMonth(date); | |
| 356 | + } | |
| 357 | + return getFixedDate(((Date)date).getNormalizedYear(), | |
| 358 | + date.getMonth(), | |
| 359 | + date.getDayOfMonth(), | |
| 360 | + (BaseCalendar.Date) date); | |
| 361 | + } | |
| 362 | + | |
| 363 | + // public for java.util.GregorianCalendar | |
| 364 | + public long getFixedDate(int year, int month, int dayOfMonth, BaseCalendar.Date cache) { | |
| 365 | + boolean isJan1 = month == JANUARY && dayOfMonth == 1; | |
| 366 | + | |
| 367 | + // Look up the one year cache | |
| 368 | + if (cache != null && cache.hit(year)) { | |
| 369 | + if (isJan1) { | |
| 370 | + return cache.getCachedJan1(); | |
| 371 | + } | |
| 372 | + return cache.getCachedJan1() + getDayOfYear(year, month, dayOfMonth) - 1; | |
| 373 | + } | |
| 374 | + | |
| 375 | + // Look up the pre-calculated fixed date table | |
| 376 | + int n = year - BASE_YEAR; | |
| 377 | + if (n >= 0 && n < FIXED_DATES.length) { | |
| 378 | + long jan1 = FIXED_DATES[n]; | |
| 379 | + if (cache != null) { | |
| 380 | + cache.setCache(year, jan1, isLeapYear(year) ? 366 : 365); | |
| 381 | + } | |
| 382 | + return isJan1 ? jan1 : jan1 + getDayOfYear(year, month, dayOfMonth) - 1; | |
| 383 | + } | |
| 384 | + | |
| 385 | + long prevyear = (long)year - 1; | |
| 386 | + long days = dayOfMonth; | |
| 387 | + | |
| 388 | + if (prevyear >= 0) { | |
| 389 | + days += (365 * prevyear) | |
| 390 | + + (prevyear / 4) | |
| 391 | + - (prevyear / 100) | |
| 392 | + + (prevyear / 400) | |
| 393 | + + ((367 * month - 362) / 12); | |
| 394 | + } else { | |
| 395 | + days += (365 * prevyear) | |
| 396 | + + CalendarUtils.floorDivide(prevyear, 4) | |
| 397 | + - CalendarUtils.floorDivide(prevyear, 100) | |
| 398 | + + CalendarUtils.floorDivide(prevyear, 400) | |
| 399 | + + CalendarUtils.floorDivide((367 * month - 362), 12); | |
| 400 | + } | |
| 401 | + | |
| 402 | + if (month > FEBRUARY) { | |
| 403 | + days -= isLeapYear(year) ? 1 : 2; | |
| 404 | + } | |
| 405 | + | |
| 406 | + // If it's January 1, update the cache. | |
| 407 | + if (cache != null && isJan1) { | |
| 408 | + cache.setCache(year, days, isLeapYear(year) ? 366 : 365); | |
| 409 | + } | |
| 410 | + | |
| 411 | + return days; | |
| 412 | + } | |
| 413 | + | |
| 414 | + /** | |
| 415 | + * Calculates calendar fields and store them in the specified | |
| 416 | + * <code>CalendarDate</code>. | |
| 417 | + */ | |
| 418 | + // should be 'protected' | |
| 419 | + public void getCalendarDateFromFixedDate(CalendarDate date, | |
| 420 | + long fixedDate) { | |
| 421 | + Date gdate = (Date) date; | |
| 422 | + int year; | |
| 423 | + long jan1; | |
| 424 | + boolean isLeap; | |
| 425 | + if (gdate.hit(fixedDate)) { | |
| 426 | + year = gdate.getCachedYear(); | |
| 427 | + jan1 = gdate.getCachedJan1(); | |
| 428 | + isLeap = isLeapYear(year); | |
| 429 | + } else { | |
| 430 | + // Looking up FIXED_DATES[] here didn't improve performance | |
| 431 | + // much. So we calculate year and jan1. getFixedDate() | |
| 432 | + // will look up FIXED_DATES[] actually. | |
| 433 | + year = getGregorianYearFromFixedDate(fixedDate); | |
| 434 | + jan1 = getFixedDate(year, JANUARY, 1, null); | |
| 435 | + isLeap = isLeapYear(year); | |
| 436 | + // Update the cache data | |
| 437 | + gdate.setCache (year, jan1, isLeap ? 366 : 365); | |
| 438 | + } | |
| 439 | + | |
| 440 | + int priorDays = (int)(fixedDate - jan1); | |
| 441 | + long mar1 = jan1 + 31 + 28; | |
| 442 | + if (isLeap) { | |
| 443 | + ++mar1; | |
| 444 | + } | |
| 445 | + if (fixedDate >= mar1) { | |
| 446 | + priorDays += isLeap ? 1 : 2; | |
| 447 | + } | |
| 448 | + int month = 12 * priorDays + 373; | |
| 449 | + if (month > 0) { | |
| 450 | + month /= 367; | |
| 451 | + } else { | |
| 452 | + month = CalendarUtils.floorDivide(month, 367); | |
| 453 | + } | |
| 454 | + long month1 = jan1 + ACCUMULATED_DAYS_IN_MONTH[month]; | |
| 455 | + if (isLeap && month >= MARCH) { | |
| 456 | + ++month1; | |
| 457 | + } | |
| 458 | + int dayOfMonth = (int)(fixedDate - month1) + 1; | |
| 459 | + int dayOfWeek = getDayOfWeekFromFixedDate(fixedDate); | |
| 460 | + assert dayOfWeek > 0 : "negative day of week " + dayOfWeek; | |
| 461 | + gdate.setNormalizedYear(year); | |
| 462 | + gdate.setMonth(month); | |
| 463 | + gdate.setDayOfMonth(dayOfMonth); | |
| 464 | + gdate.setDayOfWeek(dayOfWeek); | |
| 465 | + gdate.setLeapYear(isLeap); | |
| 466 | + gdate.setNormalized(true); | |
| 467 | + } | |
| 468 | + | |
| 469 | + /** | |
| 470 | + * Returns the day of week of the given Gregorian date. | |
| 471 | + */ | |
| 472 | + public int getDayOfWeek(CalendarDate date) { | |
| 473 | + long fixedDate = getFixedDate(date); | |
| 474 | + return getDayOfWeekFromFixedDate(fixedDate); | |
| 475 | + } | |
| 476 | + | |
| 477 | + public static final int getDayOfWeekFromFixedDate(long fixedDate) { | |
| 478 | + // The fixed day 1 (January 1, 1 Gregorian) is Monday. | |
| 479 | + if (fixedDate >= 0) { | |
| 480 | + return (int)(fixedDate % 7) + SUNDAY; | |
| 481 | + } | |
| 482 | + return (int)CalendarUtils.mod(fixedDate, 7) + SUNDAY; | |
| 483 | + } | |
| 484 | + | |
| 485 | + public int getYearFromFixedDate(long fixedDate) { | |
| 486 | + return getGregorianYearFromFixedDate(fixedDate); | |
| 487 | + } | |
| 488 | + | |
| 489 | + /** | |
| 490 | + * Returns the Gregorian year number of the given fixed date. | |
| 491 | + */ | |
| 492 | + final int getGregorianYearFromFixedDate(long fixedDate) { | |
| 493 | + long d0; | |
| 494 | + int d1, d2, d3, d4; | |
| 495 | + int n400, n100, n4, n1; | |
| 496 | + int year; | |
| 497 | + | |
| 498 | + if (fixedDate > 0) { | |
| 499 | + d0 = fixedDate - 1; | |
| 500 | + n400 = (int)(d0 / 146097); | |
| 501 | + d1 = (int)(d0 % 146097); | |
| 502 | + n100 = d1 / 36524; | |
| 503 | + d2 = d1 % 36524; | |
| 504 | + n4 = d2 / 1461; | |
| 505 | + d3 = d2 % 1461; | |
| 506 | + n1 = d3 / 365; | |
| 507 | + d4 = (d3 % 365) + 1; | |
| 508 | + } else { | |
| 509 | + d0 = fixedDate - 1; | |
| 510 | + n400 = (int)CalendarUtils.floorDivide(d0, 146097L); | |
| 511 | + d1 = (int)CalendarUtils.mod(d0, 146097L); | |
| 512 | + n100 = CalendarUtils.floorDivide(d1, 36524); | |
| 513 | + d2 = CalendarUtils.mod(d1, 36524); | |
| 514 | + n4 = CalendarUtils.floorDivide(d2, 1461); | |
| 515 | + d3 = CalendarUtils.mod(d2, 1461); | |
| 516 | + n1 = CalendarUtils.floorDivide(d3, 365); | |
| 517 | + d4 = CalendarUtils.mod(d3, 365) + 1; | |
| 518 | + } | |
| 519 | + year = 400 * n400 + 100 * n100 + 4 * n4 + n1; | |
| 520 | + if (!(n100 == 4 || n1 == 4)) { | |
| 521 | + ++year; | |
| 522 | + } | |
| 523 | + return year; | |
| 524 | + } | |
| 525 | + | |
| 526 | + /** | |
| 527 | + * @return true if the specified year is a Gregorian leap year, or | |
| 528 | + * false otherwise. | |
| 529 | + * @see BaseCalendar#isGregorianLeapYear | |
| 530 | + */ | |
| 531 | + protected boolean isLeapYear(CalendarDate date) { | |
| 532 | + return isLeapYear(((Date)date).getNormalizedYear()); | |
| 533 | + } | |
| 534 | + | |
| 535 | + boolean isLeapYear(int normalizedYear) { | |
| 536 | + return CalendarUtils.isGregorianLeapYear(normalizedYear); | |
| 537 | + } | |
| 538 | +} | |