0001 /*
0002 * Copyright 1996-2006 Sun Microsystems, Inc. All Rights Reserved.
0003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0004 *
0005 * This code is free software; you can redistribute it and/or modify it
0006 * under the terms of the GNU General Public License version 2 only, as
0007 * published by the Free Software Foundation. Sun designates this
0008 * particular file as subject to the "Classpath" exception as provided
0009 * by Sun in the LICENSE file that accompanied this code.
0010 *
0011 * This code is distributed in the hope that it will be useful, but WITHOUT
0012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0013 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0014 * version 2 for more details (a copy is included in the LICENSE file that
0015 * accompanied this code).
0016 *
0017 * You should have received a copy of the GNU General Public License version
0018 * 2 along with this work; if not, write to the Free Software Foundation,
0019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0020 *
0021 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
0022 * CA 95054 USA or visit www.sun.com if you need additional information or
0023 * have any questions.
0024 */
0025
0026 /*
0027 * (C) Copyright Taligent, Inc. 1996-1998 - All Rights Reserved
0028 * (C) Copyright IBM Corp. 1996-1998 - All Rights Reserved
0029 *
0030 * The original version of this source code and documentation is copyrighted
0031 * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
0032 * materials are provided under terms of a License Agreement between Taligent
0033 * and Sun. This technology is protected by multiple US and International
0034 * patents. This notice and attribution to Taligent may not be removed.
0035 * Taligent is a registered trademark of Taligent, Inc.
0036 *
0037 */
0038
0039 package java.util;
0040
0041 import java.io.IOException;
0042 import java.io.ObjectInputStream;
0043 import sun.util.calendar.BaseCalendar;
0044 import sun.util.calendar.CalendarDate;
0045 import sun.util.calendar.CalendarSystem;
0046 import sun.util.calendar.CalendarUtils;
0047 import sun.util.calendar.Era;
0048 import sun.util.calendar.Gregorian;
0049 import sun.util.calendar.JulianCalendar;
0050 import sun.util.calendar.ZoneInfo;
0051
0052 /**
0053 * <code>GregorianCalendar</code> is a concrete subclass of
0054 * <code>Calendar</code> and provides the standard calendar system
0055 * used by most of the world.
0056 *
0057 * <p> <code>GregorianCalendar</code> is a hybrid calendar that
0058 * supports both the Julian and Gregorian calendar systems with the
0059 * support of a single discontinuity, which corresponds by default to
0060 * the Gregorian date when the Gregorian calendar was instituted
0061 * (October 15, 1582 in some countries, later in others). The cutover
0062 * date may be changed by the caller by calling {@link
0063 * #setGregorianChange(Date) setGregorianChange()}.
0064 *
0065 * <p>
0066 * Historically, in those countries which adopted the Gregorian calendar first,
0067 * October 4, 1582 (Julian) was thus followed by October 15, 1582 (Gregorian). This calendar models
0068 * this correctly. Before the Gregorian cutover, <code>GregorianCalendar</code>
0069 * implements the Julian calendar. The only difference between the Gregorian
0070 * and the Julian calendar is the leap year rule. The Julian calendar specifies
0071 * leap years every four years, whereas the Gregorian calendar omits century
0072 * years which are not divisible by 400.
0073 *
0074 * <p>
0075 * <code>GregorianCalendar</code> implements <em>proleptic</em> Gregorian and
0076 * Julian calendars. That is, dates are computed by extrapolating the current
0077 * rules indefinitely far backward and forward in time. As a result,
0078 * <code>GregorianCalendar</code> may be used for all years to generate
0079 * meaningful and consistent results. However, dates obtained using
0080 * <code>GregorianCalendar</code> are historically accurate only from March 1, 4
0081 * AD onward, when modern Julian calendar rules were adopted. Before this date,
0082 * leap year rules were applied irregularly, and before 45 BC the Julian
0083 * calendar did not even exist.
0084 *
0085 * <p>
0086 * Prior to the institution of the Gregorian calendar, New Year's Day was
0087 * March 25. To avoid confusion, this calendar always uses January 1. A manual
0088 * adjustment may be made if desired for dates that are prior to the Gregorian
0089 * changeover and which fall between January 1 and March 24.
0090 *
0091 * <p>Values calculated for the <code>WEEK_OF_YEAR</code> field range from 1 to
0092 * 53. Week 1 for a year is the earliest seven day period starting on
0093 * <code>getFirstDayOfWeek()</code> that contains at least
0094 * <code>getMinimalDaysInFirstWeek()</code> days from that year. It thus
0095 * depends on the values of <code>getMinimalDaysInFirstWeek()</code>,
0096 * <code>getFirstDayOfWeek()</code>, and the day of the week of January 1.
0097 * Weeks between week 1 of one year and week 1 of the following year are
0098 * numbered sequentially from 2 to 52 or 53 (as needed).
0099
0100 * <p>For example, January 1, 1998 was a Thursday. If
0101 * <code>getFirstDayOfWeek()</code> is <code>MONDAY</code> and
0102 * <code>getMinimalDaysInFirstWeek()</code> is 4 (these are the values
0103 * reflecting ISO 8601 and many national standards), then week 1 of 1998 starts
0104 * on December 29, 1997, and ends on January 4, 1998. If, however,
0105 * <code>getFirstDayOfWeek()</code> is <code>SUNDAY</code>, then week 1 of 1998
0106 * starts on January 4, 1998, and ends on January 10, 1998; the first three days
0107 * of 1998 then are part of week 53 of 1997.
0108 *
0109 * <p>Values calculated for the <code>WEEK_OF_MONTH</code> field range from 0
0110 * to 6. Week 1 of a month (the days with <code>WEEK_OF_MONTH =
0111 * 1</code>) is the earliest set of at least
0112 * <code>getMinimalDaysInFirstWeek()</code> contiguous days in that month,
0113 * ending on the day before <code>getFirstDayOfWeek()</code>. Unlike
0114 * week 1 of a year, week 1 of a month may be shorter than 7 days, need
0115 * not start on <code>getFirstDayOfWeek()</code>, and will not include days of
0116 * the previous month. Days of a month before week 1 have a
0117 * <code>WEEK_OF_MONTH</code> of 0.
0118 *
0119 * <p>For example, if <code>getFirstDayOfWeek()</code> is <code>SUNDAY</code>
0120 * and <code>getMinimalDaysInFirstWeek()</code> is 4, then the first week of
0121 * January 1998 is Sunday, January 4 through Saturday, January 10. These days
0122 * have a <code>WEEK_OF_MONTH</code> of 1. Thursday, January 1 through
0123 * Saturday, January 3 have a <code>WEEK_OF_MONTH</code> of 0. If
0124 * <code>getMinimalDaysInFirstWeek()</code> is changed to 3, then January 1
0125 * through January 3 have a <code>WEEK_OF_MONTH</code> of 1.
0126 *
0127 * <p>The <code>clear</code> methods set calendar field(s)
0128 * undefined. <code>GregorianCalendar</code> uses the following
0129 * default value for each calendar field if its value is undefined.
0130 *
0131 * <table cellpadding="0" cellspacing="3" border="0"
0132 * summary="GregorianCalendar default field values"
0133 * style="text-align: left; width: 66%;">
0134 * <tbody>
0135 * <tr>
0136 * <th style="vertical-align: top; background-color: rgb(204, 204, 255);
0137 * text-align: center;">Field<br>
0138 * </th>
0139 * <th style="vertical-align: top; background-color: rgb(204, 204, 255);
0140 * text-align: center;">Default Value<br>
0141 * </th>
0142 * </tr>
0143 * <tr>
0144 * <td style="vertical-align: middle;">
0145 * <code>ERA<br></code>
0146 * </td>
0147 * <td style="vertical-align: middle;">
0148 * <code>AD<br></code>
0149 * </td>
0150 * </tr>
0151 * <tr>
0152 * <td style="vertical-align: middle; background-color: rgb(238, 238, 255);">
0153 * <code>YEAR<br></code>
0154 * </td>
0155 * <td style="vertical-align: middle; background-color: rgb(238, 238, 255);">
0156 * <code>1970<br></code>
0157 * </td>
0158 * </tr>
0159 * <tr>
0160 * <td style="vertical-align: middle;">
0161 * <code>MONTH<br></code>
0162 * </td>
0163 * <td style="vertical-align: middle;">
0164 * <code>JANUARY<br></code>
0165 * </td>
0166 * </tr>
0167 * <tr>
0168 * <td style="vertical-align: top; background-color: rgb(238, 238, 255);">
0169 * <code>DAY_OF_MONTH<br></code>
0170 * </td>
0171 * <td style="vertical-align: top; background-color: rgb(238, 238, 255);">
0172 * <code>1<br></code>
0173 * </td>
0174 * </tr>
0175 * <tr>
0176 * <td style="vertical-align: middle;">
0177 * <code>DAY_OF_WEEK<br></code>
0178 * </td>
0179 * <td style="vertical-align: middle;">
0180 * <code>the first day of week<br></code>
0181 * </td>
0182 * </tr>
0183 * <tr>
0184 * <td style="vertical-align: top; background-color: rgb(238, 238, 255);">
0185 * <code>WEEK_OF_MONTH<br></code>
0186 * </td>
0187 * <td style="vertical-align: top; background-color: rgb(238, 238, 255);">
0188 * <code>0<br></code>
0189 * </td>
0190 * </tr>
0191 * <tr>
0192 * <td style="vertical-align: top;">
0193 * <code>DAY_OF_WEEK_IN_MONTH<br></code>
0194 * </td>
0195 * <td style="vertical-align: top;">
0196 * <code>1<br></code>
0197 * </td>
0198 * </tr>
0199 * <tr>
0200 * <td style="vertical-align: middle; background-color: rgb(238, 238, 255);">
0201 * <code>AM_PM<br></code>
0202 * </td>
0203 * <td style="vertical-align: middle; background-color: rgb(238, 238, 255);">
0204 * <code>AM<br></code>
0205 * </td>
0206 * </tr>
0207 * <tr>
0208 * <td style="vertical-align: middle;">
0209 * <code>HOUR, HOUR_OF_DAY, MINUTE, SECOND, MILLISECOND<br></code>
0210 * </td>
0211 * <td style="vertical-align: middle;">
0212 * <code>0<br></code>
0213 * </td>
0214 * </tr>
0215 * </tbody>
0216 * </table>
0217 * <br>Default values are not applicable for the fields not listed above.
0218 *
0219 * <p>
0220 * <strong>Example:</strong>
0221 * <blockquote>
0222 * <pre>
0223 * // get the supported ids for GMT-08:00 (Pacific Standard Time)
0224 * String[] ids = TimeZone.getAvailableIDs(-8 * 60 * 60 * 1000);
0225 * // if no ids were returned, something is wrong. get out.
0226 * if (ids.length == 0)
0227 * System.exit(0);
0228 *
0229 * // begin output
0230 * System.out.println("Current Time");
0231 *
0232 * // create a Pacific Standard Time time zone
0233 * SimpleTimeZone pdt = new SimpleTimeZone(-8 * 60 * 60 * 1000, ids[0]);
0234 *
0235 * // set up rules for daylight savings time
0236 * pdt.setStartRule(Calendar.APRIL, 1, Calendar.SUNDAY, 2 * 60 * 60 * 1000);
0237 * pdt.setEndRule(Calendar.OCTOBER, -1, Calendar.SUNDAY, 2 * 60 * 60 * 1000);
0238 *
0239 * // create a GregorianCalendar with the Pacific Daylight time zone
0240 * // and the current date and time
0241 * Calendar calendar = new GregorianCalendar(pdt);
0242 * Date trialTime = new Date();
0243 * calendar.setTime(trialTime);
0244 *
0245 * // print out a bunch of interesting things
0246 * System.out.println("ERA: " + calendar.get(Calendar.ERA));
0247 * System.out.println("YEAR: " + calendar.get(Calendar.YEAR));
0248 * System.out.println("MONTH: " + calendar.get(Calendar.MONTH));
0249 * System.out.println("WEEK_OF_YEAR: " + calendar.get(Calendar.WEEK_OF_YEAR));
0250 * System.out.println("WEEK_OF_MONTH: " + calendar.get(Calendar.WEEK_OF_MONTH));
0251 * System.out.println("DATE: " + calendar.get(Calendar.DATE));
0252 * System.out.println("DAY_OF_MONTH: " + calendar.get(Calendar.DAY_OF_MONTH));
0253 * System.out.println("DAY_OF_YEAR: " + calendar.get(Calendar.DAY_OF_YEAR));
0254 * System.out.println("DAY_OF_WEEK: " + calendar.get(Calendar.DAY_OF_WEEK));
0255 * System.out.println("DAY_OF_WEEK_IN_MONTH: "
0256 * + calendar.get(Calendar.DAY_OF_WEEK_IN_MONTH));
0257 * System.out.println("AM_PM: " + calendar.get(Calendar.AM_PM));
0258 * System.out.println("HOUR: " + calendar.get(Calendar.HOUR));
0259 * System.out.println("HOUR_OF_DAY: " + calendar.get(Calendar.HOUR_OF_DAY));
0260 * System.out.println("MINUTE: " + calendar.get(Calendar.MINUTE));
0261 * System.out.println("SECOND: " + calendar.get(Calendar.SECOND));
0262 * System.out.println("MILLISECOND: " + calendar.get(Calendar.MILLISECOND));
0263 * System.out.println("ZONE_OFFSET: "
0264 * + (calendar.get(Calendar.ZONE_OFFSET)/(60*60*1000)));
0265 * System.out.println("DST_OFFSET: "
0266 * + (calendar.get(Calendar.DST_OFFSET)/(60*60*1000)));
0267
0268 * System.out.println("Current Time, with hour reset to 3");
0269 * calendar.clear(Calendar.HOUR_OF_DAY); // so doesn't override
0270 * calendar.set(Calendar.HOUR, 3);
0271 * System.out.println("ERA: " + calendar.get(Calendar.ERA));
0272 * System.out.println("YEAR: " + calendar.get(Calendar.YEAR));
0273 * System.out.println("MONTH: " + calendar.get(Calendar.MONTH));
0274 * System.out.println("WEEK_OF_YEAR: " + calendar.get(Calendar.WEEK_OF_YEAR));
0275 * System.out.println("WEEK_OF_MONTH: " + calendar.get(Calendar.WEEK_OF_MONTH));
0276 * System.out.println("DATE: " + calendar.get(Calendar.DATE));
0277 * System.out.println("DAY_OF_MONTH: " + calendar.get(Calendar.DAY_OF_MONTH));
0278 * System.out.println("DAY_OF_YEAR: " + calendar.get(Calendar.DAY_OF_YEAR));
0279 * System.out.println("DAY_OF_WEEK: " + calendar.get(Calendar.DAY_OF_WEEK));
0280 * System.out.println("DAY_OF_WEEK_IN_MONTH: "
0281 * + calendar.get(Calendar.DAY_OF_WEEK_IN_MONTH));
0282 * System.out.println("AM_PM: " + calendar.get(Calendar.AM_PM));
0283 * System.out.println("HOUR: " + calendar.get(Calendar.HOUR));
0284 * System.out.println("HOUR_OF_DAY: " + calendar.get(Calendar.HOUR_OF_DAY));
0285 * System.out.println("MINUTE: " + calendar.get(Calendar.MINUTE));
0286 * System.out.println("SECOND: " + calendar.get(Calendar.SECOND));
0287 * System.out.println("MILLISECOND: " + calendar.get(Calendar.MILLISECOND));
0288 * System.out.println("ZONE_OFFSET: "
0289 * + (calendar.get(Calendar.ZONE_OFFSET)/(60*60*1000))); // in hours
0290 * System.out.println("DST_OFFSET: "
0291 * + (calendar.get(Calendar.DST_OFFSET)/(60*60*1000))); // in hours
0292 * </pre>
0293 * </blockquote>
0294 *
0295 * @see TimeZone
0296 * @version 1.99
0297 * @author David Goldsmith, Mark Davis, Chen-Lieh Huang, Alan Liu
0298 * @since JDK1.1
0299 */
0300 public class GregorianCalendar extends Calendar {
0301 /*
0302 * Implementation Notes
0303 *
0304 * The epoch is the number of days or milliseconds from some defined
0305 * starting point. The epoch for java.util.Date is used here; that is,
0306 * milliseconds from January 1, 1970 (Gregorian), midnight UTC. Other
0307 * epochs which are used are January 1, year 1 (Gregorian), which is day 1
0308 * of the Gregorian calendar, and December 30, year 0 (Gregorian), which is
0309 * day 1 of the Julian calendar.
0310 *
0311 * We implement the proleptic Julian and Gregorian calendars. This means we
0312 * implement the modern definition of the calendar even though the
0313 * historical usage differs. For example, if the Gregorian change is set
0314 * to new Date(Long.MIN_VALUE), we have a pure Gregorian calendar which
0315 * labels dates preceding the invention of the Gregorian calendar in 1582 as
0316 * if the calendar existed then.
0317 *
0318 * Likewise, with the Julian calendar, we assume a consistent
0319 * 4-year leap year rule, even though the historical pattern of
0320 * leap years is irregular, being every 3 years from 45 BCE
0321 * through 9 BCE, then every 4 years from 8 CE onwards, with no
0322 * leap years in-between. Thus date computations and functions
0323 * such as isLeapYear() are not intended to be historically
0324 * accurate.
0325 */
0326
0327 //////////////////
0328 // Class Variables
0329 //////////////////
0330 /**
0331 * Value of the <code>ERA</code> field indicating
0332 * the period before the common era (before Christ), also known as BCE.
0333 * The sequence of years at the transition from <code>BC</code> to <code>AD</code> is
0334 * ..., 2 BC, 1 BC, 1 AD, 2 AD,...
0335 *
0336 * @see #ERA
0337 */
0338 public static final int BC = 0;
0339
0340 /**
0341 * Value of the {@link #ERA} field indicating
0342 * the period before the common era, the same value as {@link #BC}.
0343 *
0344 * @see #CE
0345 */
0346 static final int BCE = 0;
0347
0348 /**
0349 * Value of the <code>ERA</code> field indicating
0350 * the common era (Anno Domini), also known as CE.
0351 * The sequence of years at the transition from <code>BC</code> to <code>AD</code> is
0352 * ..., 2 BC, 1 BC, 1 AD, 2 AD,...
0353 *
0354 * @see #ERA
0355 */
0356 public static final int AD = 1;
0357
0358 /**
0359 * Value of the {@link #ERA} field indicating
0360 * the common era, the same value as {@link #AD}.
0361 *
0362 * @see #BCE
0363 */
0364 static final int CE = 1;
0365
0366 private static final int EPOCH_OFFSET = 719163; // Fixed date of January 1, 1970 (Gregorian)
0367 private static final int EPOCH_YEAR = 1970;
0368
0369 static final int MONTH_LENGTH[] = { 31, 28, 31, 30, 31, 30, 31, 31,
0370 30, 31, 30, 31 }; // 0-based
0371 static final int LEAP_MONTH_LENGTH[] = { 31, 29, 31, 30, 31, 30,
0372 31, 31, 30, 31, 30, 31 }; // 0-based
0373
0374 // Useful millisecond constants. Although ONE_DAY and ONE_WEEK can fit
0375 // into ints, they must be longs in order to prevent arithmetic overflow
0376 // when performing (bug 4173516).
0377 private static final int ONE_SECOND = 1000;
0378 private static final int ONE_MINUTE = 60 * ONE_SECOND;
0379 private static final int ONE_HOUR = 60 * ONE_MINUTE;
0380 private static final long ONE_DAY = 24 * ONE_HOUR;
0381 private static final long ONE_WEEK = 7 * ONE_DAY;
0382
0383 /*
0384 * <pre>
0385 * Greatest Least
0386 * Field name Minimum Minimum Maximum Maximum
0387 * ---------- ------- ------- ------- -------
0388 * ERA 0 0 1 1
0389 * YEAR 1 1 292269054 292278994
0390 * MONTH 0 0 11 11
0391 * WEEK_OF_YEAR 1 1 52* 53
0392 * WEEK_OF_MONTH 0 0 4* 6
0393 * DAY_OF_MONTH 1 1 28* 31
0394 * DAY_OF_YEAR 1 1 365* 366
0395 * DAY_OF_WEEK 1 1 7 7
0396 * DAY_OF_WEEK_IN_MONTH -1 -1 4* 6
0397 * AM_PM 0 0 1 1
0398 * HOUR 0 0 11 11
0399 * HOUR_OF_DAY 0 0 23 23
0400 * MINUTE 0 0 59 59
0401 * SECOND 0 0 59 59
0402 * MILLISECOND 0 0 999 999
0403 * ZONE_OFFSET -13:00 -13:00 14:00 14:00
0404 * DST_OFFSET 0:00 0:00 0:20 2:00
0405 * </pre>
0406 * *: depends on the Gregorian change date
0407 */
0408 static final int MIN_VALUES[] = { BCE, // ERA
0409 1, // YEAR
0410 JANUARY, // MONTH
0411 1, // WEEK_OF_YEAR
0412 0, // WEEK_OF_MONTH
0413 1, // DAY_OF_MONTH
0414 1, // DAY_OF_YEAR
0415 SUNDAY, // DAY_OF_WEEK
0416 1, // DAY_OF_WEEK_IN_MONTH
0417 AM, // AM_PM
0418 0, // HOUR
0419 0, // HOUR_OF_DAY
0420 0, // MINUTE
0421 0, // SECOND
0422 0, // MILLISECOND
0423 -13 * ONE_HOUR, // ZONE_OFFSET (UNIX compatibility)
0424 0 // DST_OFFSET
0425 };
0426 static final int LEAST_MAX_VALUES[] = { CE, // ERA
0427 292269054, // YEAR
0428 DECEMBER, // MONTH
0429 52, // WEEK_OF_YEAR
0430 4, // WEEK_OF_MONTH
0431 28, // DAY_OF_MONTH
0432 365, // DAY_OF_YEAR
0433 SATURDAY, // DAY_OF_WEEK
0434 4, // DAY_OF_WEEK_IN
0435 PM, // AM_PM
0436 11, // HOUR
0437 23, // HOUR_OF_DAY
0438 59, // MINUTE
0439 59, // SECOND
0440 999, // MILLISECOND
0441 14 * ONE_HOUR, // ZONE_OFFSET
0442 20 * ONE_MINUTE // DST_OFFSET (historical least maximum)
0443 };
0444 static final int MAX_VALUES[] = { CE, // ERA
0445 292278994, // YEAR
0446 DECEMBER, // MONTH
0447 53, // WEEK_OF_YEAR
0448 6, // WEEK_OF_MONTH
0449 31, // DAY_OF_MONTH
0450 366, // DAY_OF_YEAR
0451 SATURDAY, // DAY_OF_WEEK
0452 6, // DAY_OF_WEEK_IN
0453 PM, // AM_PM
0454 11, // HOUR
0455 23, // HOUR_OF_DAY
0456 59, // MINUTE
0457 59, // SECOND
0458 999, // MILLISECOND
0459 14 * ONE_HOUR, // ZONE_OFFSET
0460 2 * ONE_HOUR // DST_OFFSET (double summer time)
0461 };
0462
0463 // Proclaim serialization compatibility with JDK 1.1
0464 static final long serialVersionUID = -8125100834729963327L;
0465
0466 // Reference to the sun.util.calendar.Gregorian instance (singleton).
0467 private static final Gregorian gcal = CalendarSystem
0468 .getGregorianCalendar();
0469
0470 // Reference to the JulianCalendar instance (singleton), set as needed. See
0471 // getJulianCalendarSystem().
0472 private static JulianCalendar jcal;
0473
0474 // JulianCalendar eras. See getJulianCalendarSystem().
0475 private static Era[] jeras;
0476
0477 // The default value of gregorianCutover.
0478 static final long DEFAULT_GREGORIAN_CUTOVER = -12219292800000L;
0479
0480 /////////////////////
0481 // Instance Variables
0482 /////////////////////
0483
0484 /**
0485 * The point at which the Gregorian calendar rules are used, measured in
0486 * milliseconds from the standard epoch. Default is October 15, 1582
0487 * (Gregorian) 00:00:00 UTC or -12219292800000L. For this value, October 4,
0488 * 1582 (Julian) is followed by October 15, 1582 (Gregorian). This
0489 * corresponds to Julian day number 2299161.
0490 * @serial
0491 */
0492 private long gregorianCutover = DEFAULT_GREGORIAN_CUTOVER;
0493
0494 /**
0495 * The fixed date of the gregorianCutover.
0496 */
0497 private transient long gregorianCutoverDate = (((DEFAULT_GREGORIAN_CUTOVER + 1) / ONE_DAY) - 1)
0498 + EPOCH_OFFSET; // == 577736
0499
0500 /**
0501 * The normalized year of the gregorianCutover in Gregorian, with
0502 * 0 representing 1 BCE, -1 representing 2 BCE, etc.
0503 */
0504 private transient int gregorianCutoverYear = 1582;
0505
0506 /**
0507 * The normalized year of the gregorianCutover in Julian, with 0
0508 * representing 1 BCE, -1 representing 2 BCE, etc.
0509 */
0510 private transient int gregorianCutoverYearJulian = 1582;
0511
0512 /**
0513 * gdate always has a sun.util.calendar.Gregorian.Date instance to
0514 * avoid overhead of creating it. The assumption is that most
0515 * applications will need only Gregorian calendar calculations.
0516 */
0517 private transient BaseCalendar.Date gdate;
0518
0519 /**
0520 * Reference to either gdate or a JulianCalendar.Date
0521 * instance. After calling complete(), this value is guaranteed to
0522 * be set.
0523 */
0524 private transient BaseCalendar.Date cdate;
0525
0526 /**
0527 * The CalendarSystem used to calculate the date in cdate. After
0528 * calling complete(), this value is guaranteed to be set and
0529 * consistent with the cdate value.
0530 */
0531 private transient BaseCalendar calsys;
0532
0533 /**
0534 * Temporary int[2] to get time zone offsets. zoneOffsets[0] gets
0535 * the GMT offset value and zoneOffsets[1] gets the DST saving
0536 * value.
0537 */
0538 private transient int[] zoneOffsets;
0539
0540 /**
0541 * Temporary storage for saving original fields[] values in
0542 * non-lenient mode.
0543 */
0544 private transient int[] originalFields;
0545
0546 ///////////////
0547 // Constructors
0548 ///////////////
0549
0550 /**
0551 * Constructs a default <code>GregorianCalendar</code> using the current time
0552 * in the default time zone with the default locale.
0553 */
0554 public GregorianCalendar() {
0555 this (TimeZone.getDefaultRef(), Locale.getDefault());
0556 setZoneShared(true);
0557 }
0558
0559 /**
0560 * Constructs a <code>GregorianCalendar</code> based on the current time
0561 * in the given time zone with the default locale.
0562 *
0563 * @param zone the given time zone.
0564 */
0565 public GregorianCalendar(TimeZone zone) {
0566 this (zone, Locale.getDefault());
0567 }
0568
0569 /**
0570 * Constructs a <code>GregorianCalendar</code> based on the current time
0571 * in the default time zone with the given locale.
0572 *
0573 * @param aLocale the given locale.
0574 */
0575 public GregorianCalendar(Locale aLocale) {
0576 this (TimeZone.getDefaultRef(), aLocale);
0577 setZoneShared(true);
0578 }
0579
0580 /**
0581 * Constructs a <code>GregorianCalendar</code> based on the current time
0582 * in the given time zone with the given locale.
0583 *
0584 * @param zone the given time zone.
0585 * @param aLocale the given locale.
0586 */
0587 public GregorianCalendar(TimeZone zone, Locale aLocale) {
0588 super (zone, aLocale);
0589 gdate = (BaseCalendar.Date) gcal.newCalendarDate(zone);
0590 setTimeInMillis(System.currentTimeMillis());
0591 }
0592
0593 /**
0594 * Constructs a <code>GregorianCalendar</code> with the given date set
0595 * in the default time zone with the default locale.
0596 *
0597 * @param year the value used to set the <code>YEAR</code> calendar field in the calendar.
0598 * @param month the value used to set the <code>MONTH</code> calendar field in the calendar.
0599 * Month value is 0-based. e.g., 0 for January.
0600 * @param dayOfMonth the value used to set the <code>DAY_OF_MONTH</code> calendar field in the calendar.
0601 */
0602 public GregorianCalendar(int year, int month, int dayOfMonth) {
0603 this (year, month, dayOfMonth, 0, 0, 0, 0);
0604 }
0605
0606 /**
0607 * Constructs a <code>GregorianCalendar</code> with the given date
0608 * and time set for the default time zone with the default locale.
0609 *
0610 * @param year the value used to set the <code>YEAR</code> calendar field in the calendar.
0611 * @param month the value used to set the <code>MONTH</code> calendar field in the calendar.
0612 * Month value is 0-based. e.g., 0 for January.
0613 * @param dayOfMonth the value used to set the <code>DAY_OF_MONTH</code> calendar field in the calendar.
0614 * @param hourOfDay the value used to set the <code>HOUR_OF_DAY</code> calendar field
0615 * in the calendar.
0616 * @param minute the value used to set the <code>MINUTE</code> calendar field
0617 * in the calendar.
0618 */
0619 public GregorianCalendar(int year, int month, int dayOfMonth,
0620 int hourOfDay, int minute) {
0621 this (year, month, dayOfMonth, hourOfDay, minute, 0, 0);
0622 }
0623
0624 /**
0625 * Constructs a GregorianCalendar with the given date
0626 * and time set for the default time zone with the default locale.
0627 *
0628 * @param year the value used to set the <code>YEAR</code> calendar field in the calendar.
0629 * @param month the value used to set the <code>MONTH</code> calendar field in the calendar.
0630 * Month value is 0-based. e.g., 0 for January.
0631 * @param dayOfMonth the value used to set the <code>DAY_OF_MONTH</code> calendar field in the calendar.
0632 * @param hourOfDay the value used to set the <code>HOUR_OF_DAY</code> calendar field
0633 * in the calendar.
0634 * @param minute the value used to set the <code>MINUTE</code> calendar field
0635 * in the calendar.
0636 * @param second the value used to set the <code>SECOND</code> calendar field
0637 * in the calendar.
0638 */
0639 public GregorianCalendar(int year, int month, int dayOfMonth,
0640 int hourOfDay, int minute, int second) {
0641 this (year, month, dayOfMonth, hourOfDay, minute, second, 0);
0642 }
0643
0644 /**
0645 * Constructs a <code>GregorianCalendar</code> with the given date
0646 * and time set for the default time zone with the default locale.
0647 *
0648 * @param year the value used to set the <code>YEAR</code> calendar field in the calendar.
0649 * @param month the value used to set the <code>MONTH</code> calendar field in the calendar.
0650 * Month value is 0-based. e.g., 0 for January.
0651 * @param dayOfMonth the value used to set the <code>DAY_OF_MONTH</code> calendar field in the calendar.
0652 * @param hourOfDay the value used to set the <code>HOUR_OF_DAY</code> calendar field
0653 * in the calendar.
0654 * @param minute the value used to set the <code>MINUTE</code> calendar field
0655 * in the calendar.
0656 * @param second the value used to set the <code>SECOND</code> calendar field
0657 * in the calendar.
0658 * @param millis the value used to set the <code>MILLISECOND</code> calendar field
0659 */
0660 GregorianCalendar(int year, int month, int dayOfMonth,
0661 int hourOfDay, int minute, int second, int millis) {
0662 super ();
0663 gdate = (BaseCalendar.Date) gcal.newCalendarDate(getZone());
0664 this .set(YEAR, year);
0665 this .set(MONTH, month);
0666 this .set(DAY_OF_MONTH, dayOfMonth);
0667
0668 // Set AM_PM and HOUR here to set their stamp values before
0669 // setting HOUR_OF_DAY (6178071).
0670 if (hourOfDay >= 12 && hourOfDay <= 23) {
0671 // If hourOfDay is a valid PM hour, set the correct PM values
0672 // so that it won't throw an exception in case it's set to
0673 // non-lenient later.
0674 this .internalSet(AM_PM, PM);
0675 this .internalSet(HOUR, hourOfDay - 12);
0676 } else {
0677 // The default value for AM_PM is AM.
0678 // We don't care any out of range value here for leniency.
0679 this .internalSet(HOUR, hourOfDay);
0680 }
0681 // The stamp values of AM_PM and HOUR must be COMPUTED. (6440854)
0682 setFieldsComputed(HOUR_MASK | AM_PM_MASK);
0683
0684 this .set(HOUR_OF_DAY, hourOfDay);
0685 this .set(MINUTE, minute);
0686 this .set(SECOND, second);
0687 // should be changed to set() when this constructor is made
0688 // public.
0689 this .internalSet(MILLISECOND, millis);
0690 }
0691
0692 /////////////////
0693 // Public methods
0694 /////////////////
0695
0696 /**
0697 * Sets the <code>GregorianCalendar</code> change date. This is the point when the switch
0698 * from Julian dates to Gregorian dates occurred. Default is October 15,
0699 * 1582 (Gregorian). Previous to this, dates will be in the Julian calendar.
0700 * <p>
0701 * To obtain a pure Julian calendar, set the change date to
0702 * <code>Date(Long.MAX_VALUE)</code>. To obtain a pure Gregorian calendar,
0703 * set the change date to <code>Date(Long.MIN_VALUE)</code>.
0704 *
0705 * @param date the given Gregorian cutover date.
0706 */
0707 public void setGregorianChange(Date date) {
0708 long cutoverTime = date.getTime();
0709 if (cutoverTime == gregorianCutover) {
0710 return;
0711 }
0712 // Before changing the cutover date, make sure to have the
0713 // time of this calendar.
0714 complete();
0715 setGregorianChange(cutoverTime);
0716 }
0717
0718 private void setGregorianChange(long cutoverTime) {
0719 gregorianCutover = cutoverTime;
0720 gregorianCutoverDate = CalendarUtils.floorDivide(cutoverTime,
0721 ONE_DAY)
0722 + EPOCH_OFFSET;
0723
0724 // To provide the "pure" Julian calendar as advertised.
0725 // Strictly speaking, the last millisecond should be a
0726 // Gregorian date. However, the API doc specifies that setting
0727 // the cutover date to Long.MAX_VALUE will make this calendar
0728 // a pure Julian calendar. (See 4167995)
0729 if (cutoverTime == Long.MAX_VALUE) {
0730 gregorianCutoverDate++;
0731 }
0732
0733 BaseCalendar.Date d = getGregorianCutoverDate();
0734
0735 // Set the cutover year (in the Gregorian year numbering)
0736 gregorianCutoverYear = d.getYear();
0737
0738 BaseCalendar jcal = getJulianCalendarSystem();
0739 d = (BaseCalendar.Date) jcal
0740 .newCalendarDate(TimeZone.NO_TIMEZONE);
0741 jcal.getCalendarDateFromFixedDate(d, gregorianCutoverDate - 1);
0742 gregorianCutoverYearJulian = d.getNormalizedYear();
0743
0744 if (time < gregorianCutover) {
0745 // The field values are no longer valid under the new
0746 // cutover date.
0747 setUnnormalized();
0748 }
0749 }
0750
0751 /**
0752 * Gets the Gregorian Calendar change date. This is the point when the
0753 * switch from Julian dates to Gregorian dates occurred. Default is
0754 * October 15, 1582 (Gregorian). Previous to this, dates will be in the Julian
0755 * calendar.
0756 *
0757 * @return the Gregorian cutover date for this <code>GregorianCalendar</code> object.
0758 */
0759 public final Date getGregorianChange() {
0760 return new Date(gregorianCutover);
0761 }
0762
0763 /**
0764 * Determines if the given year is a leap year. Returns <code>true</code> if
0765 * the given year is a leap year. To specify BC year numbers,
0766 * <code>1 - year number</code> must be given. For example, year BC 4 is
0767 * specified as -3.
0768 *
0769 * @param year the given year.
0770 * @return <code>true</code> if the given year is a leap year; <code>false</code> otherwise.
0771 */
0772 public boolean isLeapYear(int year) {
0773 if ((year & 3) != 0) {
0774 return false;
0775 }
0776
0777 if (year > gregorianCutoverYear) {
0778 return (year % 100 != 0) || (year % 400 == 0); // Gregorian
0779 }
0780 if (year < gregorianCutoverYearJulian) {
0781 return true; // Julian
0782 }
0783 boolean gregorian;
0784 // If the given year is the Gregorian cutover year, we need to
0785 // determine which calendar system to be applied to February in the year.
0786 if (gregorianCutoverYear == gregorianCutoverYearJulian) {
0787 BaseCalendar.Date d = getCalendarDate(gregorianCutoverDate); // Gregorian
0788 gregorian = d.getMonth() < BaseCalendar.MARCH;
0789 } else {
0790 gregorian = year == gregorianCutoverYear;
0791 }
0792 return gregorian ? (year % 100 != 0) || (year % 400 == 0)
0793 : true;
0794 }
0795
0796 /**
0797 * Compares this <code>GregorianCalendar</code> to the specified
0798 * <code>Object</code>. The result is <code>true</code> if and
0799 * only if the argument is a <code>GregorianCalendar</code> object
0800 * that represents the same time value (millisecond offset from
0801 * the <a href="Calendar.html#Epoch">Epoch</a>) under the same
0802 * <code>Calendar</code> parameters and Gregorian change date as
0803 * this object.
0804 *
0805 * @param obj the object to compare with.
0806 * @return <code>true</code> if this object is equal to <code>obj</code>;
0807 * <code>false</code> otherwise.
0808 * @see Calendar#compareTo(Calendar)
0809 */
0810 public boolean equals(Object obj) {
0811 return obj instanceof GregorianCalendar
0812 && super .equals(obj)
0813 && gregorianCutover == ((GregorianCalendar) obj).gregorianCutover;
0814 }
0815
0816 /**
0817 * Generates the hash code for this <code>GregorianCalendar</code> object.
0818 */
0819 public int hashCode() {
0820 return super .hashCode() ^ (int) gregorianCutoverDate;
0821 }
0822
0823 /**
0824 * Adds the specified (signed) amount of time to the given calendar field,
0825 * based on the calendar's rules.
0826 *
0827 * <p><em>Add rule 1</em>. The value of <code>field</code>
0828 * after the call minus the value of <code>field</code> before the
0829 * call is <code>amount</code>, modulo any overflow that has occurred in
0830 * <code>field</code>. Overflow occurs when a field value exceeds its
0831 * range and, as a result, the next larger field is incremented or
0832 * decremented and the field value is adjusted back into its range.</p>
0833 *
0834 * <p><em>Add rule 2</em>. If a smaller field is expected to be
0835 * invariant, but it is impossible for it to be equal to its
0836 * prior value because of changes in its minimum or maximum after
0837 * <code>field</code> is changed, then its value is adjusted to be as close
0838 * as possible to its expected value. A smaller field represents a
0839 * smaller unit of time. <code>HOUR</code> is a smaller field than
0840 * <code>DAY_OF_MONTH</code>. No adjustment is made to smaller fields
0841 * that are not expected to be invariant. The calendar system
0842 * determines what fields are expected to be invariant.</p>
0843 *
0844 * @param field the calendar field.
0845 * @param amount the amount of date or time to be added to the field.
0846 * @exception IllegalArgumentException if <code>field</code> is
0847 * <code>ZONE_OFFSET</code>, <code>DST_OFFSET</code>, or unknown,
0848 * or if any calendar fields have out-of-range values in
0849 * non-lenient mode.
0850 */
0851 public void add(int field, int amount) {
0852 // If amount == 0, do nothing even the given field is out of
0853 // range. This is tested by JCK.
0854 if (amount == 0) {
0855 return; // Do nothing!
0856 }
0857
0858 if (field < 0 || field >= ZONE_OFFSET) {
0859 throw new IllegalArgumentException();
0860 }
0861
0862 // Sync the time and calendar fields.
0863 complete();
0864
0865 if (field == YEAR) {
0866 int year = internalGet(YEAR);
0867 if (internalGetEra() == CE) {
0868 year += amount;
0869 if (year > 0) {
0870 set(YEAR, year);
0871 } else { // year <= 0
0872 set(YEAR, 1 - year);
0873 // if year == 0, you get 1 BCE.
0874 set(ERA, BCE);
0875 }
0876 } else { // era == BCE
0877 year -= amount;
0878 if (year > 0) {
0879 set(YEAR, year);
0880 } else { // year <= 0
0881 set(YEAR, 1 - year);
0882 // if year == 0, you get 1 CE
0883 set(ERA, CE);
0884 }
0885 }
0886 pinDayOfMonth();
0887 } else if (field == MONTH) {
0888 int month = internalGet(MONTH) + amount;
0889 int year = internalGet(YEAR);
0890 int y_amount;
0891
0892 if (month >= 0) {
0893 y_amount = month / 12;
0894 } else {
0895 y_amount = (month + 1) / 12 - 1;
0896 }
0897 if (y_amount != 0) {
0898 if (internalGetEra() == CE) {
0899 year += y_amount;
0900 if (year > 0) {
0901 set(YEAR, year);
0902 } else { // year <= 0
0903 set(YEAR, 1 - year);
0904 // if year == 0, you get 1 BCE
0905 set(ERA, BCE);
0906 }
0907 } else { // era == BCE
0908 year -= y_amount;
0909 if (year > 0) {
0910 set(YEAR, year);
0911 } else { // year <= 0
0912 set(YEAR, 1 - year);
0913 // if year == 0, you get 1 CE
0914 set(ERA, CE);
0915 }
0916 }
0917 }
0918
0919 if (month >= 0) {
0920 set(MONTH, (int) (month % 12));
0921 } else {
0922 // month < 0
0923 month %= 12;
0924 if (month < 0) {
0925 month += 12;
0926 }
0927 set(MONTH, JANUARY + month);
0928 }
0929 pinDayOfMonth();
0930 } else if (field == ERA) {
0931 int era = internalGet(ERA) + amount;
0932 if (era < 0) {
0933 era = 0;
0934 }
0935 if (era > 1) {
0936 era = 1;
0937 }
0938 set(ERA, era);
0939 } else {
0940 long delta = amount;
0941 long timeOfDay = 0;
0942 switch (field) {
0943 // Handle the time fields here. Convert the given
0944 // amount to milliseconds and call setTimeInMillis.
0945 case HOUR:
0946 case HOUR_OF_DAY:
0947 delta *= 60 * 60 * 1000; // hours to minutes
0948 break;
0949
0950 case MINUTE:
0951 delta *= 60 * 1000; // minutes to seconds
0952 break;
0953
0954 case SECOND:
0955 delta *= 1000; // seconds to milliseconds
0956 break;
0957
0958 case MILLISECOND:
0959 break;
0960
0961 // Handle week, day and AM_PM fields which involves
0962 // time zone offset change adjustment. Convert the
0963 // given amount to the number of days.
0964 case WEEK_OF_YEAR:
0965 case WEEK_OF_MONTH:
0966 case DAY_OF_WEEK_IN_MONTH:
0967 delta *= 7;
0968 break;
0969
0970 case DAY_OF_MONTH: // synonym of DATE
0971 case DAY_OF_YEAR:
0972 case DAY_OF_WEEK:
0973 break;
0974
0975 case AM_PM:
0976 // Convert the amount to the number of days (delta)
0977 // and +12 or -12 hours (timeOfDay).
0978 delta = amount / 2;
0979 timeOfDay = 12 * (amount % 2);
0980 break;
0981 }
0982
0983 // The time fields don't require time zone offset change
0984 // adjustment.
0985 if (field >= HOUR) {
0986 setTimeInMillis(time + delta);
0987 return;
0988 }
0989
0990 // The rest of the fields (week, day or AM_PM fields)
0991 // require time zone offset (both GMT and DST) change
0992 // adjustment.
0993
0994 // Translate the current time to the fixed date and time
0995 // of the day.
0996 long fd = getCurrentFixedDate();
0997 timeOfDay += internalGet(HOUR_OF_DAY);
0998 timeOfDay *= 60;
0999 timeOfDay += internalGet(MINUTE);
1000 timeOfDay *= 60;
1001 timeOfDay += internalGet(SECOND);
1002 timeOfDay *= 1000;
1003 timeOfDay += internalGet(MILLISECOND);
1004 if (timeOfDay >= ONE_DAY) {
1005 fd++;
1006 timeOfDay -= ONE_DAY;
1007 } else if (timeOfDay < 0) {
1008 fd--;
1009 timeOfDay += ONE_DAY;
1010 }
1011
1012 fd += delta; // fd is the expected fixed date after the calculation
1013 int zoneOffset = internalGet(ZONE_OFFSET)
1014 + internalGet(DST_OFFSET);
1015 setTimeInMillis((fd - EPOCH_OFFSET) * ONE_DAY + timeOfDay
1016 - zoneOffset);
1017 zoneOffset -= internalGet(ZONE_OFFSET)
1018 + internalGet(DST_OFFSET);
1019 // If the time zone offset has changed, then adjust the difference.
1020 if (zoneOffset != 0) {
1021 setTimeInMillis(time + zoneOffset);
1022 long fd2 = getCurrentFixedDate();
1023 // If the adjustment has changed the date, then take
1024 // the previous one.
1025 if (fd2 != fd) {
1026 setTimeInMillis(time - zoneOffset);
1027 }
1028 }
1029 }
1030 }
1031
1032 /**
1033 * Adds or subtracts (up/down) a single unit of time on the given time
1034 * field without changing larger fields.
1035 * <p>
1036 * <em>Example</em>: Consider a <code>GregorianCalendar</code>
1037 * originally set to December 31, 1999. Calling {@link #roll(int,boolean) roll(Calendar.MONTH, true)}
1038 * sets the calendar to January 31, 1999. The <code>YEAR</code> field is unchanged
1039 * because it is a larger field than <code>MONTH</code>.</p>
1040 *
1041 * @param up indicates if the value of the specified calendar field is to be
1042 * rolled up or rolled down. Use <code>true</code> if rolling up, <code>false</code> otherwise.
1043 * @exception IllegalArgumentException if <code>field</code> is
1044 * <code>ZONE_OFFSET</code>, <code>DST_OFFSET</code>, or unknown,
1045 * or if any calendar fields have out-of-range values in
1046 * non-lenient mode.
1047 * @see #add(int,int)
1048 * @see #set(int,int)
1049 */
1050 public void roll(int field, boolean up) {
1051 roll(field, up ? +1 : -1);
1052 }
1053
1054 /**
1055 * Adds a signed amount to the specified calendar field without changing larger fields.
1056 * A negative roll amount means to subtract from field without changing
1057 * larger fields. If the specified amount is 0, this method performs nothing.
1058 *
1059 * <p>This method calls {@link #complete()} before adding the
1060 * amount so that all the calendar fields are normalized. If there
1061 * is any calendar field having an out-of-range value in non-lenient mode, then an
1062 * <code>IllegalArgumentException</code> is thrown.
1063 *
1064 * <p>
1065 * <em>Example</em>: Consider a <code>GregorianCalendar</code>
1066 * originally set to August 31, 1999. Calling <code>roll(Calendar.MONTH,
1067 * 8)</code> sets the calendar to April 30, <strong>1999</strong>. Using a
1068 * <code>GregorianCalendar</code>, the <code>DAY_OF_MONTH</code> field cannot
1069 * be 31 in the month April. <code>DAY_OF_MONTH</code> is set to the closest possible
1070 * value, 30. The <code>YEAR</code> field maintains the value of 1999 because it
1071 * is a larger field than <code>MONTH</code>.
1072 * <p>
1073 * <em>Example</em>: Consider a <code>GregorianCalendar</code>
1074 * originally set to Sunday June 6, 1999. Calling
1075 * <code>roll(Calendar.WEEK_OF_MONTH, -1)</code> sets the calendar to
1076 * Tuesday June 1, 1999, whereas calling
1077 * <code>add(Calendar.WEEK_OF_MONTH, -1)</code> sets the calendar to
1078 * Sunday May 30, 1999. This is because the roll rule imposes an
1079 * additional constraint: The <code>MONTH</code> must not change when the
1080 * <code>WEEK_OF_MONTH</code> is rolled. Taken together with add rule 1,
1081 * the resultant date must be between Tuesday June 1 and Saturday June
1082 * 5. According to add rule 2, the <code>DAY_OF_WEEK</code>, an invariant
1083 * when changing the <code>WEEK_OF_MONTH</code>, is set to Tuesday, the
1084 * closest possible value to Sunday (where Sunday is the first day of the
1085 * week).</p>
1086 *
1087 * @param field the calendar field.
1088 * @param amount the signed amount to add to <code>field</code>.
1089 * @exception IllegalArgumentException if <code>field</code> is
1090 * <code>ZONE_OFFSET</code>, <code>DST_OFFSET</code>, or unknown,
1091 * or if any calendar fields have out-of-range values in
1092 * non-lenient mode.
1093 * @see #roll(int,boolean)
1094 * @see #add(int,int)
1095 * @see #set(int,int)
1096 * @since 1.2
1097 */
1098 public void roll(int field, int amount) {
1099 // If amount == 0, do nothing even the given field is out of
1100 // range. This is tested by JCK.
1101 if (amount == 0) {
1102 return;
1103 }
1104
1105 if (field < 0 || field >= ZONE_OFFSET) {
1106 throw new IllegalArgumentException();
1107 }
1108
1109 // Sync the time and calendar fields.
1110 complete();
1111
1112 int min = getMinimum(field);
1113 int max = getMaximum(field);
1114
1115 switch (field) {
1116 case AM_PM:
1117 case ERA:
1118 case YEAR:
1119 case MINUTE:
1120 case SECOND:
1121 case MILLISECOND:
1122 // These fields are handled simply, since they have fixed minima
1123 // and maxima. The field DAY_OF_MONTH is almost as simple. Other
1124 // fields are complicated, since the range within they must roll
1125 // varies depending on the date.
1126 break;
1127
1128 case HOUR:
1129 case HOUR_OF_DAY: {
1130 int unit = max + 1; // 12 or 24 hours
1131 int h = internalGet(field);
1132 int nh = (h + amount) % unit;
1133 if (nh < 0) {
1134 nh += unit;
1135 }
1136 time += ONE_HOUR * (nh - h);
1137
1138 // The day might have changed, which could happen if
1139 // the daylight saving time transition brings it to
1140 // the next day, although it's very unlikely. But we
1141 // have to make sure not to change the larger fields.
1142 CalendarDate d = calsys.getCalendarDate(time, getZone());
1143 if (internalGet(DAY_OF_MONTH) != d.getDayOfMonth()) {
1144 d.setDate(internalGet(YEAR), internalGet(MONTH) + 1,
1145 internalGet(DAY_OF_MONTH));
1146 if (field == HOUR) {
1147 assert (internalGet(AM_PM) == PM);
1148 d.addHours(+12); // restore PM
1149 }
1150 time = calsys.getTime(d);
1151 }
1152 int hourOfDay = d.getHours();
1153 internalSet(field, hourOfDay % unit);
1154 if (field == HOUR) {
1155 internalSet(HOUR_OF_DAY, hourOfDay);
1156 } else {
1157 internalSet(AM_PM, hourOfDay / 12);
1158 internalSet(HOUR, hourOfDay % 12);
1159 }
1160
1161 // Time zone offset and/or daylight saving might have changed.
1162 int zoneOffset = d.getZoneOffset();
1163 int saving = d.getDaylightSaving();
1164 internalSet(ZONE_OFFSET, zoneOffset - saving);
1165 internalSet(DST_OFFSET, saving);
1166 return;
1167 }
1168
1169 case MONTH:
1170 // Rolling the month involves both pinning the final value to [0, 11]
1171 // and adjusting the DAY_OF_MONTH if necessary. We only adjust the
1172 // DAY_OF_MONTH if, after updating the MONTH field, it is illegal.
1173 // E.g., <jan31>.roll(MONTH, 1) -> <feb28> or <feb29>.
1174 {
1175 if (!isCutoverYear(cdate.getNormalizedYear())) {
1176 int mon = (internalGet(MONTH) + amount) % 12;
1177 if (mon < 0) {
1178 mon += 12;
1179 }
1180 set(MONTH, mon);
1181
1182 // Keep the day of month in the range. We don't want to spill over
1183 // into the next month; e.g., we don't want jan31 + 1 mo -> feb31 ->
1184 // mar3.
1185 int monthLen = monthLength(mon);
1186 if (internalGet(DAY_OF_MONTH) > monthLen) {
1187 set(DAY_OF_MONTH, monthLen);
1188 }
1189 } else {
1190 // We need to take care of different lengths in
1191 // year and month due to the cutover.
1192 int yearLength = getActualMaximum(MONTH) + 1;
1193 int mon = (internalGet(MONTH) + amount) % yearLength;
1194 if (mon < 0) {
1195 mon += yearLength;
1196 }
1197 set(MONTH, mon);
1198 int monthLen = getActualMaximum(DAY_OF_MONTH);
1199 if (internalGet(DAY_OF_MONTH) > monthLen) {
1200 set(DAY_OF_MONTH, monthLen);
1201 }
1202 }
1203 return;
1204 }
1205
1206 case WEEK_OF_YEAR: {
1207 int y = cdate.getNormalizedYear();
1208 max = getActualMaximum(WEEK_OF_YEAR);
1209 set(DAY_OF_WEEK, internalGet(DAY_OF_WEEK));
1210 int woy = internalGet(WEEK_OF_YEAR);
1211 int value = woy + amount;
1212 if (!isCutoverYear(y)) {
1213 // If the new value is in between min and max
1214 // (exclusive), then we can use the value.
1215 if (value > min && value < max) {
1216 set(WEEK_OF_YEAR, value);
1217 return;
1218 }
1219 long fd = getCurrentFixedDate();
1220 // Make sure that the min week has the current DAY_OF_WEEK
1221 long day1 = fd - (7 * (woy - min));
1222 if (calsys.getYearFromFixedDate(day1) != y) {
1223 min++;
1224 }
1225
1226 // Make sure the same thing for the max week
1227 fd += 7 * (max - internalGet(WEEK_OF_YEAR));
1228 if (calsys.getYearFromFixedDate(fd) != y) {
1229 max--;
1230 }
1231 break;
1232 }
1233
1234 // Handle cutover here.
1235 long fd = getCurrentFixedDate();
1236 BaseCalendar cal;
1237 if (gregorianCutoverYear == gregorianCutoverYearJulian) {
1238 cal = getCutoverCalendarSystem();
1239 } else if (y == gregorianCutoverYear) {
1240 cal = gcal;
1241 } else {
1242 cal = getJulianCalendarSystem();
1243 }
1244 long day1 = fd - (7 * (woy - min));
1245 // Make sure that the min week has the current DAY_OF_WEEK
1246 if (cal.getYearFromFixedDate(day1) != y) {
1247 min++;
1248 }
1249
1250 // Make sure the same thing for the max week
1251 fd += 7 * (max - woy);
1252 cal = (fd >= gregorianCutoverDate) ? gcal
1253 : getJulianCalendarSystem();
1254 if (cal.getYearFromFixedDate(fd) != y) {
1255 max--;
1256 }
1257 // value: the new WEEK_OF_YEAR which must be converted
1258 // to month and day of month.
1259 value = getRolledValue(woy, amount, min, max) - 1;
1260 BaseCalendar.Date d = getCalendarDate(day1 + value * 7);
1261 set(MONTH, d.getMonth() - 1);
1262 set(DAY_OF_MONTH, d.getDayOfMonth());
1263 return;
1264 }
1265
1266 case WEEK_OF_MONTH: {
1267 boolean isCutoverYear = isCutoverYear(cdate
1268 .getNormalizedYear());
1269 // dow: relative day of week from first day of week
1270 int dow = internalGet(DAY_OF_WEEK) - getFirstDayOfWeek();
1271 if (dow < 0) {
1272 dow += 7;
1273 }
1274
1275 long fd = getCurrentFixedDate();
1276 long month1; // fixed date of the first day (usually 1) of the month
1277 int monthLength; // actual month length
1278 if (isCutoverYear) {
1279 month1 = getFixedDateMonth1(cdate, fd);
1280 monthLength = actualMonthLength();
1281 } else {
1282 month1 = fd - internalGet(DAY_OF_MONTH) + 1;
1283 monthLength = calsys.getMonthLength(cdate);
1284 }
1285
1286 // the first day of week of the month.
1287 long monthDay1st = calsys.getDayOfWeekDateOnOrBefore(
1288 month1 + 6, getFirstDayOfWeek());
1289 // if the week has enough days to form a week, the
1290 // week starts from the previous month.
1291 if ((int) (monthDay1st - month1) >= getMinimalDaysInFirstWeek()) {
1292 monthDay1st -= 7;
1293 }
1294 max = getActualMaximum(field);
1295
1296 // value: the new WEEK_OF_MONTH value
1297 int value = getRolledValue(internalGet(field), amount, 1,
1298 max) - 1;
1299
1300 // nfd: fixed date of the rolled date
1301 long nfd = monthDay1st + value * 7 + dow;
1302
1303 // Unlike WEEK_OF_YEAR, we need to change day of week if the
1304 // nfd is out of the month.
1305 if (nfd < month1) {
1306 nfd = month1;
1307 } else if (nfd >= (month1 + monthLength)) {
1308 nfd = month1 + monthLength - 1;
1309 }
1310 int dayOfMonth;
1311 if (isCutoverYear) {
1312 // If we are in the cutover year, convert nfd to
1313 // its calendar date and use dayOfMonth.
1314 BaseCalendar.Date d = getCalendarDate(nfd);
1315 dayOfMonth = d.getDayOfMonth();
1316 } else {
1317 dayOfMonth = (int) (nfd - month1) + 1;
1318 }
1319 set(DAY_OF_MONTH, dayOfMonth);
1320 return;
1321 }
1322
1323 case DAY_OF_MONTH: {
1324 if (!isCutoverYear(cdate.getNormalizedYear())) {
1325 max = calsys.getMonthLength(cdate);
1326 break;
1327 }
1328
1329 // Cutover year handling
1330 long fd = getCurrentFixedDate();
1331 long month1 = getFixedDateMonth1(cdate, fd);
1332 // It may not be a regular month. Convert the date and range to
1333 // the relative values, perform the roll, and
1334 // convert the result back to the rolled date.
1335 int value = getRolledValue((int) (fd - month1), amount, 0,
1336 actualMonthLength() - 1);
1337 BaseCalendar.Date d = getCalendarDate(month1 + value);
1338 assert d.getMonth() - 1 == internalGet(MONTH);
1339 set(DAY_OF_MONTH, d.getDayOfMonth());
1340 return;
1341 }
1342
1343 case DAY_OF_YEAR: {
1344 max = getActualMaximum(field);
1345 if (!isCutoverYear(cdate.getNormalizedYear())) {
1346 break;
1347 }
1348
1349 // Handle cutover here.
1350 long fd = getCurrentFixedDate();
1351 long jan1 = fd - internalGet(DAY_OF_YEAR) + 1;
1352 int value = getRolledValue((int) (fd - jan1) + 1, amount,
1353 min, max);
1354 BaseCalendar.Date d = getCalendarDate(jan1 + value - 1);
1355 set(MONTH, d.getMonth() - 1);
1356 set(DAY_OF_MONTH, d.getDayOfMonth());
1357 return;
1358 }
1359
1360 case DAY_OF_WEEK: {
1361 if (!isCutoverYear(cdate.getNormalizedYear())) {
1362 // If the week of year is in the same year, we can
1363 // just change DAY_OF_WEEK.
1364 int weekOfYear = internalGet(WEEK_OF_YEAR);
1365 if (weekOfYear > 1 && weekOfYear < 52) {
1366 set(WEEK_OF_YEAR, weekOfYear); // update stamp[WEEK_OF_YEAR]
1367 max = SATURDAY;
1368 break;
1369 }
1370 }
1371
1372 // We need to handle it in a different way around year
1373 // boundaries and in the cutover year. Note that
1374 // changing era and year values violates the roll
1375 // rule: not changing larger calendar fields...
1376 amount %= 7;
1377 if (amount == 0) {
1378 return;
1379 }
1380 long fd = getCurrentFixedDate();
1381 long dowFirst = calsys.getDayOfWeekDateOnOrBefore(fd,
1382 getFirstDayOfWeek());
1383 fd += amount;
1384 if (fd < dowFirst) {
1385 fd += 7;
1386 } else if (fd >= dowFirst + 7) {
1387 fd -= 7;
1388 }
1389 BaseCalendar.Date d = getCalendarDate(fd);
1390 set(ERA, (d.getNormalizedYear() <= 0 ? BCE : CE));
1391 set(d.getYear(), d.getMonth() - 1, d.getDayOfMonth());
1392 return;
1393 }
1394
1395 case DAY_OF_WEEK_IN_MONTH: {
1396 min = 1; // after normalized, min should be 1.
1397 if (!isCutoverYear(cdate.getNormalizedYear())) {
1398 int dom = internalGet(DAY_OF_MONTH);
1399 int monthLength = calsys.getMonthLength(cdate);
1400 int lastDays = monthLength % 7;
1401 max = monthLength / 7;
1402 int x = (dom - 1) % 7;
1403 if (x < lastDays) {
1404 max++;
1405 }
1406 set(DAY_OF_WEEK, internalGet(DAY_OF_WEEK));
1407 break;
1408 }
1409
1410 // Cutover year handling
1411 long fd = getCurrentFixedDate();
1412 long month1 = getFixedDateMonth1(cdate, fd);
1413 int monthLength = actualMonthLength();
1414 int lastDays = monthLength % 7;
1415 max = monthLength / 7;
1416 int x = (int) (fd - month1) % 7;
1417 if (x < lastDays) {
1418 max++;
1419 }
1420 int value = getRolledValue(internalGet(field), amount, min,
1421 max) - 1;
1422 fd = month1 + value * 7 + x;
1423 BaseCalendar cal = (fd >= gregorianCutoverDate) ? gcal
1424 : getJulianCalendarSystem();
1425 BaseCalendar.Date d = (BaseCalendar.Date) cal
1426 .newCalendarDate(TimeZone.NO_TIMEZONE);
1427 cal.getCalendarDateFromFixedDate(d, fd);
1428 set(DAY_OF_MONTH, d.getDayOfMonth());
1429 return;
1430 }
1431 }
1432
1433 set(field, getRolledValue(internalGet(field), amount, min, max));
1434 }
1435
1436 /**
1437 * Returns the minimum value for the given calendar field of this
1438 * <code>GregorianCalendar</code> instance. The minimum value is
1439 * defined as the smallest value returned by the {@link
1440 * Calendar#get(int) get} method for any possible time value,
1441 * taking into consideration the current values of the
1442 * {@link Calendar#getFirstDayOfWeek() getFirstDayOfWeek},
1443 * {@link Calendar#getMinimalDaysInFirstWeek() getMinimalDaysInFirstWeek},
1444 * {@link #getGregorianChange() getGregorianChange} and
1445 * {@link Calendar#getTimeZone() getTimeZone} methods.
1446 *
1447 * @param field the calendar field.
1448 * @return the minimum value for the given calendar field.
1449 * @see #getMaximum(int)
1450 * @see #getGreatestMinimum(int)
1451 * @see #getLeastMaximum(int)
1452 * @see #getActualMinimum(int)
1453 * @see #getActualMaximum(int)
1454 */
1455 public int getMinimum(int field) {
1456 return MIN_VALUES[field];
1457 }
1458
1459 /**
1460 * Returns the maximum value for the given calendar field of this
1461 * <code>GregorianCalendar</code> instance. The maximum value is
1462 * defined as the largest value returned by the {@link
1463 * Calendar#get(int) get} method for any possible time value,
1464 * taking into consideration the current values of the
1465 * {@link Calendar#getFirstDayOfWeek() getFirstDayOfWeek},
1466 * {@link Calendar#getMinimalDaysInFirstWeek() getMinimalDaysInFirstWeek},
1467 * {@link #getGregorianChange() getGregorianChange} and
1468 * {@link Calendar#getTimeZone() getTimeZone} methods.
1469 *
1470 * @param field the calendar field.
1471 * @return the maximum value for the given calendar field.
1472 * @see #getMinimum(int)
1473 * @see #getGreatestMinimum(int)
1474 * @see #getLeastMaximum(int)
1475 * @see #getActualMinimum(int)
1476 * @see #getActualMaximum(int)
1477 */
1478 public int getMaximum(int field) {
1479 switch (field) {
1480 case MONTH:
1481 case DAY_OF_MONTH:
1482 case DAY_OF_YEAR:
1483 case WEEK_OF_YEAR:
1484 case WEEK_OF_MONTH:
1485 case DAY_OF_WEEK_IN_MONTH:
1486 case YEAR: {
1487 // On or after Gregorian 200-3-1, Julian and Gregorian
1488 // calendar dates are the same or Gregorian dates are
1489 // larger (i.e., there is a "gap") after 300-3-1.
1490 if (gregorianCutoverYear > 200) {
1491 break;
1492 }
1493 // There might be "overlapping" dates.
1494 GregorianCalendar gc = (GregorianCalendar) clone();
1495 gc.setLenient(true);
1496 gc.setTimeInMillis(gregorianCutover);
1497 int v1 = gc.getActualMaximum(field);
1498 gc.setTimeInMillis(gregorianCutover - 1);
1499 int v2 = gc.getActualMaximum(field);
1500 return Math.max(MAX_VALUES[field], Math.max(v1, v2));
1501 }
1502 }
1503 return MAX_VALUES[field];
1504 }
1505
1506 /**
1507 * Returns the highest minimum value for the given calendar field
1508 * of this <code>GregorianCalendar</code> instance. The highest
1509 * minimum value is defined as the largest value returned by
1510 * {@link #getActualMinimum(int)} for any possible time value,
1511 * taking into consideration the current values of the
1512 * {@link Calendar#getFirstDayOfWeek() getFirstDayOfWeek},
1513 * {@link Calendar#getMinimalDaysInFirstWeek() getMinimalDaysInFirstWeek},
1514 * {@link #getGregorianChange() getGregorianChange} and
1515 * {@link Calendar#getTimeZone() getTimeZone} methods.
1516 *
1517 * @param field the calendar field.
1518 * @return the highest minimum value for the given calendar field.
1519 * @see #getMinimum(int)
1520 * @see #getMaximum(int)
1521 * @see #getLeastMaximum(int)
1522 * @see #getActualMinimum(int)
1523 * @see #getActualMaximum(int)
1524 */
1525 public int getGreatestMinimum(int field) {
1526 if (field == DAY_OF_MONTH) {
1527 BaseCalendar.Date d = getGregorianCutoverDate();
1528 long mon1 = getFixedDateMonth1(d, gregorianCutoverDate);
1529 d = getCalendarDate(mon1);
1530 return Math.max(MIN_VALUES[field], d.getDayOfMonth());
1531 }
1532 return MIN_VALUES[field];
1533 }
1534
1535 /**
1536 * Returns the lowest maximum value for the given calendar field
1537 * of this <code>GregorianCalendar</code> instance. The lowest
1538 * maximum value is defined as the smallest value returned by
1539 * {@link #getActualMaximum(int)} for any possible time value,
1540 * taking into consideration the current values of the
1541 * {@link Calendar#getFirstDayOfWeek() getFirstDayOfWeek},
1542 * {@link Calendar#getMinimalDaysInFirstWeek() getMinimalDaysInFirstWeek},
1543 * {@link #getGregorianChange() getGregorianChange} and
1544 * {@link Calendar#getTimeZone() getTimeZone} methods.
1545 *
1546 * @param field the calendar field
1547 * @return the lowest maximum value for the given calendar field.
1548 * @see #getMinimum(int)
1549 * @see #getMaximum(int)
1550 * @see #getGreatestMinimum(int)
1551 * @see #getActualMinimum(int)
1552 * @see #getActualMaximum(int)
1553 */
1554 public int getLeastMaximum(int field) {
1555 switch (field) {
1556 case MONTH:
1557 case DAY_OF_MONTH:
1558 case DAY_OF_YEAR:
1559 case WEEK_OF_YEAR:
1560 case WEEK_OF_MONTH:
1561 case DAY_OF_WEEK_IN_MONTH:
1562 case YEAR: {
1563 GregorianCalendar gc = (GregorianCalendar) clone();
1564 gc.setLenient(true);
1565 gc.setTimeInMillis(gregorianCutover);
1566 int v1 = gc.getActualMaximum(field);
1567 gc.setTimeInMillis(gregorianCutover - 1);
1568 int v2 = gc.getActualMaximum(field);
1569 return Math.min(LEAST_MAX_VALUES[field], Math.min(v1, v2));
1570 }
1571 }
1572 return LEAST_MAX_VALUES[field];
1573 }
1574
1575 /**
1576 * Returns the minimum value that this calendar field could have,
1577 * taking into consideration the given time value and the current
1578 * values of the
1579 * {@link Calendar#getFirstDayOfWeek() getFirstDayOfWeek},
1580 * {@link Calendar#getMinimalDaysInFirstWeek() getMinimalDaysInFirstWeek},
1581 * {@link #getGregorianChange() getGregorianChange} and
1582 * {@link Calendar#getTimeZone() getTimeZone} methods.
1583 *
1584 * <p>For example, if the Gregorian change date is January 10,
1585 * 1970 and the date of this <code>GregorianCalendar</code> is
1586 * January 20, 1970, the actual minimum value of the
1587 * <code>DAY_OF_MONTH</code> field is 10 because the previous date
1588 * of January 10, 1970 is December 27, 1996 (in the Julian
1589 * calendar). Therefore, December 28, 1969 to January 9, 1970
1590 * don't exist.
1591 *
1592 * @param field the calendar field
1593 * @return the minimum of the given field for the time value of
1594 * this <code>GregorianCalendar</code>
1595 * @see #getMinimum(int)
1596 * @see #getMaximum(int)
1597 * @see #getGreatestMinimum(int)
1598 * @see #getLeastMaximum(int)
1599 * @see #getActualMaximum(int)
1600 * @since 1.2
1601 */
1602 public int getActualMinimum(int field) {
1603 if (field == DAY_OF_MONTH) {
1604 GregorianCalendar gc = getNormalizedCalendar();
1605 int year = gc.cdate.getNormalizedYear();
1606 if (year == gregorianCutoverYear
1607 || year == gregorianCutoverYearJulian) {
1608 long month1 = getFixedDateMonth1(gc.cdate, gc.calsys
1609 .getFixedDate(gc.cdate));
1610 BaseCalendar.Date d = getCalendarDate(month1);
1611 return d.getDayOfMonth();
1612 }
1613 }
1614 return getMinimum(field);
1615 }
1616
1617 /**
1618 * Returns the maximum value that this calendar field could have,
1619 * taking into consideration the given time value and the current
1620 * values of the
1621 * {@link Calendar#getFirstDayOfWeek() getFirstDayOfWeek},
1622 * {@link Calendar#getMinimalDaysInFirstWeek() getMinimalDaysInFirstWeek},
1623 * {@link #getGregorianChange() getGregorianChange} and
1624 * {@link Calendar#getTimeZone() getTimeZone} methods.
1625 * For example, if the date of this instance is February 1, 2004,
1626 * the actual maximum value of the <code>DAY_OF_MONTH</code> field
1627 * is 29 because 2004 is a leap year, and if the date of this
1628 * instance is February 1, 2005, it's 28.
1629 *
1630 * @param field the calendar field
1631 * @return the maximum of the given field for the time value of
1632 * this <code>GregorianCalendar</code>
1633 * @see #getMinimum(int)
1634 * @see #getMaximum(int)
1635 * @see #getGreatestMinimum(int)
1636 * @see #getLeastMaximum(int)
1637 * @see #getActualMinimum(int)
1638 * @since 1.2
1639 */
1640 public int getActualMaximum(int field) {
1641 final int fieldsForFixedMax = ERA_MASK | DAY_OF_WEEK_MASK
1642 | HOUR_MASK | AM_PM_MASK | HOUR_OF_DAY_MASK
1643 | MINUTE_MASK | SECOND_MASK | MILLISECOND_MASK
1644 | ZONE_OFFSET_MASK | DST_OFFSET_MASK;
1645 if ((fieldsForFixedMax & (1 << field)) != 0) {
1646 return getMaximum(field);
1647 }
1648
1649 GregorianCalendar gc = getNormalizedCalendar();
1650 BaseCalendar.Date date = gc.cdate;
1651 BaseCalendar cal = gc.calsys;
1652 int normalizedYear = date.getNormalizedYear();
1653
1654 int value = -1;
1655 switch (field) {
1656 case MONTH: {
1657 if (!gc.isCutoverYear(normalizedYear)) {
1658 value = DECEMBER;
1659 break;
1660 }
1661
1662 // January 1 of the next year may or may not exist.
1663 long nextJan1;
1664 do {
1665 nextJan1 = gcal.getFixedDate(++normalizedYear,
1666 BaseCalendar.JANUARY, 1, null);
1667 } while (nextJan1 < gregorianCutoverDate);
1668 BaseCalendar.Date d = (BaseCalendar.Date) date.clone();
1669 cal.getCalendarDateFromFixedDate(d, nextJan1 - 1);
1670 value = d.getMonth() - 1;
1671 }
1672 break;
1673
1674 case DAY_OF_MONTH: {
1675 value = cal.getMonthLength(date);
1676 if (!gc.isCutoverYear(normalizedYear)
1677 || date.getDayOfMonth() == value) {
1678 break;
1679 }
1680
1681 // Handle cutover year.
1682 long fd = gc.getCurrentFixedDate();
1683 if (fd >= gregorianCutoverDate) {
1684 break;
1685 }
1686 int monthLength = gc.actualMonthLength();
1687 long monthEnd = gc.getFixedDateMonth1(gc.cdate, fd)
1688 + monthLength - 1;
1689 // Convert the fixed date to its calendar date.
1690 BaseCalendar.Date d = gc.getCalendarDate(monthEnd);
1691 value = d.getDayOfMonth();
1692 }
1693 break;
1694
1695 case DAY_OF_YEAR: {
1696 if (!gc.isCutoverYear(normalizedYear)) {
1697 value = cal.getYearLength(date);
1698 break;
1699 }
1700
1701 // Handle cutover year.
1702 long jan1;
1703 if (gregorianCutoverYear == gregorianCutoverYearJulian) {
1704 BaseCalendar cocal = gc.getCutoverCalendarSystem();
1705 jan1 = cocal.getFixedDate(normalizedYear, 1, 1, null);
1706 } else if (normalizedYear == gregorianCutoverYearJulian) {
1707 jan1 = cal.getFixedDate(normalizedYear, 1, 1, null);
1708 } else {
1709 jan1 = gregorianCutoverDate;
1710 }
1711 // January 1 of the next year may or may not exist.
1712 long nextJan1 = gcal.getFixedDate(++normalizedYear, 1, 1,
1713 null);
1714 if (nextJan1 < gregorianCutoverDate) {
1715 nextJan1 = gregorianCutoverDate;
1716 }
1717 assert jan1 <= cal.getFixedDate(date.getNormalizedYear(),
1718 date.getMonth(), date.getDayOfMonth(), date);
1719 assert nextJan1 >= cal.getFixedDate(date
1720 .getNormalizedYear(), date.getMonth(), date
1721 .getDayOfMonth(), date);
1722 value = (int) (nextJan1 - jan1);
1723 }
1724 break;
1725
1726 case WEEK_OF_YEAR: {
1727 if (!gc.isCutoverYear(normalizedYear)) {
1728 // Get the day of week of January 1 of the year
1729 CalendarDate d = cal
1730 .newCalendarDate(TimeZone.NO_TIMEZONE);
1731 d.setDate(date.getYear(), BaseCalendar.JANUARY, 1);
1732 int dayOfWeek = cal.getDayOfWeek(d);
1733 // Normalize the day of week with the firstDayOfWeek value
1734 dayOfWeek -= getFirstDayOfWeek();
1735 if (dayOfWeek < 0) {
1736 dayOfWeek += 7;
1737 }
1738 value = 52;
1739 int magic = dayOfWeek + getMinimalDaysInFirstWeek() - 1;
1740 if ((magic == 6)
1741 || (date.isLeapYear() && (magic == 5 || magic == 12))) {
1742 value++;
1743 }
1744 break;
1745 }
1746
1747 if (gc == this ) {
1748 gc = (GregorianCalendar) gc.clone();
1749 }
1750 gc.set(DAY_OF_YEAR, getActualMaximum(DAY_OF_YEAR));
1751 value = gc.get(WEEK_OF_YEAR);
1752 }
1753 break;
1754
1755 case WEEK_OF_MONTH: {
1756 if (!gc.isCutoverYear(normalizedYear)) {
1757 CalendarDate d = cal.newCalendarDate(null);
1758 d.setDate(date.getYear(), date.getMonth(), 1);
1759 int dayOfWeek = cal.getDayOfWeek(d);
1760 int monthLength = cal.getMonthLength(d);
1761 dayOfWeek -= getFirstDayOfWeek();
1762 if (dayOfWeek < 0) {
1763 dayOfWeek += 7;
1764 }
1765 int nDaysFirstWeek = 7 - dayOfWeek; // # of days in the first week
1766 value = 3;
1767 if (nDaysFirstWeek >= getMinimalDaysInFirstWeek()) {
1768 value++;
1769 }
1770 monthLength -= nDaysFirstWeek + 7 * 3;
1771 if (monthLength > 0) {
1772 value++;
1773 if (monthLength > 7) {
1774 value++;
1775 }
1776 }
1777 break;
1778 }
1779
1780 // Cutover year handling
1781 if (gc == this ) {
1782 gc = (GregorianCalendar) gc.clone();
1783 }
1784 int y = gc.internalGet(YEAR);
1785 int m = gc.internalGet(MONTH);
1786 do {
1787 value = gc.get(WEEK_OF_MONTH);
1788 gc.add(WEEK_OF_MONTH, +1);
1789 } while (gc.get(YEAR) == y && gc.get(MONTH) == m);
1790 }
1791 break;
1792
1793 case DAY_OF_WEEK_IN_MONTH: {
1794 // may be in the Gregorian cutover month
1795 int ndays, dow1;
1796 int dow = date.getDayOfWeek();
1797 if (!gc.isCutoverYear(normalizedYear)) {
1798 BaseCalendar.Date d = (BaseCalendar.Date) date.clone();
1799 ndays = cal.getMonthLength(d);
1800 d.setDayOfMonth(1);
1801 cal.normalize(d);
1802 dow1 = d.getDayOfWeek();
1803 } else {
1804 // Let a cloned GregorianCalendar take care of the cutover cases.
1805 if (gc == this ) {
1806 gc = (GregorianCalendar) clone();
1807 }
1808 ndays = gc.actualMonthLength();
1809 gc.set(DAY_OF_MONTH, gc.getActualMinimum(DAY_OF_MONTH));
1810 dow1 = gc.get(DAY_OF_WEEK);
1811 }
1812 int x = dow - dow1;
1813 if (x < 0) {
1814 x += 7;
1815 }
1816 ndays -= x;
1817 value = (ndays + 6) / 7;
1818 }
1819 break;
1820
1821 case YEAR:
1822 /* The year computation is no different, in principle, from the
1823 * others, however, the range of possible maxima is large. In
1824 * addition, the way we know we've exceeded the range is different.
1825 * For these reasons, we use the special case code below to handle
1826 * this field.
1827 *
1828 * The actual maxima for YEAR depend on the type of calendar:
1829 *
1830 * Gregorian = May 17, 292275056 BCE - Aug 17, 292278994 CE
1831 * Julian = Dec 2, 292269055 BCE - Jan 3, 292272993 CE
1832 * Hybrid = Dec 2, 292269055 BCE - Aug 17, 292278994 CE
1833 *
1834 * We know we've exceeded the maximum when either the month, date,
1835 * time, or era changes in response to setting the year. We don't
1836 * check for month, date, and time here because the year and era are
1837 * sufficient to detect an invalid year setting. NOTE: If code is
1838 * added to check the month and date in the future for some reason,
1839 * Feb 29 must be allowed to shift to Mar 1 when setting the year.
1840 */
1841 {
1842 if (gc == this ) {
1843 gc = (GregorianCalendar) clone();
1844 }
1845
1846 // Calculate the millisecond offset from the beginning
1847 // of the year of this calendar and adjust the max
1848 // year value if we are beyond the limit in the max
1849 // year.
1850 long current = gc.getYearOffsetInMillis();
1851
1852 if (gc.internalGetEra() == CE) {
1853 gc.setTimeInMillis(Long.MAX_VALUE);
1854 value = gc.get(YEAR);
1855 long maxEnd = gc.getYearOffsetInMillis();
1856 if (current > maxEnd) {
1857 value--;
1858 }
1859 } else {
1860 CalendarSystem mincal = gc.getTimeInMillis() >= gregorianCutover ? gcal
1861 : getJulianCalendarSystem();
1862 CalendarDate d = mincal.getCalendarDate(Long.MIN_VALUE,
1863 getZone());
1864 long maxEnd = (cal.getDayOfYear(d) - 1) * 24
1865 + d.getHours();
1866 maxEnd *= 60;
1867 maxEnd += d.getMinutes();
1868 maxEnd *= 60;
1869 maxEnd += d.getSeconds();
1870 maxEnd *= 1000;
1871 maxEnd += d.getMillis();
1872 value = d.getYear();
1873 if (value <= 0) {
1874 assert mincal == gcal;
1875 value = 1 - value;
1876 }
1877 if (current < maxEnd) {
1878 value--;
1879 }
1880 }
1881 }
1882 break;
1883
1884 default:
1885 throw new ArrayIndexOutOfBoundsException(field);
1886 }
1887 return value;
1888 }
1889
1890 /**
1891 * Returns the millisecond offset from the beginning of this
1892 * year. This Calendar object must have been normalized.
1893 */
1894 private final long getYearOffsetInMillis() {
1895 long t = (internalGet(DAY_OF_YEAR) - 1) * 24;
1896 t += internalGet(HOUR_OF_DAY);
1897 t *= 60;
1898 t += internalGet(MINUTE);
1899 t *= 60;
1900 t += internalGet(SECOND);
1901 t *= 1000;
1902 return t + internalGet(MILLISECOND)
1903 - (internalGet(ZONE_OFFSET) + internalGet(DST_OFFSET));
1904 }
1905
1906 public Object clone() {
1907 GregorianCalendar other = (GregorianCalendar) super .clone();
1908
1909 other.gdate = (BaseCalendar.Date) gdate.clone();
1910 if (cdate != null) {
1911 if (cdate != gdate) {
1912 other.cdate = (BaseCalendar.Date) cdate.clone();
1913 } else {
1914 other.cdate = other.gdate;
1915 }
1916 }
1917 other.originalFields = null;
1918 other.zoneOffsets = null;
1919 return other;
1920 }
1921
1922 public TimeZone getTimeZone() {
1923 TimeZone zone = super .getTimeZone();
1924 // To share the zone by CalendarDates
1925 gdate.setZone(zone);
1926 if (cdate != null && cdate != gdate) {
1927 cdate.setZone(zone);
1928 }
1929 return zone;
1930 }
1931
1932 public void setTimeZone(TimeZone zone) {
1933 super .setTimeZone(zone);
1934 // To share the zone by CalendarDates
1935 gdate.setZone(zone);
1936 if (cdate != null && cdate != gdate) {
1937 cdate.setZone(zone);
1938 }
1939 }
1940
1941 //////////////////////
1942 // Proposed public API
1943 //////////////////////
1944
1945 /**
1946 * Returns the year that corresponds to the <code>WEEK_OF_YEAR</code> field.
1947 * This may be one year before or after the Gregorian or Julian year stored
1948 * in the <code>YEAR</code> field. For example, January 1, 1999 is considered
1949 * Friday of week 53 of 1998 (if minimal days in first week is
1950 * 2 or less, and the first day of the week is Sunday). Given
1951 * these same settings, the ISO year of January 1, 1999 is
1952 * 1998.
1953 *
1954 * <p>This method calls {@link Calendar#complete} before
1955 * calculating the week-based year.
1956 *
1957 * @return the year corresponding to the <code>WEEK_OF_YEAR</code> field, which
1958 * may be one year before or after the <code>YEAR</code> field.
1959 * @see #YEAR
1960 * @see #WEEK_OF_YEAR
1961 */
1962 /*
1963 public int getWeekBasedYear() {
1964 complete();
1965 // TODO: Below doesn't work for gregorian cutover...
1966 int weekOfYear = internalGet(WEEK_OF_YEAR);
1967 int year = internalGet(YEAR);
1968 if (internalGet(MONTH) == Calendar.JANUARY) {
1969 if (weekOfYear >= 52) {
1970 --year;
1971 }
1972 } else {
1973 if (weekOfYear == 1) {
1974 ++year;
1975 }
1976 }
1977 return year;
1978 }
1979 */
1980
1981 /////////////////////////////
1982 // Time => Fields computation
1983 /////////////////////////////
1984 /**
1985 * The fixed date corresponding to gdate. If the value is
1986 * Long.MIN_VALUE, the fixed date value is unknown. Currently,
1987 * Julian calendar dates are not cached.
1988 */
1989 transient private long cachedFixedDate = Long.MIN_VALUE;
1990
1991 /**
1992 * Converts the time value (millisecond offset from the <a
1993 * href="Calendar.html#Epoch">Epoch</a>) to calendar field values.
1994 * The time is <em>not</em>
1995 * recomputed first; to recompute the time, then the fields, call the
1996 * <code>complete</code> method.
1997 *
1998 * @see Calendar#complete
1999 */
2000 protected void computeFields() {
2001 int mask = 0;
2002 if (isPartiallyNormalized()) {
2003 // Determine which calendar fields need to be computed.
2004 mask = getSetStateFields();
2005 int fieldMask = ~mask & ALL_FIELDS;
2006 // We have to call computTime in case calsys == null in
2007 // order to set calsys and cdate. (6263644)
2008 if (fieldMask != 0 || calsys == null) {
2009 mask |= computeFields(fieldMask, mask
2010 & (ZONE_OFFSET_MASK | DST_OFFSET_MASK));
2011 assert mask == ALL_FIELDS;
2012 }
2013 } else {
2014 mask = ALL_FIELDS;
2015 computeFields(mask, 0);
2016 }
2017 // After computing all the fields, set the field state to `COMPUTED'.
2018 setFieldsComputed(mask);
2019 }
2020
2021 /**
2022 * This computeFields implements the conversion from UTC
2023 * (millisecond offset from the Epoch) to calendar
2024 * field values. fieldMask specifies which fields to change the
2025 * setting state to COMPUTED, although all fields are set to
2026 * the correct values. This is required to fix 4685354.
2027 *
2028 * @param fieldMask a bit mask to specify which fields to change
2029 * the setting state.
2030 * @param tzMask a bit mask to specify which time zone offset
2031 * fields to be used for time calculations
2032 * @return a new field mask that indicates what field values have
2033 * actually been set.
2034 */
2035 private int computeFields(int fieldMask, int tzMask) {
2036 int zoneOffset = 0;
2037 TimeZone tz = getZone();
2038 if (zoneOffsets == null) {
2039 zoneOffsets = new int[2];
2040 }
2041 if (tzMask != (ZONE_OFFSET_MASK | DST_OFFSET_MASK)) {
2042 if (tz instanceof ZoneInfo) {
2043 zoneOffset = ((ZoneInfo) tz).getOffsets(time,
2044 zoneOffsets);
2045 } else {
2046 zoneOffset = tz.getOffset(time);
2047 zoneOffsets[0] = tz.getRawOffset();
2048 zoneOffsets[1] = zoneOffset - zoneOffsets[0];
2049 }
2050 }
2051 if (tzMask != 0) {
2052 if (isFieldSet(tzMask, ZONE_OFFSET)) {
2053 zoneOffsets[0] = internalGet(ZONE_OFFSET);
2054 }
2055 if (isFieldSet(tzMask, DST_OFFSET)) {
2056 zoneOffsets[1] = internalGet(DST_OFFSET);
2057 }
2058 zoneOffset = zoneOffsets[0] + zoneOffsets[1];
2059 }
2060
2061 // By computing time and zoneOffset separately, we can take
2062 // the wider range of time+zoneOffset than the previous
2063 // implementation.
2064 long fixedDate = zoneOffset / ONE_DAY;
2065 int timeOfDay = zoneOffset % (int) ONE_DAY;
2066 fixedDate += time / ONE_DAY;
2067 timeOfDay += (int) (time % ONE_DAY);
2068 if (timeOfDay >= ONE_DAY) {
2069 timeOfDay -= ONE_DAY;
2070 ++fixedDate;
2071 } else {
2072 while (timeOfDay < 0) {
2073 timeOfDay += ONE_DAY;
2074 --fixedDate;
2075 }
2076 }
2077 fixedDate += EPOCH_OFFSET;
2078
2079 int era = CE;
2080 int year;
2081 if (fixedDate >= gregorianCutoverDate) {
2082 // Handle Gregorian dates.
2083 assert cachedFixedDate == Long.MIN_VALUE
2084 || gdate.isNormalized() : "cache control: not normalized";
2085 assert cachedFixedDate == Long.MIN_VALUE
2086 || gcal.getFixedDate(gdate.getNormalizedYear(),
2087 gdate.getMonth(), gdate.getDayOfMonth(),
2088 gdate) == cachedFixedDate : "cache control: inconsictency"
2089 + ", cachedFixedDate="
2090 + cachedFixedDate
2091 + ", computed="
2092 + gcal.getFixedDate(gdate.getNormalizedYear(),
2093 gdate.getMonth(), gdate.getDayOfMonth(),
2094 gdate) + ", date=" + gdate;
2095
2096 // See if we can use gdate to avoid date calculation.
2097 if (fixedDate != cachedFixedDate) {
2098 gcal.getCalendarDateFromFixedDate(gdate, fixedDate);
2099 cachedFixedDate = fixedDate;
2100 }
2101
2102 year = gdate.getYear();
2103 if (year <= 0) {
2104 year = 1 - year;
2105 era = BCE;
2106 }
2107 calsys = gcal;
2108 cdate = gdate;
2109 assert cdate.getDayOfWeek() > 0 : "dow="
2110 + cdate.getDayOfWeek() + ", date=" + cdate;
2111 } else {
2112 // Handle Julian calendar dates.
2113 calsys = getJulianCalendarSystem();
2114 cdate = (BaseCalendar.Date) jcal.newCalendarDate(getZone());
2115 jcal.getCalendarDateFromFixedDate(cdate, fixedDate);
2116 Era e = cdate.getEra();
2117 if (e == jeras[0]) {
2118 era = BCE;
2119 }
2120 year = cdate.getYear();
2121 }
2122
2123 // Always set the ERA and YEAR values.
2124 internalSet(ERA, era);
2125 internalSet(YEAR, year);
2126 int mask = fieldMask | (ERA_MASK | YEAR_MASK);
2127
2128 int month = cdate.getMonth() - 1; // 0-based
2129 int dayOfMonth = cdate.getDayOfMonth();
2130
2131 // Set the basic date fields.
2132 if ((fieldMask & (MONTH_MASK | DAY_OF_MONTH_MASK | DAY_OF_WEEK_MASK)) != 0) {
2133 internalSet(MONTH, month);
2134 internalSet(DAY_OF_MONTH, dayOfMonth);
2135 internalSet(DAY_OF_WEEK, cdate.getDayOfWeek());
2136 mask |= MONTH_MASK | DAY_OF_MONTH_MASK | DAY_OF_WEEK_MASK;
2137 }
2138
2139 if ((fieldMask & (HOUR_OF_DAY_MASK | AM_PM_MASK | HOUR_MASK
2140 | MINUTE_MASK | SECOND_MASK | MILLISECOND_MASK)) != 0) {
2141 if (timeOfDay != 0) {
2142 int hours = timeOfDay / ONE_HOUR;
2143 internalSet(HOUR_OF_DAY, hours);
2144 internalSet(AM_PM, hours / 12); // Assume AM == 0
2145 internalSet(HOUR, hours % 12);
2146 int r = timeOfDay % ONE_HOUR;
2147 internalSet(MINUTE, r / ONE_MINUTE);
2148 r %= ONE_MINUTE;
2149 internalSet(SECOND, r / ONE_SECOND);
2150 internalSet(MILLISECOND, r % ONE_SECOND);
2151 } else {
2152 internalSet(HOUR_OF_DAY, 0);
2153 internalSet(AM_PM, AM);
2154 internalSet(HOUR, 0);
2155 internalSet(MINUTE, 0);
2156 internalSet(SECOND, 0);
2157 internalSet(MILLISECOND, 0);
2158 }
2159 mask |= (HOUR_OF_DAY_MASK | AM_PM_MASK | HOUR_MASK
2160 | MINUTE_MASK | SECOND_MASK | MILLISECOND_MASK);
2161 }
2162
2163 if ((fieldMask & (ZONE_OFFSET_MASK | DST_OFFSET_MASK)) != 0) {
2164 internalSet(ZONE_OFFSET, zoneOffsets[0]);
2165 internalSet(DST_OFFSET, zoneOffsets[1]);
2166 mask |= (ZONE_OFFSET_MASK | DST_OFFSET_MASK);
2167 }
2168
2169 if ((fieldMask & (DAY_OF_YEAR_MASK | WEEK_OF_YEAR_MASK
2170 | WEEK_OF_MONTH_MASK | DAY_OF_WEEK_IN_MONTH_MASK)) != 0) {
2171 int normalizedYear = cdate.getNormalizedYear();
2172 long fixedDateJan1 = calsys.getFixedDate(normalizedYear, 1,
2173 1, cdate);
2174 int dayOfYear = (int) (fixedDate - fixedDateJan1) + 1;
2175 long fixedDateMonth1 = fixedDate - dayOfMonth + 1;
2176 int cutoverGap = 0;
2177 int cutoverYear = (calsys == gcal) ? gregorianCutoverYear
2178 : gregorianCutoverYearJulian;
2179 int relativeDayOfMonth = dayOfMonth - 1;
2180
2181 // If we are in the cutover year, we need some special handling.
2182 if (normalizedYear == cutoverYear) {
2183 // Need to take care of the "missing" days.
2184 if (getCutoverCalendarSystem() == jcal) {
2185 // We need to find out where we are. The cutover
2186 // gap could even be more than one year. (One
2187 // year difference in ~48667 years.)
2188 fixedDateJan1 = getFixedDateJan1(cdate, fixedDate);
2189 if (fixedDate >= gregorianCutoverDate) {
2190 fixedDateMonth1 = getFixedDateMonth1(cdate,
2191 fixedDate);
2192 }
2193 }
2194 int realDayOfYear = (int) (fixedDate - fixedDateJan1) + 1;
2195 cutoverGap = dayOfYear - realDayOfYear;
2196 dayOfYear = realDayOfYear;
2197 relativeDayOfMonth = (int) (fixedDate - fixedDateMonth1);
2198 }
2199 internalSet(DAY_OF_YEAR, dayOfYear);
2200 internalSet(DAY_OF_WEEK_IN_MONTH,
2201 relativeDayOfMonth / 7 + 1);
2202
2203 int weekOfYear = getWeekNumber(fixedDateJan1, fixedDate);
2204
2205 // The spec is to calculate WEEK_OF_YEAR in the
2206 // ISO8601-style. This creates problems, though.
2207 if (weekOfYear == 0) {
2208 // If the date belongs to the last week of the
2209 // previous year, use the week number of "12/31" of
2210 // the "previous" year. Again, if the previous year is
2211 // the Gregorian cutover year, we need to take care of
2212 // it. Usually the previous day of January 1 is
2213 // December 31, which is not always true in
2214 // GregorianCalendar.
2215 long fixedDec31 = fixedDateJan1 - 1;
2216 long prevJan1;
2217 if (normalizedYear > (cutoverYear + 1)) {
2218 prevJan1 = fixedDateJan1 - 365;
2219 if (CalendarUtils
2220 .isGregorianLeapYear(normalizedYear - 1)) {
2221 --prevJan1;
2222 }
2223 } else {
2224 BaseCalendar calForJan1 = calsys;
2225 int prevYear = normalizedYear - 1;
2226 if (prevYear == cutoverYear) {
2227 calForJan1 = getCutoverCalendarSystem();
2228 }
2229 prevJan1 = calForJan1.getFixedDate(prevYear,
2230 BaseCalendar.JANUARY, 1, null);
2231 while (prevJan1 > fixedDec31) {
2232 prevJan1 = getJulianCalendarSystem()
2233 .getFixedDate(--prevYear,
2234 BaseCalendar.JANUARY, 1, null);
2235 }
2236 }
2237 weekOfYear = getWeekNumber(prevJan1, fixedDec31);
2238 } else {
2239 if (normalizedYear > gregorianCutoverYear
2240 || normalizedYear < (gregorianCutoverYearJulian - 1)) {
2241 // Regular years
2242 if (weekOfYear >= 52) {
2243 long nextJan1 = fixedDateJan1 + 365;
2244 if (cdate.isLeapYear()) {
2245 nextJan1++;
2246 }
2247 long nextJan1st = calsys
2248 .getDayOfWeekDateOnOrBefore(
2249 nextJan1 + 6,
2250 getFirstDayOfWeek());
2251 int ndays = (int) (nextJan1st - nextJan1);
2252 if (ndays >= getMinimalDaysInFirstWeek()
2253 && fixedDate >= (nextJan1st - 7)) {
2254 // The first days forms a week in which the date is included.
2255 weekOfYear = 1;
2256 }
2257 }
2258 } else {
2259 BaseCalendar calForJan1 = calsys;
2260 int nextYear = normalizedYear + 1;
2261 if (nextYear == (gregorianCutoverYearJulian + 1)
2262 && nextYear < gregorianCutoverYear) {
2263 // In case the gap is more than one year.
2264 nextYear = gregorianCutoverYear;
2265 }
2266 if (nextYear == gregorianCutoverYear) {
2267 calForJan1 = getCutoverCalendarSystem();
2268 }
2269 long nextJan1 = calForJan1.getFixedDate(nextYear,
2270 BaseCalendar.JANUARY, 1, null);
2271 if (nextJan1 < fixedDate) {
2272 nextJan1 = gregorianCutoverDate;
2273 calForJan1 = gcal;
2274 }
2275 long nextJan1st = calForJan1
2276 .getDayOfWeekDateOnOrBefore(nextJan1 + 6,
2277 getFirstDayOfWeek());
2278 int ndays = (int) (nextJan1st - nextJan1);
2279 if (ndays >= getMinimalDaysInFirstWeek()
2280 && fixedDate >= (nextJan1st - 7)) {
2281 // The first days forms a week in which the date is included.
2282 weekOfYear = 1;
2283 }
2284 }
2285 }
2286 internalSet(WEEK_OF_YEAR, weekOfYear);
2287 internalSet(WEEK_OF_MONTH, getWeekNumber(fixedDateMonth1,
2288 fixedDate));
2289 mask |= (DAY_OF_YEAR_MASK | WEEK_OF_YEAR_MASK
2290 | WEEK_OF_MONTH_MASK | DAY_OF_WEEK_IN_MONTH_MASK);
2291 }
2292 return mask;
2293 }
2294
2295 /**
2296 * Returns the number of weeks in a period between fixedDay1 and
2297 * fixedDate. The getFirstDayOfWeek-getMinimalDaysInFirstWeek rule
2298 * is applied to calculate the number of weeks.
2299 *
2300 * @param fixedDay1 the fixed date of the first day of the period
2301 * @param fixedDate the fixed date of the last day of the period
2302 * @return the number of weeks of the given period
2303 */
2304 private final int getWeekNumber(long fixedDay1, long fixedDate) {
2305 // We can always use `gcal' since Julian and Gregorian are the
2306 // same thing for this calculation.
2307 long fixedDay1st = gcal.getDayOfWeekDateOnOrBefore(
2308 fixedDay1 + 6, getFirstDayOfWeek());
2309 int ndays = (int) (fixedDay1st - fixedDay1);
2310 assert ndays <= 7;
2311 if (ndays >= getMinimalDaysInFirstWeek()) {
2312 fixedDay1st -= 7;
2313 }
2314 int normalizedDayOfPeriod = (int) (fixedDate - fixedDay1st);
2315 if (normalizedDayOfPeriod >= 0) {
2316 return normalizedDayOfPeriod / 7 + 1;
2317 }
2318 return CalendarUtils.floorDivide(normalizedDayOfPeriod, 7) + 1;
2319 }
2320
2321 /**
2322 * Converts calendar field values to the time value (millisecond
2323 * offset from the <a href="Calendar.html#Epoch">Epoch</a>).
2324 *
2325 * @exception IllegalArgumentException if any calendar fields are invalid.
2326 */
2327 protected void computeTime() {
2328 // In non-lenient mode, perform brief checking of calendar
2329 // fields which have been set externally. Through this
2330 // checking, the field values are stored in originalFields[]
2331 // to see if any of them are normalized later.
2332 if (!isLenient()) {
2333 if (originalFields == null) {
2334 originalFields = new int[FIELD_COUNT];
2335 }
2336 for (int field = 0; field < FIELD_COUNT; field++) {
2337 int value = internalGet(field);
2338 if (isExternallySet(field)) {
2339 // Quick validation for any out of range values
2340 if (value < getMinimum(field)
2341 || value > getMaximum(field)) {
2342 throw new IllegalArgumentException(
2343 getFieldName(field));
2344 }
2345 }
2346 originalFields[field] = value;
2347 }
2348 }
2349
2350 // Let the super class determine which calendar fields to be
2351 // used to calculate the time.
2352 int fieldMask = selectFields();
2353
2354 // The year defaults to the epoch start. We don't check
2355 // fieldMask for YEAR because YEAR is a mandatory field to
2356 // determine the date.
2357 int year = isSet(YEAR) ? internalGet(YEAR) : EPOCH_YEAR;
2358
2359 int era = internalGetEra();
2360 if (era == BCE) {
2361 year = 1 - year;
2362 } else if (era != CE) {
2363 // Even in lenient mode we disallow ERA values other than CE & BCE.
2364 // (The same normalization rule as add()/roll() could be
2365 // applied here in lenient mode. But this checking is kept
2366 // unchanged for compatibility as of 1.5.)
2367 throw new IllegalArgumentException("Invalid era");
2368 }
2369
2370 // If year is 0 or negative, we need to set the ERA value later.
2371 if (year <= 0 && !isSet(ERA)) {
2372 fieldMask |= ERA_MASK;
2373 setFieldsComputed(ERA_MASK);
2374 }
2375
2376 // Calculate the time of day. We rely on the convention that
2377 // an UNSET field has 0.
2378 long timeOfDay = 0;
2379 if (isFieldSet(fieldMask, HOUR_OF_DAY)) {
2380 timeOfDay += (long) internalGet(HOUR_OF_DAY);
2381 } else {
2382 timeOfDay += internalGet(HOUR);
2383 // The default value of AM_PM is 0 which designates AM.
2384 if (isFieldSet(fieldMask, AM_PM)) {
2385 timeOfDay += 12 * internalGet(AM_PM);
2386 }
2387 }
2388 timeOfDay *= 60;
2389 timeOfDay += internalGet(MINUTE);
2390 timeOfDay *= 60;
2391 timeOfDay += internalGet(SECOND);
2392 timeOfDay *= 1000;
2393 timeOfDay += internalGet(MILLISECOND);
2394
2395 // Convert the time of day to the number of days and the
2396 // millisecond offset from midnight.
2397 long fixedDate = timeOfDay / ONE_DAY;
2398 timeOfDay %= ONE_DAY;
2399 while (timeOfDay < 0) {
2400 timeOfDay += ONE_DAY;
2401 --fixedDate;
2402 }
2403
2404 // Calculate the fixed date since January 1, 1 (Gregorian).
2405 calculateFixedDate: {
2406 long gfd, jfd;
2407 if (year > gregorianCutoverYear
2408 && year > gregorianCutoverYearJulian) {
2409 gfd = fixedDate + getFixedDate(gcal, year, fieldMask);
2410 if (gfd >= gregorianCutoverDate) {
2411 fixedDate = gfd;
2412 break calculateFixedDate;
2413 }
2414 jfd = fixedDate
2415 + getFixedDate(getJulianCalendarSystem(), year,
2416 fieldMask);
2417 } else if (year < gregorianCutoverYear
2418 && year < gregorianCutoverYearJulian) {
2419 jfd = fixedDate
2420 + getFixedDate(getJulianCalendarSystem(), year,
2421 fieldMask);
2422 if (jfd < gregorianCutoverDate) {
2423 fixedDate = jfd;
2424 break calculateFixedDate;
2425 }
2426 gfd = jfd;
2427 } else {
2428 gfd = fixedDate + getFixedDate(gcal, year, fieldMask);
2429 jfd = fixedDate
2430 + getFixedDate(getJulianCalendarSystem(), year,
2431 fieldMask);
2432 }
2433 // Now we have to determine which calendar date it is.
2434 if (gfd >= gregorianCutoverDate) {
2435 if (jfd >= gregorianCutoverDate) {
2436 fixedDate = gfd;
2437 } else {
2438 // The date is in an "overlapping" period. No way
2439 // to disambiguate it. Determine it using the
2440 // previous date calculation.
2441 if (calsys == gcal || calsys == null) {
2442 fixedDate = gfd;
2443 } else {
2444 fixedDate = jfd;
2445 }
2446 }
2447 } else {
2448 if (jfd < gregorianCutoverDate) {
2449 fixedDate = jfd;
2450 } else {
2451 // The date is in a "missing" period.
2452 if (!isLenient()) {
2453 throw new IllegalArgumentException(
2454 "the specified date doesn't exist");
2455 }
2456 // Take the Julian date for compatibility, which
2457 // will produce a Gregorian date.
2458 fixedDate = jfd;
2459 }
2460 }
2461 }
2462
2463 // millis represents local wall-clock time in milliseconds.
2464 long millis = (fixedDate - EPOCH_OFFSET) * ONE_DAY + timeOfDay;
2465
2466 // Compute the time zone offset and DST offset. There are two potential
2467 // ambiguities here. We'll assume a 2:00 am (wall time) switchover time
2468 // for discussion purposes here.
2469 // 1. The transition into DST. Here, a designated time of 2:00 am - 2:59 am
2470 // can be in standard or in DST depending. However, 2:00 am is an invalid
2471 // representation (the representation jumps from 1:59:59 am Std to 3:00:00 am DST).
2472 // We assume standard time.
2473 // 2. The transition out of DST. Here, a designated time of 1:00 am - 1:59 am
2474 // can be in standard or DST. Both are valid representations (the rep
2475 // jumps from 1:59:59 DST to 1:00:00 Std).
2476 // Again, we assume standard time.
2477 // We use the TimeZone object, unless the user has explicitly set the ZONE_OFFSET
2478 // or DST_OFFSET fields; then we use those fields.
2479 TimeZone zone = getZone();
2480 if (zoneOffsets == null) {
2481 zoneOffsets = new int[2];
2482 }
2483 int tzMask = fieldMask & (ZONE_OFFSET_MASK | DST_OFFSET_MASK);
2484 if (tzMask != (ZONE_OFFSET_MASK | DST_OFFSET_MASK)) {
2485 if (zone instanceof ZoneInfo) {
2486 ((ZoneInfo) zone).getOffsetsByWall(millis, zoneOffsets);
2487 } else {
2488 int gmtOffset = isFieldSet(fieldMask, ZONE_OFFSET) ? internalGet(ZONE_OFFSET)
2489 : zone.getRawOffset();
2490 zone.getOffsets(millis - gmtOffset, zoneOffsets);
2491 }
2492 }
2493 if (tzMask != 0) {
2494 if (isFieldSet(tzMask, ZONE_OFFSET)) {
2495 zoneOffsets[0] = internalGet(ZONE_OFFSET);
2496 }
2497 if (isFieldSet(tzMask, DST_OFFSET)) {
2498 zoneOffsets[1] = internalGet(DST_OFFSET);
2499 }
2500 }
2501
2502 // Adjust the time zone offset values to get the UTC time.
2503 millis -= zoneOffsets[0] + zoneOffsets[1];
2504
2505 // Set this calendar's time in milliseconds
2506 time = millis;
2507
2508 int mask = computeFields(fieldMask | getSetStateFields(),
2509 tzMask);
2510
2511 if (!isLenient()) {
2512 for (int field = 0; field < FIELD_COUNT; field++) {
2513 if (!isExternallySet(field)) {
2514 continue;
2515 }
2516 if (originalFields[field] != internalGet(field)) {
2517 // Restore the original field values
2518 System.arraycopy(originalFields, 0, fields, 0,
2519 fields.length);
2520 throw new IllegalArgumentException(
2521 getFieldName(field));
2522 }
2523 }
2524 }
2525 setFieldsNormalized(mask);
2526 }
2527
2528 /**
2529 * Computes the fixed date under either the Gregorian or the
2530 * Julian calendar, using the given year and the specified calendar fields.
2531 *
2532 * @param cal the CalendarSystem to be used for the date calculation
2533 * @param year the normalized year number, with 0 indicating the
2534 * year 1 BCE, -1 indicating 2 BCE, etc.
2535 * @param fieldMask the calendar fields to be used for the date calculation
2536 * @return the fixed date
2537 * @see Calendar#selectFields
2538 */
2539 private long getFixedDate(BaseCalendar cal, int year, int fieldMask) {
2540 int month = JANUARY;
2541 if (isFieldSet(fieldMask, MONTH)) {
2542 // No need to check if MONTH has been set (no isSet(MONTH)
2543 // call) since its unset value happens to be JANUARY (0).
2544 month = internalGet(MONTH);
2545
2546 // If the month is out of range, adjust it into range
2547 if (month > DECEMBER) {
2548 year += month / 12;
2549 month %= 12;
2550 } else if (month < JANUARY) {
2551 int[] rem = new int[1];
2552 year += CalendarUtils.floorDivide(month, 12, rem);
2553 month = rem[0];
2554 }
2555 }
2556
2557 // Get the fixed date since Jan 1, 1 (Gregorian). We are on
2558 // the first day of either `month' or January in 'year'.
2559 long fixedDate = cal.getFixedDate(year, month + 1, 1,
2560 cal == gcal ? gdate : null);
2561 if (isFieldSet(fieldMask, MONTH)) {
2562 // Month-based calculations
2563 if (isFieldSet(fieldMask, DAY_OF_MONTH)) {
2564 // We are on the first day of the month. Just add the
2565 // offset if DAY_OF_MONTH is set. If the isSet call
2566 // returns false, that means DAY_OF_MONTH has been
2567 // selected just because of the selected
2568 // combination. We don't need to add any since the
2569 // default value is the 1st.
2570 if (isSet(DAY_OF_MONTH)) {
2571 // To avoid underflow with DAY_OF_MONTH-1, add
2572 // DAY_OF_MONTH, then subtract 1.
2573 fixedDate += internalGet(DAY_OF_MONTH);
2574 fixedDate--;
2575 }
2576 } else {
2577 if (isFieldSet(fieldMask, WEEK_OF_MONTH)) {
2578 long firstDayOfWeek = cal
2579 .getDayOfWeekDateOnOrBefore(fixedDate + 6,
2580 getFirstDayOfWeek());
2581 // If we have enough days in the first week, then
2582 // move to the previous week.
2583 if ((firstDayOfWeek - fixedDate) >= getMinimalDaysInFirstWeek()) {
2584 firstDayOfWeek -= 7;
2585 }
2586 if (isFieldSet(fieldMask, DAY_OF_WEEK)) {
2587 firstDayOfWeek = cal
2588 .getDayOfWeekDateOnOrBefore(
2589 firstDayOfWeek + 6,
2590 internalGet(DAY_OF_WEEK));
2591 }
2592 // In lenient mode, we treat days of the previous
2593 // months as a part of the specified
2594 // WEEK_OF_MONTH. See 4633646.
2595 fixedDate = firstDayOfWeek + 7
2596 * (internalGet(WEEK_OF_MONTH) - 1);
2597 } else {
2598 int dayOfWeek;
2599 if (isFieldSet(fieldMask, DAY_OF_WEEK)) {
2600 dayOfWeek = internalGet(DAY_OF_WEEK);
2601 } else {
2602 dayOfWeek = getFirstDayOfWeek();
2603 }
2604 // We are basing this on the day-of-week-in-month. The only
2605 // trickiness occurs if the day-of-week-in-month is
2606 // negative.
2607 int dowim;
2608 if (isFieldSet(fieldMask, DAY_OF_WEEK_IN_MONTH)) {
2609 dowim = internalGet(DAY_OF_WEEK_IN_MONTH);
2610 } else {
2611 dowim = 1;
2612 }
2613 if (dowim >= 0) {
2614 fixedDate = cal.getDayOfWeekDateOnOrBefore(
2615 fixedDate + (7 * dowim) - 1, dayOfWeek);
2616 } else {
2617 // Go to the first day of the next week of
2618 // the specified week boundary.
2619 int lastDate = monthLength(month, year)
2620 + (7 * (dowim + 1));
2621 // Then, get the day of week date on or before the last date.
2622 fixedDate = cal.getDayOfWeekDateOnOrBefore(
2623 fixedDate + lastDate - 1, dayOfWeek);
2624 }
2625 }
2626 }
2627 } else {
2628 if (year == gregorianCutoverYear
2629 && cal == gcal
2630 && fixedDate < gregorianCutoverDate
2631 && gregorianCutoverYear != gregorianCutoverYearJulian) {
2632 // January 1 of the year doesn't exist. Use
2633 // gregorianCutoverDate as the first day of the
2634 // year.
2635 fixedDate = gregorianCutoverDate;
2636 }
2637 // We are on the first day of the year.
2638 if (isFieldSet(fieldMask, DAY_OF_YEAR)) {
2639 // Add the offset, then subtract 1. (Make sure to avoid underflow.)
2640 fixedDate += internalGet(DAY_OF_YEAR);
2641 fixedDate--;
2642 } else {
2643 long firstDayOfWeek = cal.getDayOfWeekDateOnOrBefore(
2644 fixedDate + 6, getFirstDayOfWeek());
2645 // If we have enough days in the first week, then move
2646 // to the previous week.
2647 if ((firstDayOfWeek - fixedDate) >= getMinimalDaysInFirstWeek()) {
2648 firstDayOfWeek -= 7;
2649 }
2650 if (isFieldSet(fieldMask, DAY_OF_WEEK)) {
2651 int dayOfWeek = internalGet(DAY_OF_WEEK);
2652 if (dayOfWeek != getFirstDayOfWeek()) {
2653 firstDayOfWeek = cal
2654 .getDayOfWeekDateOnOrBefore(
2655 firstDayOfWeek + 6, dayOfWeek);
2656 }
2657 }
2658 fixedDate = firstDayOfWeek + 7
2659 * ((long) internalGet(WEEK_OF_YEAR) - 1);
2660 }
2661 }
2662
2663 return fixedDate;
2664 }
2665
2666 /**
2667 * Returns this object if it's normalized (all fields and time are
2668 * in sync). Otherwise, a cloned object is returned after calling
2669 * complete() in lenient mode.
2670 */
2671 private final GregorianCalendar getNormalizedCalendar() {
2672 GregorianCalendar gc;
2673 if (isFullyNormalized()) {
2674 gc = this ;
2675 } else {
2676 // Create a clone and normalize the calendar fields
2677 gc = (GregorianCalendar) this .clone();
2678 gc.setLenient(true);
2679 gc.complete();
2680 }
2681 return gc;
2682 }
2683
2684 /**
2685 * Returns the Julian calendar system instance (singleton). 'jcal'
2686 * and 'jeras' are set upon the return.
2687 */
2688 synchronized private static final BaseCalendar getJulianCalendarSystem() {
2689 if (jcal == null) {
2690 jcal = (JulianCalendar) CalendarSystem.forName("julian");
2691 jeras = jcal.getEras();
2692 }
2693 return jcal;
2694 }
2695
2696 /**
2697 * Returns the calendar system for dates before the cutover date
2698 * in the cutover year. If the cutover date is January 1, the
2699 * method returns Gregorian. Otherwise, Julian.
2700 */
2701 private BaseCalendar getCutoverCalendarSystem() {
2702 CalendarDate date = getGregorianCutoverDate();
2703 if (date.getMonth() == BaseCalendar.JANUARY
2704 && date.getDayOfMonth() == 1) {
2705 return gcal;
2706 }
2707 return getJulianCalendarSystem();
2708 }
2709
2710 /**
2711 * Determines if the specified year (normalized) is the Gregorian
2712 * cutover year. This object must have been normalized.
2713 */
2714 private final boolean isCutoverYear(int normalizedYear) {
2715 int cutoverYear = (calsys == gcal) ? gregorianCutoverYear
2716 : gregorianCutoverYearJulian;
2717 return normalizedYear == cutoverYear;
2718 }
2719
2720 /**
2721 * Returns the fixed date of the first day of the year (usually
2722 * January 1) before the specified date.
2723 *
2724 * @param date the date for which the first day of the year is
2725 * calculated. The date has to be in the cut-over year (Gregorian
2726 * or Julian).
2727 * @param fixedDate the fixed date representation of the date
2728 */
2729 private final long getFixedDateJan1(BaseCalendar.Date date,
2730 long fixedDate) {
2731 assert date.getNormalizedYear() == gregorianCutoverYear
2732 || date.getNormalizedYear() == gregorianCutoverYearJulian;
2733 if (gregorianCutoverYear != gregorianCutoverYearJulian) {
2734 if (fixedDate >= gregorianCutoverDate) {
2735 // Dates before the cutover date don't exist
2736 // in the same (Gregorian) year. So, no
2737 // January 1 exists in the year. Use the
2738 // cutover date as the first day of the year.
2739 return gregorianCutoverDate;
2740 }
2741 }
2742 // January 1 of the normalized year should exist.
2743 BaseCalendar jcal = getJulianCalendarSystem();
2744 return jcal.getFixedDate(date.getNormalizedYear(),
2745 BaseCalendar.JANUARY, 1, null);
2746 }
2747
2748 /**
2749 * Returns the fixed date of the first date of the month (usually
2750 * the 1st of the month) before the specified date.
2751 *
2752 * @param date the date for which the first day of the month is
2753 * calculated. The date has to be in the cut-over year (Gregorian
2754 * or Julian).
2755 * @param fixedDate the fixed date representation of the date
2756 */
2757 private final long getFixedDateMonth1(BaseCalendar.Date date,
2758 long fixedDate) {
2759 assert date.getNormalizedYear() == gregorianCutoverYear
2760 || date.getNormalizedYear() == gregorianCutoverYearJulian;
2761 BaseCalendar.Date gCutover = getGregorianCutoverDate();
2762 if (gCutover.getMonth() == BaseCalendar.JANUARY
2763 && gCutover.getDayOfMonth() == 1) {
2764 // The cutover happened on January 1.
2765 return fixedDate - date.getDayOfMonth() + 1;
2766 }
2767
2768 long fixedDateMonth1;
2769 // The cutover happened sometime during the year.
2770 if (date.getMonth() == gCutover.getMonth()) {
2771 // The cutover happened in the month.
2772 BaseCalendar.Date jLastDate = getLastJulianDate();
2773 if (gregorianCutoverYear == gregorianCutoverYearJulian
2774 && gCutover.getMonth() == jLastDate.getMonth()) {
2775 // The "gap" fits in the same month.
2776 fixedDateMonth1 = jcal.getFixedDate(date
2777 .getNormalizedYear(), date.getMonth(), 1, null);
2778 } else {
2779 // Use the cutover date as the first day of the month.
2780 fixedDateMonth1 = gregorianCutoverDate;
2781 }
2782 } else {
2783 // The cutover happened before the month.
2784 fixedDateMonth1 = fixedDate - date.getDayOfMonth() + 1;
2785 }
2786
2787 return fixedDateMonth1;
2788 }
2789
2790 /**
2791 * Returns a CalendarDate produced from the specified fixed date.
2792 *
2793 * @param fd the fixed date
2794 */
2795 private final BaseCalendar.Date getCalendarDate(long fd) {
2796 BaseCalendar cal = (fd >= gregorianCutoverDate) ? gcal
2797 : getJulianCalendarSystem();
2798 BaseCalendar.Date d = (BaseCalendar.Date) cal
2799 .newCalendarDate(TimeZone.NO_TIMEZONE);
2800 cal.getCalendarDateFromFixedDate(d, fd);
2801 return d;
2802 }
2803
2804 /**
2805 * Returns the Gregorian cutover date as a BaseCalendar.Date. The
2806 * date is a Gregorian date.
2807 */
2808 private final BaseCalendar.Date getGregorianCutoverDate() {
2809 return getCalendarDate(gregorianCutoverDate);
2810 }
2811
2812 /**
2813 * Returns the day before the Gregorian cutover date as a
2814 * BaseCalendar.Date. The date is a Julian date.
2815 */
2816 private final BaseCalendar.Date getLastJulianDate() {
2817 return getCalendarDate(gregorianCutoverDate - 1);
2818 }
2819
2820 /**
2821 * Returns the length of the specified month in the specified
2822 * year. The year number must be normalized.
2823 *
2824 * @see #isLeapYear(int)
2825 */
2826 private final int monthLength(int month, int year) {
2827 return isLeapYear(year) ? LEAP_MONTH_LENGTH[month]
2828 : MONTH_LENGTH[month];
2829 }
2830
2831 /**
2832 * Returns the length of the specified month in the year provided
2833 * by internalGet(YEAR).
2834 *
2835 * @see #isLeapYear(int)
2836 */
2837 private final int monthLength(int month) {
2838 int year = internalGet(YEAR);
2839 if (internalGetEra() == BCE) {
2840 year = 1 - year;
2841 }
2842 return monthLength(month, year);
2843 }
2844
2845 private final int actualMonthLength() {
2846 int year = cdate.getNormalizedYear();
2847 if (year != gregorianCutoverYear
2848 && year != gregorianCutoverYearJulian) {
2849 return calsys.getMonthLength(cdate);
2850 }
2851 BaseCalendar.Date date = (BaseCalendar.Date) cdate.clone();
2852 long fd = calsys.getFixedDate(date);
2853 long month1 = getFixedDateMonth1(date, fd);
2854 long next1 = month1 + calsys.getMonthLength(date);
2855 if (next1 < gregorianCutoverDate) {
2856 return (int) (next1 - month1);
2857 }
2858 if (cdate != gdate) {
2859 date = (BaseCalendar.Date) gcal
2860 .newCalendarDate(TimeZone.NO_TIMEZONE);
2861 }
2862 gcal.getCalendarDateFromFixedDate(date, next1);
2863 next1 = getFixedDateMonth1(date, next1);
2864 return (int) (next1 - month1);
2865 }
2866
2867 /**
2868 * Returns the length (in days) of the specified year. The year
2869 * must be normalized.
2870 */
2871 private final int yearLength(int year) {
2872 return isLeapYear(year) ? 366 : 365;
2873 }
2874
2875 /**
2876 * Returns the length (in days) of the year provided by
2877 * internalGet(YEAR).
2878 */
2879 private final int yearLength() {
2880 int year = internalGet(YEAR);
2881 if (internalGetEra() == BCE) {
2882 year = 1 - year;
2883 }
2884 return yearLength(year);
2885 }
2886
2887 /**
2888 * After adjustments such as add(MONTH), add(YEAR), we don't want the
2889 * month to jump around. E.g., we don't want Jan 31 + 1 month to go to Mar
2890 * 3, we want it to go to Feb 28. Adjustments which might run into this
2891 * problem call this method to retain the proper month.
2892 */
2893 private final void pinDayOfMonth() {
2894 int year = internalGet(YEAR);
2895 int monthLen;
2896 if (year > gregorianCutoverYear
2897 || year < gregorianCutoverYearJulian) {
2898 monthLen = monthLength(internalGet(MONTH));
2899 } else {
2900 GregorianCalendar gc = getNormalizedCalendar();
2901 monthLen = gc.getActualMaximum(DAY_OF_MONTH);
2902 }
2903 int dom = internalGet(DAY_OF_MONTH);
2904 if (dom > monthLen) {
2905 set(DAY_OF_MONTH, monthLen);
2906 }
2907 }
2908
2909 /**
2910 * Returns the fixed date value of this object. The time value and
2911 * calendar fields must be in synch.
2912 */
2913 private final long getCurrentFixedDate() {
2914 return (calsys == gcal) ? cachedFixedDate : calsys
2915 .getFixedDate(cdate);
2916 }
2917
2918 /**
2919 * Returns the new value after 'roll'ing the specified value and amount.
2920 */
2921 private static final int getRolledValue(int value, int amount,
2922 int min, int max) {
2923 assert value >= min && value <= max;
2924 int range = max - min + 1;
2925 amount %= range;
2926 int n = value + amount;
2927 if (n > max) {
2928 n -= range;
2929 } else if (n < min) {
2930 n += range;
2931 }
2932 assert n >= min && n <= max;
2933 return n;
2934 }
2935
2936 /**
2937 * Returns the ERA. We need a special method for this because the
2938 * default ERA is CE, but a zero (unset) ERA is BCE.
2939 */
2940 private final int internalGetEra() {
2941 return isSet(ERA) ? internalGet(ERA) : CE;
2942 }
2943
2944 /**
2945 * Updates internal state.
2946 */
2947 private void readObject(ObjectInputStream stream)
2948 throws IOException, ClassNotFoundException {
2949 stream.defaultReadObject();
2950 if (gdate == null) {
2951 gdate = (BaseCalendar.Date) gcal.newCalendarDate(getZone());
2952 cachedFixedDate = Long.MIN_VALUE;
2953 }
2954 setGregorianChange(gregorianCutover);
2955 }
2956 }
|