| GregorianCalendar.java |
1 /*
2 * %W% %E%
3 *
4 * Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved.
5 * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6 */
7
8 /*
9 * (C) Copyright Taligent, Inc. 1996-1998 - All Rights Reserved
10 * (C) Copyright IBM Corp. 1996-1998 - All Rights Reserved
11 *
12 * The original version of this source code and documentation is copyrighted
13 * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
14 * materials are provided under terms of a License Agreement between Taligent
15 * and Sun. This technology is protected by multiple US and International
16 * patents. This notice and attribution to Taligent may not be removed.
17 * Taligent is a registered trademark of Taligent, Inc.
18 *
19 */
20
21 package java.util;
22
23 import java.io.IOException;
24 import java.io.ObjectInputStream;
25 import sun.util.calendar.BaseCalendar;
26 import sun.util.calendar.CalendarDate;
27 import sun.util.calendar.CalendarSystem;
28 import sun.util.calendar.CalendarUtils;
29 import sun.util.calendar.Era;
30 import sun.util.calendar.Gregorian;
31 import sun.util.calendar.JulianCalendar;
32 import sun.util.calendar.ZoneInfo;
33
34 /**
35 * <code>GregorianCalendar</code> is a concrete subclass of
36 * <code>Calendar</code> and provides the standard calendar system
37 * used by most of the world.
38 *
39 * <p> <code>GregorianCalendar</code> is a hybrid calendar that
40 * supports both the Julian and Gregorian calendar systems with the
41 * support of a single discontinuity, which corresponds by default to
42 * the Gregorian date when the Gregorian calendar was instituted
43 * (October 15, 1582 in some countries, later in others). The cutover
44 * date may be changed by the caller by calling {@link
45 * #setGregorianChange(Date) setGregorianChange()}.
46 *
47 * <p>
48 * Historically, in those countries which adopted the Gregorian calendar first,
49 * October 4, 1582 (Julian) was thus followed by October 15, 1582 (Gregorian). This calendar models
50 * this correctly. Before the Gregorian cutover, <code>GregorianCalendar</code>
51 * implements the Julian calendar. The only difference between the Gregorian
52 * and the Julian calendar is the leap year rule. The Julian calendar specifies
53 * leap years every four years, whereas the Gregorian calendar omits century
54 * years which are not divisible by 400.
55 *
56 * <p>
57 * <code>GregorianCalendar</code> implements <em>proleptic</em> Gregorian and
58 * Julian calendars. That is, dates are computed by extrapolating the current
59 * rules indefinitely far backward and forward in time. As a result,
60 * <code>GregorianCalendar</code> may be used for all years to generate
61 * meaningful and consistent results. However, dates obtained using
62 * <code>GregorianCalendar</code> are historically accurate only from March 1, 4
63 * AD onward, when modern Julian calendar rules were adopted. Before this date,
64 * leap year rules were applied irregularly, and before 45 BC the Julian
65 * calendar did not even exist.
66 *
67 * <p>
68 * Prior to the institution of the Gregorian calendar, New Year's Day was
69 * March 25. To avoid confusion, this calendar always uses January 1. A manual
70 * adjustment may be made if desired for dates that are prior to the Gregorian
71 * changeover and which fall between January 1 and March 24.
72 *
73 * <p>Values calculated for the <code>WEEK_OF_YEAR</code> field range from 1 to
74 * 53. Week 1 for a year is the earliest seven day period starting on
75 * <code>getFirstDayOfWeek()</code> that contains at least
76 * <code>getMinimalDaysInFirstWeek()</code> days from that year. It thus
77 * depends on the values of <code>getMinimalDaysInFirstWeek()</code>,
78 * <code>getFirstDayOfWeek()</code>, and the day of the week of January 1.
79 * Weeks between week 1 of one year and week 1 of the following year are
80 * numbered sequentially from 2 to 52 or 53 (as needed).
81
82 * <p>For example, January 1, 1998 was a Thursday. If
83 * <code>getFirstDayOfWeek()</code> is <code>MONDAY</code> and
84 * <code>getMinimalDaysInFirstWeek()</code> is 4 (these are the values
85 * reflecting ISO 8601 and many national standards), then week 1 of 1998 starts
86 * on December 29, 1997, and ends on January 4, 1998. If, however,
87 * <code>getFirstDayOfWeek()</code> is <code>SUNDAY</code>, then week 1 of 1998
88 * starts on January 4, 1998, and ends on January 10, 1998; the first three days
89 * of 1998 then are part of week 53 of 1997.
90 *
91 * <p>Values calculated for the <code>WEEK_OF_MONTH</code> field range from 0
92 * to 6. Week 1 of a month (the days with <code>WEEK_OF_MONTH =
93 * 1</code>) is the earliest set of at least
94 * <code>getMinimalDaysInFirstWeek()</code> contiguous days in that month,
95 * ending on the day before <code>getFirstDayOfWeek()</code>. Unlike
96 * week 1 of a year, week 1 of a month may be shorter than 7 days, need
97 * not start on <code>getFirstDayOfWeek()</code>, and will not include days of
98 * the previous month. Days of a month before week 1 have a
99 * <code>WEEK_OF_MONTH</code> of 0.
100 *
101 * <p>For example, if <code>getFirstDayOfWeek()</code> is <code>SUNDAY</code>
102 * and <code>getMinimalDaysInFirstWeek()</code> is 4, then the first week of
103 * January 1998 is Sunday, January 4 through Saturday, January 10. These days
104 * have a <code>WEEK_OF_MONTH</code> of 1. Thursday, January 1 through
105 * Saturday, January 3 have a <code>WEEK_OF_MONTH</code> of 0. If
106 * <code>getMinimalDaysInFirstWeek()</code> is changed to 3, then January 1
107 * through January 3 have a <code>WEEK_OF_MONTH</code> of 1.
108 *
109 * <p>The <code>clear</code> methods set calendar field(s)
110 * undefined. <code>GregorianCalendar</code> uses the following
111 * default value for each calendar field if its value is undefined.
112 *
113 * <table cellpadding="0" cellspacing="3" border="0"
114 * summary="GregorianCalendar default field values"
115 * style="text-align: left; width: 66%;">
116 * <tbody>
117 * <tr>
118 * <th style="vertical-align: top; background-color: rgb(204, 204, 255);
119 * text-align: center;">Field<br>
120 * </th>
121 * <th style="vertical-align: top; background-color: rgb(204, 204, 255);
122 * text-align: center;">Default Value<br>
123 * </th>
124 * </tr>
125 * <tr>
126 * <td style="vertical-align: middle;">
127 * <code>ERA<br></code>
128 * </td>
129 * <td style="vertical-align: middle;">
130 * <code>AD<br></code>
131 * </td>
132 * </tr>
133 * <tr>
134 * <td style="vertical-align: middle; background-color: rgb(238, 238, 255);">
135 * <code>YEAR<br></code>
136 * </td>
137 * <td style="vertical-align: middle; background-color: rgb(238, 238, 255);">
138 * <code>1970<br></code>
139 * </td>
140 * </tr>
141 * <tr>
142 * <td style="vertical-align: middle;">
143 * <code>MONTH<br></code>
144 * </td>
145 * <td style="vertical-align: middle;">
146 * <code>JANUARY<br></code>
147 * </td>
148 * </tr>
149 * <tr>
150 * <td style="vertical-align: top; background-color: rgb(238, 238, 255);">
151 * <code>DAY_OF_MONTH<br></code>
152 * </td>
153 * <td style="vertical-align: top; background-color: rgb(238, 238, 255);">
154 * <code>1<br></code>
155 * </td>
156 * </tr>
157 * <tr>
158 * <td style="vertical-align: middle;">
159 * <code>DAY_OF_WEEK<br></code>
160 * </td>
161 * <td style="vertical-align: middle;">
162 * <code>the first day of week<br></code>
163 * </td>
164 * </tr>
165 * <tr>
166 * <td style="vertical-align: top; background-color: rgb(238, 238, 255);">
167 * <code>WEEK_OF_MONTH<br></code>
168 * </td>
169 * <td style="vertical-align: top; background-color: rgb(238, 238, 255);">
170 * <code>0<br></code>
171 * </td>
172 * </tr>
173 * <tr>
174 * <td style="vertical-align: top;">
175 * <code>DAY_OF_WEEK_IN_MONTH<br></code>
176 * </td>
177 * <td style="vertical-align: top;">
178 * <code>1<br></code>
179 * </td>
180 * </tr>
181 * <tr>
182 * <td style="vertical-align: middle; background-color: rgb(238, 238, 255);">
183 * <code>AM_PM<br></code>
184 * </td>
185 * <td style="vertical-align: middle; background-color: rgb(238, 238, 255);">
186 * <code>AM<br></code>
187 * </td>
188 * </tr>
189 * <tr>
190 * <td style="vertical-align: middle;">
191 * <code>HOUR, HOUR_OF_DAY, MINUTE, SECOND, MILLISECOND<br></code>
192 * </td>
193 * <td style="vertical-align: middle;">
194 * <code>0<br></code>
195 * </td>
196 * </tr>
197 * </tbody>
198 * </table>
199 * <br>Default values are not applicable for the fields not listed above.
200 *
201 * <p>
202 * <strong>Example:</strong>
203 * <blockquote>
204 * <pre>
205 * // get the supported ids for GMT-08:00 (Pacific Standard Time)
206 * String[] ids = TimeZone.getAvailableIDs(-8 * 60 * 60 * 1000);
207 * // if no ids were returned, something is wrong. get out.
208 * if (ids.length == 0)
209 * System.exit(0);
210 *
211 * // begin output
212 * System.out.println("Current Time");
213 *
214 * // create a Pacific Standard Time time zone
215 * SimpleTimeZone pdt = new SimpleTimeZone(-8 * 60 * 60 * 1000, ids[0]);
216 *
217 * // set up rules for daylight savings time
218 * pdt.setStartRule(Calendar.APRIL, 1, Calendar.SUNDAY, 2 * 60 * 60 * 1000);
219 * pdt.setEndRule(Calendar.OCTOBER, -1, Calendar.SUNDAY, 2 * 60 * 60 * 1000);
220 *
221 * // create a GregorianCalendar with the Pacific Daylight time zone
222 * // and the current date and time
223 * Calendar calendar = new GregorianCalendar(pdt);
224 * Date trialTime = new Date();
225 * calendar.setTime(trialTime);
226 *
227 * // print out a bunch of interesting things
228 * System.out.println("ERA: " + calendar.get(Calendar.ERA));
229 * System.out.println("YEAR: " + calendar.get(Calendar.YEAR));
230 * System.out.println("MONTH: " + calendar.get(Calendar.MONTH));
231 * System.out.println("WEEK_OF_YEAR: " + calendar.get(Calendar.WEEK_OF_YEAR));
232 * System.out.println("WEEK_OF_MONTH: " + calendar.get(Calendar.WEEK_OF_MONTH));
233 * System.out.println("DATE: " + calendar.get(Calendar.DATE));
234 * System.out.println("DAY_OF_MONTH: " + calendar.get(Calendar.DAY_OF_MONTH));
235 * System.out.println("DAY_OF_YEAR: " + calendar.get(Calendar.DAY_OF_YEAR));
236 * System.out.println("DAY_OF_WEEK: " + calendar.get(Calendar.DAY_OF_WEEK));
237 * System.out.println("DAY_OF_WEEK_IN_MONTH: "
238 * + calendar.get(Calendar.DAY_OF_WEEK_IN_MONTH));
239 * System.out.println("AM_PM: " + calendar.get(Calendar.AM_PM));
240 * System.out.println("HOUR: " + calendar.get(Calendar.HOUR));
241 * System.out.println("HOUR_OF_DAY: " + calendar.get(Calendar.HOUR_OF_DAY));
242 * System.out.println("MINUTE: " + calendar.get(Calendar.MINUTE));
243 * System.out.println("SECOND: " + calendar.get(Calendar.SECOND));
244 * System.out.println("MILLISECOND: " + calendar.get(Calendar.MILLISECOND));
245 * System.out.println("ZONE_OFFSET: "
246 * + (calendar.get(Calendar.ZONE_OFFSET)/(60*60*1000)));
247 * System.out.println("DST_OFFSET: "
248 * + (calendar.get(Calendar.DST_OFFSET)/(60*60*1000)));
249
250 * System.out.println("Current Time, with hour reset to 3");
251 * calendar.clear(Calendar.HOUR_OF_DAY); // so doesn't override
252 * calendar.set(Calendar.HOUR, 3);
253 * System.out.println("ERA: " + calendar.get(Calendar.ERA));
254 * System.out.println("YEAR: " + calendar.get(Calendar.YEAR));
255 * System.out.println("MONTH: " + calendar.get(Calendar.MONTH));
256 * System.out.println("WEEK_OF_YEAR: " + calendar.get(Calendar.WEEK_OF_YEAR));
257 * System.out.println("WEEK_OF_MONTH: " + calendar.get(Calendar.WEEK_OF_MONTH));
258 * System.out.println("DATE: " + calendar.get(Calendar.DATE));
259 * System.out.println("DAY_OF_MONTH: " + calendar.get(Calendar.DAY_OF_MONTH));
260 * System.out.println("DAY_OF_YEAR: " + calendar.get(Calendar.DAY_OF_YEAR));
261 * System.out.println("DAY_OF_WEEK: " + calendar.get(Calendar.DAY_OF_WEEK));
262 * System.out.println("DAY_OF_WEEK_IN_MONTH: "
263 * + calendar.get(Calendar.DAY_OF_WEEK_IN_MONTH));
264 * System.out.println("AM_PM: " + calendar.get(Calendar.AM_PM));
265 * System.out.println("HOUR: " + calendar.get(Calendar.HOUR));
266 * System.out.println("HOUR_OF_DAY: " + calendar.get(Calendar.HOUR_OF_DAY));
267 * System.out.println("MINUTE: " + calendar.get(Calendar.MINUTE));
268 * System.out.println("SECOND: " + calendar.get(Calendar.SECOND));
269 * System.out.println("MILLISECOND: " + calendar.get(Calendar.MILLISECOND));
270 * System.out.println("ZONE_OFFSET: "
271 * + (calendar.get(Calendar.ZONE_OFFSET)/(60*60*1000))); // in hours
272 * System.out.println("DST_OFFSET: "
273 * + (calendar.get(Calendar.DST_OFFSET)/(60*60*1000))); // in hours
274 * </pre>
275 * </blockquote>
276 *
277 * @see TimeZone
278 * @version %I%
279 * @author David Goldsmith, Mark Davis, Chen-Lieh Huang, Alan Liu
280 * @since JDK1.1
281 */
282 public class GregorianCalendar extends Calendar {
283 /*
284 * Implementation Notes
285 *
286 * The epoch is the number of days or milliseconds from some defined
287 * starting point. The epoch for java.util.Date is used here; that is,
288 * milliseconds from January 1, 1970 (Gregorian), midnight UTC. Other
289 * epochs which are used are January 1, year 1 (Gregorian), which is day 1
290 * of the Gregorian calendar, and December 30, year 0 (Gregorian), which is
291 * day 1 of the Julian calendar.
292 *
293 * We implement the proleptic Julian and Gregorian calendars. This means we
294 * implement the modern definition of the calendar even though the
295 * historical usage differs. For example, if the Gregorian change is set
296 * to new Date(Long.MIN_VALUE), we have a pure Gregorian calendar which
297 * labels dates preceding the invention of the Gregorian calendar in 1582 as
298 * if the calendar existed then.
299 *
300 * Likewise, with the Julian calendar, we assume a consistent
301 * 4-year leap year rule, even though the historical pattern of
302 * leap years is irregular, being every 3 years from 45 BCE
303 * through 9 BCE, then every 4 years from 8 CE onwards, with no
304 * leap years in-between. Thus date computations and functions
305 * such as isLeapYear() are not intended to be historically
306 * accurate.
307 */
308
309 //////////////////
310 // Class Variables
311 //////////////////
312
313 /**
314 * Value of the <code>ERA</code> field indicating
315 * the period before the common era (before Christ), also known as BCE.
316 * The sequence of years at the transition from <code>BC</code> to <code>AD</code> is
317 * ..., 2 BC, 1 BC, 1 AD, 2 AD,...
318 *
319 * @see #ERA
320 */
321 public static final int BC = 0;
322
323 /**
324 * Value of the {@link #ERA} field indicating
325 * the period before the common era, the same value as {@link #BC}.
326 *
327 * @see #CE
328 */
329 static final int BCE = 0;
330
331 /**
332 * Value of the <code>ERA</code> field indicating
333 * the common era (Anno Domini), also known as CE.
334 * The sequence of years at the transition from <code>BC</code> to <code>AD</code> is
335 * ..., 2 BC, 1 BC, 1 AD, 2 AD,...
336 *
337 * @see #ERA
338 */
339 public static final int AD = 1;
340
341 /**
342 * Value of the {@link #ERA} field indicating
343 * the common era, the same value as {@link #AD}.
344 *
345 * @see #BCE
346 */
347 static final int CE = 1;
348
349 private static final int EPOCH_OFFSET = 719163; // Fixed date of January 1, 1970 (Gregorian)
350 private static final int EPOCH_YEAR = 1970;
351
352 static final int MONTH_LENGTH[]
353 = {31,28,31,30,31,30,31,31,30,31,30,31}; // 0-based
354 static final int LEAP_MONTH_LENGTH[]
355 = {31,29,31,30,31,30,31,31,30,31,30,31}; // 0-based
356
357 // Useful millisecond constants. Although ONE_DAY and ONE_WEEK can fit
358 // into ints, they must be longs in order to prevent arithmetic overflow
359 // when performing (bug 4173516).
360 private static final int ONE_SECOND = 1000;
361 private static final int ONE_MINUTE = 60*ONE_SECOND;
362 private static final int ONE_HOUR = 60*ONE_MINUTE;
363 private static final long ONE_DAY = 24*ONE_HOUR;
364 private static final long ONE_WEEK = 7*ONE_DAY;
365
366 /*
367 * <pre>
368 * Greatest Least
369 * Field name Minimum Minimum Maximum Maximum
370 * ---------- ------- ------- ------- -------
371 * ERA 0 0 1 1
372 * YEAR 1 1 292269054 292278994
373 * MONTH 0 0 11 11
374 * WEEK_OF_YEAR 1 1 52* 53
375 * WEEK_OF_MONTH 0 0 4* 6
376 * DAY_OF_MONTH 1 1 28* 31
377 * DAY_OF_YEAR 1 1 365* 366
378 * DAY_OF_WEEK 1 1 7 7
379 * DAY_OF_WEEK_IN_MONTH -1 -1 4* 6
380 * AM_PM 0 0 1 1
381 * HOUR 0 0 11 11
382 * HOUR_OF_DAY 0 0 23 23
383 * MINUTE 0 0 59 59
384 * SECOND 0 0 59 59
385 * MILLISECOND 0 0 999 999
386 * ZONE_OFFSET -13:00 -13:00 14:00 14:00
387 * DST_OFFSET 0:00 0:00 0:20 2:00
388 * </pre>
389 * *: depends on the Gregorian change date
390 */
391 static final int MIN_VALUES[] = {
392 BCE, // ERA
393 1, // YEAR
394 JANUARY, // MONTH
395 1, // WEEK_OF_YEAR
396 0, // WEEK_OF_MONTH
397 1, // DAY_OF_MONTH
398 1, // DAY_OF_YEAR
399 SUNDAY, // DAY_OF_WEEK
400 1, // DAY_OF_WEEK_IN_MONTH
401 AM, // AM_PM
402 0, // HOUR
403 0, // HOUR_OF_DAY
404 0, // MINUTE
405 0, // SECOND
406 0, // MILLISECOND
407 -13*ONE_HOUR, // ZONE_OFFSET (UNIX compatibility)
408 0 // DST_OFFSET
409 };
410 static final int LEAST_MAX_VALUES[] = {
411 CE, // ERA
412 292269054, // YEAR
413 DECEMBER, // MONTH
414 52, // WEEK_OF_YEAR
415 4, // WEEK_OF_MONTH
416 28, // DAY_OF_MONTH
417 365, // DAY_OF_YEAR
418 SATURDAY, // DAY_OF_WEEK
419 4, // DAY_OF_WEEK_IN
420 PM, // AM_PM
421 11, // HOUR
422 23, // HOUR_OF_DAY
423 59, // MINUTE
424 59, // SECOND
425 999, // MILLISECOND
426 14*ONE_HOUR, // ZONE_OFFSET
427 20*ONE_MINUTE // DST_OFFSET (historical least maximum)
428 };
429 static final int MAX_VALUES[] = {
430 CE, // ERA
431 292278994, // YEAR
432 DECEMBER, // MONTH
433 53, // WEEK_OF_YEAR
434 6, // WEEK_OF_MONTH
435 31, // DAY_OF_MONTH
436 366, // DAY_OF_YEAR
437 SATURDAY, // DAY_OF_WEEK
438 6, // DAY_OF_WEEK_IN
439 PM, // AM_PM
440 11, // HOUR
441 23, // HOUR_OF_DAY
442 59, // MINUTE
443 59, // SECOND
444 999, // MILLISECOND
445 14*ONE_HOUR, // ZONE_OFFSET
446 2*ONE_HOUR // DST_OFFSET (double summer time)
447 };
448
449 // Proclaim serialization compatibility with JDK 1.1
450 static final long serialVersionUID = -8125100834729963327L;
451
452 // Reference to the sun.util.calendar.Gregorian instance (singleton).
453 private static final Gregorian gcal =
454 CalendarSystem.getGregorianCalendar();
455
456 // Reference to the JulianCalendar instance (singleton), set as needed. See
457 // getJulianCalendarSystem().
458 private static JulianCalendar jcal;
459
460 // JulianCalendar eras. See getJulianCalendarSystem().
461 private static Era[] jeras;
462
463 // The default value of gregorianCutover.
464 static final long DEFAULT_GREGORIAN_CUTOVER = -12219292800000L;
465
466 /////////////////////
467 // Instance Variables
468 /////////////////////
469
470 /**
471 * The point at which the Gregorian calendar rules are used, measured in
472 * milliseconds from the standard epoch. Default is October 15, 1582
473 * (Gregorian) 00:00:00 UTC or -12219292800000L. For this value, October 4,
474 * 1582 (Julian) is followed by October 15, 1582 (Gregorian). This
475 * corresponds to Julian day number 2299161.
476 * @serial
477 */
478 private long gregorianCutover = DEFAULT_GREGORIAN_CUTOVER;
479
480 /**
481 * The fixed date of the gregorianCutover.
482 */
483 private transient long gregorianCutoverDate =
484 (((DEFAULT_GREGORIAN_CUTOVER + 1)/ONE_DAY) - 1) + EPOCH_OFFSET; // == 577736
485
486 /**
487 * The normalized year of the gregorianCutover in Gregorian, with
488 * 0 representing 1 BCE, -1 representing 2 BCE, etc.
489 */
490 private transient int gregorianCutoverYear = 1582;
491
492 /**
493 * The normalized year of the gregorianCutover in Julian, with 0
494 * representing 1 BCE, -1 representing 2 BCE, etc.
495 */
496 private transient int gregorianCutoverYearJulian = 1582;
497
498 /**
499 * gdate always has a sun.util.calendar.Gregorian.Date instance to
500 * avoid overhead of creating it. The assumption is that most
501 * applications will need only Gregorian calendar calculations.
502 */
503 private transient BaseCalendar.Date gdate;
504
505 /**
506 * Reference to either gdate or a JulianCalendar.Date
507 * instance. After calling complete(), this value is guaranteed to
508 * be set.
509 */
510 private transient BaseCalendar.Date cdate;
511
512 /**
513 * The CalendarSystem used to calculate the date in cdate. After
514 * calling complete(), this value is guaranteed to be set and
515 * consistent with the cdate value.
516 */
517 private transient BaseCalendar calsys;
518
519 /**
520 * Temporary int[2] to get time zone offsets. zoneOffsets[0] gets
521 * the GMT offset value and zoneOffsets[1] gets the DST saving
522 * value.
523 */
524 private transient int[] zoneOffsets;
525
526 /**
527 * Temporary storage for saving original fields[] values in
528 * non-lenient mode.
529 */
530 private transient int[] originalFields;
531
532 ///////////////
533 // Constructors
534 ///////////////
535
536 /**
537 * Constructs a default <code>GregorianCalendar</code> using the current time
538 * in the default time zone with the default locale.
539 */
540 public GregorianCalendar() {
541 this(TimeZone.getDefaultRef(), Locale.getDefault());
542 setZoneShared(true);
543 }
544
545 /**
546 * Constructs a <code>GregorianCalendar</code> based on the current time
547 * in the given time zone with the default locale.
548 *
549 * @param zone the given time zone.
550 */
551 public GregorianCalendar(TimeZone zone) {
552 this(zone, Locale.getDefault());
553 }
554
555 /**
556 * Constructs a <code>GregorianCalendar</code> based on the current time
557 * in the default time zone with the given locale.
558 *
559 * @param aLocale the given locale.
560 */
561 public GregorianCalendar(Locale aLocale) {
562 this(TimeZone.getDefaultRef(), aLocale);
563 setZoneShared(true);
564 }
565
566 /**
567 * Constructs a <code>GregorianCalendar</code> based on the current time
568 * in the given time zone with the given locale.
569 *
570 * @param zone the given time zone.
571 * @param aLocale the given locale.
572 */
573 public GregorianCalendar(TimeZone zone, Locale aLocale) {
574 super(zone, aLocale);
575 gdate = (BaseCalendar.Date) gcal.newCalendarDate(zone);
576 setTimeInMillis(System.currentTimeMillis());
577 }
578
579 /**
580 * Constructs a <code>GregorianCalendar</code> with the given date set
581 * in the default time zone with the default locale.
582 *
583 * @param year the value used to set the <code>YEAR</code> calendar field in the calendar.
584 * @param month the value used to set the <code>MONTH</code> calendar field in the calendar.
585 * Month value is 0-based. e.g., 0 for January.
586 * @param dayOfMonth the value used to set the <code>DAY_OF_MONTH</code> calendar field in the calendar.
587 */
588 public GregorianCalendar(int year, int month, int dayOfMonth) {
589 this(year, month, dayOfMonth, 0, 0, 0, 0);
590 }
591
592 /**
593 * Constructs a <code>GregorianCalendar</code> with the given date
594 * and time set for the default time zone with the default locale.
595 *
596 * @param year the value used to set the <code>YEAR</code> calendar field in the calendar.
597 * @param month the value used to set the <code>MONTH</code> calendar field in the calendar.
598 * Month value is 0-based. e.g., 0 for January.
599 * @param dayOfMonth the value used to set the <code>DAY_OF_MONTH</code> calendar field in the calendar.
600 * @param hourOfDay the value used to set the <code>HOUR_OF_DAY</code> calendar field
601 * in the calendar.
602 * @param minute the value used to set the <code>MINUTE</code> calendar field
603 * in the calendar.
604 */
605 public GregorianCalendar(int year, int month, int dayOfMonth, int hourOfDay,
606 int minute) {
607 this(year, month, dayOfMonth, hourOfDay, minute, 0, 0);
608 }
609
610 /**
611 * Constructs a GregorianCalendar with the given date
612 * and time set for the default time zone with the default locale.
613 *
614 * @param year the value used to set the <code>YEAR</code> calendar field in the calendar.
615 * @param month the value used to set the <code>MONTH</code> calendar field in the calendar.
616 * Month value is 0-based. e.g., 0 for January.
617 * @param dayOfMonth the value used to set the <code>DAY_OF_MONTH</code> calendar field in the calendar.
618 * @param hourOfDay the value used to set the <code>HOUR_OF_DAY</code> calendar field
619 * in the calendar.
620 * @param minute the value used to set the <code>MINUTE</code> calendar field
621 * in the calendar.
622 * @param second the value used to set the <code>SECOND</code> calendar field
623 * in the calendar.
624 */
625 public GregorianCalendar(int year, int month, int dayOfMonth, int hourOfDay,
626 int minute, int second) {
627 this(year, month, dayOfMonth, hourOfDay, minute, second, 0);
628 }
629
630 /**
631 * Constructs a <code>GregorianCalendar</code> with the given date
632 * and time set for the default time zone with the default locale.
633 *
634 * @param year the value used to set the <code>YEAR</code> calendar field in the calendar.
635 * @param month the value used to set the <code>MONTH</code> calendar field in the calendar.
636 * Month value is 0-based. e.g., 0 for January.
637 * @param dayOfMonth the value used to set the <code>DAY_OF_MONTH</code> calendar field in the calendar.
638 * @param hourOfDay the value used to set the <code>HOUR_OF_DAY</code> calendar field
639 * in the calendar.
640 * @param minute the value used to set the <code>MINUTE</code> calendar field
641 * in the calendar.
642 * @param second the value used to set the <code>SECOND</code> calendar field
643 * in the calendar.
644 * @param millis the value used to set the <code>MILLISECOND</code> calendar field
645 */
646 GregorianCalendar(int year, int month, int dayOfMonth,
647 int hourOfDay, int minute, int second, int millis) {
648 super();
649 gdate = (BaseCalendar.Date) gcal.newCalendarDate(getZone());
650 this.set(YEAR, year);
651 this.set(MONTH, month);
652 this.set(DAY_OF_MONTH, dayOfMonth);
653
654 // Set AM_PM and HOUR here to set their stamp values before
655 // setting HOUR_OF_DAY (6178071).
656 if (hourOfDay >= 12 && hourOfDay <= 23) {
657 // If hourOfDay is a valid PM hour, set the correct PM values
658 // so that it won't throw an exception in case it's set to
659 // non-lenient later.
660 this.internalSet(AM_PM, PM);
661 this.internalSet(HOUR, hourOfDay - 12);
662 } else {
663 // The default value for AM_PM is AM.
664 // We don't care any out of range value here for leniency.
665 this.internalSet(HOUR, hourOfDay);
666 }
667 // The stamp values of AM_PM and HOUR must be COMPUTED. (6440854)
668 setFieldsComputed(HOUR_MASK|AM_PM_MASK);
669
670 this.set(HOUR_OF_DAY, hourOfDay);
671 this.set(MINUTE, minute);
672 this.set(SECOND, second);
673 // should be changed to set() when this constructor is made
674 // public.
675 this.internalSet(MILLISECOND, millis);
676 }
677
678 /////////////////
679 // Public methods
680 /////////////////
681
682 /**
683 * Sets the <code>GregorianCalendar</code> change date. This is the point when the switch
684 * from Julian dates to Gregorian dates occurred. Default is October 15,
685 * 1582 (Gregorian). Previous to this, dates will be in the Julian calendar.
686 * <p>
687 * To obtain a pure Julian calendar, set the change date to
688 * <code>Date(Long.MAX_VALUE)</code>. To obtain a pure Gregorian calendar,
689 * set the change date to <code>Date(Long.MIN_VALUE)</code>.
690 *
691 * @param date the given Gregorian cutover date.
692 */
693 public void setGregorianChange(Date date) {
694 long cutoverTime = date.getTime();
695 if (cutoverTime == gregorianCutover) {
696 return;
697 }
698 // Before changing the cutover date, make sure to have the
699 // time of this calendar.
700 complete();
701 setGregorianChange(cutoverTime);
702 }
703
704 private void setGregorianChange(long cutoverTime) {
705 gregorianCutover = cutoverTime;
706 gregorianCutoverDate = CalendarUtils.floorDivide(cutoverTime, ONE_DAY)
707 + EPOCH_OFFSET;
708
709 // To provide the "pure" Julian calendar as advertised.
710 // Strictly speaking, the last millisecond should be a
711 // Gregorian date. However, the API doc specifies that setting
712 // the cutover date to Long.MAX_VALUE will make this calendar
713 // a pure Julian calendar. (See 4167995)
714 if (cutoverTime == Long.MAX_VALUE) {
715 gregorianCutoverDate++;
716 }
717
718 BaseCalendar.Date d = getGregorianCutoverDate();
719
720 // Set the cutover year (in the Gregorian year numbering)
721 gregorianCutoverYear = d.getYear();
722
723 BaseCalendar jcal = getJulianCalendarSystem();
724 d = (BaseCalendar.Date) jcal.newCalendarDate(TimeZone.NO_TIMEZONE);
725 jcal.getCalendarDateFromFixedDate(d, gregorianCutoverDate - 1);
726 gregorianCutoverYearJulian = d.getNormalizedYear();
727
728 if (time < gregorianCutover) {
729 // The field values are no longer valid under the new
730 // cutover date.
731 setUnnormalized();
732 }
733 }
734
735 /**
736 * Gets the Gregorian Calendar change date. This is the point when the
737 * switch from Julian dates to Gregorian dates occurred. Default is
738 * October 15, 1582 (Gregorian). Previous to this, dates will be in the Julian
739 * calendar.
740 *
741 * @return the Gregorian cutover date for this <code>GregorianCalendar</code> object.
742 */
743 public final Date getGregorianChange() {
744 return new Date(gregorianCutover);
745 }
746
747 /**
748 * Determines if the given year is a leap year. Returns <code>true</code> if
749 * the given year is a leap year. To specify BC year numbers,
750 * <code>1 - year number</code> must be given. For example, year BC 4 is
751 * specified as -3.
752 *
753 * @param year the given year.
754 * @return <code>true</code> if the given year is a leap year; <code>false</code> otherwise.
755 */
756 public boolean isLeapYear(int year) {
757 if ((year & 3) != 0) {
758 return false;
759 }
760
761 if (year > gregorianCutoverYear) {
762 return (year%100 != 0) || (year%400 == 0); // Gregorian
763 }
764 if (year < gregorianCutoverYearJulian) {
765 return true; // Julian
766 }
767 boolean gregorian;
768 // If the given year is the Gregorian cutover year, we need to
769 // determine which calendar system to be applied to February in the year.
770 if (gregorianCutoverYear == gregorianCutoverYearJulian) {
771 BaseCalendar.Date d = getCalendarDate(gregorianCutoverDate); // Gregorian
772 gregorian = d.getMonth() < BaseCalendar.MARCH;
773 } else {
774 gregorian = year == gregorianCutoverYear;
775 }
776 return gregorian ? (year%100 != 0) || (year%400 == 0) : true;
777 }
778
779 /**
780 * Compares this <code>GregorianCalendar</code> to the specified
781 * <code>Object</code>. The result is <code>true</code> if and
782 * only if the argument is a <code>GregorianCalendar</code> object
783 * that represents the same time value (millisecond offset from
784 * the <a href="Calendar.html#Epoch">Epoch</a>) under the same
785 * <code>Calendar</code> parameters and Gregorian change date as
786 * this object.
787 *
788 * @param obj the object to compare with.
789 * @return <code>true</code> if this object is equal to <code>obj</code>;
790 * <code>false</code> otherwise.
791 * @see Calendar#compareTo(Calendar)
792 */
793 public boolean equals(Object obj) {
794 return obj instanceof GregorianCalendar &&
795 super.equals(obj) &&
796 gregorianCutover == ((GregorianCalendar)obj).gregorianCutover;
797 }
798
799 /**
800 * Generates the hash code for this <code>GregorianCalendar</code> object.
801 */
802 public int hashCode() {
803 return super.hashCode() ^ (int)gregorianCutoverDate;
804 }
805
806 /**
807 * Adds the specified (signed) amount of time to the given calendar field,
808 * based on the calendar's rules.
809 *
810 * <p><em>Add rule 1</em>. The value of <code>field</code>
811 * after the call minus the value of <code>field</code> before the
812 * call is <code>amount</code>, modulo any overflow that has occurred in
813 * <code>field</code>. Overflow occurs when a field value exceeds its
814 * range and, as a result, the next larger field is incremented or
815 * decremented and the field value is adjusted back into its range.</p>
816 *
817 * <p><em>Add rule 2</em>. If a smaller field is expected to be
818 * invariant, but it is impossible for it to be equal to its
819 * prior value because of changes in its minimum or maximum after
820 * <code>field</code> is changed, then its value is adjusted to be as close
821 * as possible to its expected value. A smaller field represents a
822 * smaller unit of time. <code>HOUR</code> is a smaller field than
823 * <code>DAY_OF_MONTH</code>. No adjustment is made to smaller fields
824 * that are not expected to be invariant. The calendar system
825 * determines what fields are expected to be invariant.</p>
826 *
827 * @param field the calendar field.
828 * @param amount the amount of date or time to be added to the field.
829 * @exception IllegalArgumentException if <code>field</code> is
830 * <code>ZONE_OFFSET</code>, <code>DST_OFFSET</code>, or unknown,
831 * or if any calendar fields have out-of-range values in
832 * non-lenient mode.
833 */
834 public void add(int field, int amount) {
835 // If amount == 0, do nothing even the given field is out of
836 // range. This is tested by JCK.
837 if (amount == 0) {
838 return; // Do nothing!
839 }
840
841 if (field < 0 || field >= ZONE_OFFSET) {
842 throw new IllegalArgumentException();
843 }
844
845 // Sync the time and calendar fields.
846 complete();
847
848 if (field == YEAR) {
849 int year = internalGet(YEAR);
850 if (internalGetEra() == CE) {
851 year += amount;
852 if (year > 0) {
853 set(YEAR, year);
854 } else { // year <= 0
855 set(YEAR, 1 - year);
856 // if year == 0, you get 1 BCE.
857 set(ERA, BCE);
858 }
859 }
860 else { // era == BCE
861 year -= amount;
862 if (year > 0) {
863 set(YEAR, year);
864 } else { // year <= 0
865 set(YEAR, 1 - year);
866 // if year == 0, you get 1 CE
867 set(ERA, CE);
868 }
869 }
870 pinDayOfMonth();
871 } else if (field == MONTH) {
872 int month = internalGet(MONTH) + amount;
873 int year = internalGet(YEAR);
874 int y_amount;
875
876 if (month >= 0) {
877 y_amount = month/12;
878 } else {
879 y_amount = (month+1)/12 - 1;
880 }
881 if (y_amount != 0) {
882 if (internalGetEra() == CE) {
883 year += y_amount;
884 if (year > 0) {
885 set(YEAR, year);
886 } else { // year <= 0
887 set(YEAR, 1 - year);
888 // if year == 0, you get 1 BCE
889 set(ERA, BCE);
890 }
891 }
892 else { // era == BCE
893 year -= y_amount;
894 if (year > 0) {
895 set(YEAR, year);
896 } else { // year <= 0
897 set(YEAR, 1 - year);
898 // if year == 0, you get 1 CE
899 set(ERA, CE);
900 }
901 }
902 }
903
904 if (month >= 0) {
905 set(MONTH, (int) (month % 12));
906 } else {
907 // month < 0
908 month %= 12;
909 if (month < 0) {
910 month += 12;
911 }
912 set(MONTH, JANUARY + month);
913 }
914 pinDayOfMonth();
915 } else if (field == ERA) {
916 int era = internalGet(ERA) + amount;
917 if (era < 0) {
918 era = 0;
919 }
920 if (era > 1) {
921 era = 1;
922 }
923 set(ERA, era);
924 } else {
925 long delta = amount;
926 long timeOfDay = 0;
927 switch (field) {
928 // Handle the time fields here. Convert the given
929 // amount to milliseconds and call setTimeInMillis.
930 case HOUR:
931 case HOUR_OF_DAY:
932 delta *= 60 * 60 * 1000; // hours to minutes
933 break;
934
935 case MINUTE:
936 delta *= 60 * 1000; // minutes to seconds
937 break;
938
939 case SECOND:
940 delta *= 1000; // seconds to milliseconds
941 break;
942
943 case MILLISECOND:
944 break;
945
946 // Handle week, day and AM_PM fields which involves
947 // time zone offset change adjustment. Convert the
948 // given amount to the number of days.
949 case WEEK_OF_YEAR:
950 case WEEK_OF_MONTH:
951 case DAY_OF_WEEK_IN_MONTH:
952 delta *= 7;
953 break;
954
955 case DAY_OF_MONTH: // synonym of DATE
956 case DAY_OF_YEAR:
957 case DAY_OF_WEEK:
958 break;
959
960 case AM_PM:
961 // Convert the amount to the number of days (delta)
962 // and +12 or -12 hours (timeOfDay).
963 delta = amount / 2;
964 timeOfDay = 12 * (amount % 2);
965 break;
966 }
967
968 // The time fields don't require time zone offset change
969 // adjustment.
970 if (field >= HOUR) {
971 setTimeInMillis(time + delta);
972 return;
973 }
974
975 // The rest of the fields (week, day or AM_PM fields)
976 // require time zone offset (both GMT and DST) change
977 // adjustment.
978
979 // Translate the current time to the fixed date and time
980 // of the day.
981 long fd = getCurrentFixedDate();
982 timeOfDay += internalGet(HOUR_OF_DAY);
983 timeOfDay *= 60;
984 timeOfDay += internalGet(MINUTE);
985 timeOfDay *= 60;
986 timeOfDay += internalGet(SECOND);
987 timeOfDay *= 1000;
988 timeOfDay += internalGet(MILLISECOND);
989 if (timeOfDay >= ONE_DAY) {
990 fd++;
991 timeOfDay -= ONE_DAY;
992 } else if (timeOfDay < 0) {
993 fd--;
994 timeOfDay += ONE_DAY;
995 }
996
997 fd += delta; // fd is the expected fixed date after the calculation
998 int zoneOffset = internalGet(ZONE_OFFSET) + internalGet(DST_OFFSET);
999 setTimeInMillis((fd - EPOCH_OFFSET) * ONE_DAY + timeOfDay - zoneOffset);
1000 zoneOffset -= internalGet(ZONE_OFFSET) + internalGet(DST_OFFSET);
1001 // If the time zone offset has changed, then adjust the difference.
1002 if (zoneOffset != 0) {
1003 setTimeInMillis(time + zoneOffset);
1004 long fd2 = getCurrentFixedDate();
1005 // If the adjustment has changed the date, then take
1006 // the previous one.
1007 if (fd2 != fd) {
1008 setTimeInMillis(time - zoneOffset);
1009 }
1010 }
1011 }
1012 }
1013
1014 /**
1015 * Adds or subtracts (up/down) a single unit of time on the given time
1016 * field without changing larger fields.
1017 * <p>
1018 * <em>Example</em>: Consider a <code>GregorianCalendar</code>
1019 * originally set to December 31, 1999. Calling {@link #roll(int,boolean) roll(Calendar.MONTH, true)}
1020 * sets the calendar to January 31, 1999. The <code>YEAR</code> field is unchanged
1021 * because it is a larger field than <code>MONTH</code>.</p>
1022 *
1023 * @param up indicates if the value of the specified calendar field is to be
1024 * rolled up or rolled down. Use <code>true</code> if rolling up, <code>false</code> otherwise.
1025 * @exception IllegalArgumentException if <code>field</code> is
1026 * <code>ZONE_OFFSET</code>, <code>DST_OFFSET</code>, or unknown,
1027 * or if any calendar fields have out-of-range values in
1028 * non-lenient mode.
1029 * @see #add(int,int)
1030 * @see #set(int,int)
1031 */
1032 public void roll(int field, boolean up) {
1033 roll(field, up ? +1 : -1);
1034 }
1035
1036 /**
1037 * Adds a signed amount to the specified calendar field without changing larger fields.
1038 * A negative roll amount means to subtract from field without changing
1039 * larger fields. If the specified amount is 0, this method performs nothing.
1040 *
1041 * <p>This method calls {@link #complete()} before adding the
1042 * amount so that all the calendar fields are normalized. If there
1043 * is any calendar field having an out-of-range value in non-lenient mode, then an
1044 * <code>IllegalArgumentException</code> is thrown.
1045 *
1046 * <p>
1047 * <em>Example</em>: Consider a <code>GregorianCalendar</code>
1048 * originally set to August 31, 1999. Calling <code>roll(Calendar.MONTH,
1049 * 8)</code> sets the calendar to April 30, <strong>1999</strong>. Using a
1050 * <code>GregorianCalendar</code>, the <code>DAY_OF_MONTH</code> field cannot
1051 * be 31 in the month April. <code>DAY_OF_MONTH</code> is set to the closest possible
1052 * value, 30. The <code>YEAR</code> field maintains the value of 1999 because it
1053 * is a larger field than <code>MONTH</code>.
1054 * <p>
1055 * <em>Example</em>: Consider a <code>GregorianCalendar</code>
1056 * originally set to Sunday June 6, 1999. Calling
1057 * <code>roll(Calendar.WEEK_OF_MONTH, -1)</code> sets the calendar to
1058 * Tuesday June 1, 1999, whereas calling
1059 * <code>add(Calendar.WEEK_OF_MONTH, -1)</code> sets the calendar to
1060 * Sunday May 30, 1999. This is because the roll rule imposes an
1061 * additional constraint: The <code>MONTH</code> must not change when the
1062 * <code>WEEK_OF_MONTH</code> is rolled. Taken together with add rule 1,
1063 * the resultant date must be between Tuesday June 1 and Saturday June
1064 * 5. According to add rule 2, the <code>DAY_OF_WEEK</code>, an invariant
1065 * when changing the <code>WEEK_OF_MONTH</code>, is set to Tuesday, the
1066 * closest possible value to Sunday (where Sunday is the first day of the
1067 * week).</p>
1068 *
1069 * @param field the calendar field.
1070 * @param amount the signed amount to add to <code>field</code>.
1071 * @exception IllegalArgumentException if <code>field</code> is
1072 * <code>ZONE_OFFSET</code>, <code>DST_OFFSET</code>, or unknown,
1073 * or if any calendar fields have out-of-range values in
1074 * non-lenient mode.
1075 * @see #roll(int,boolean)
1076 * @see #add(int,int)
1077 * @see #set(int,int)
1078 * @since 1.2
1079 */
1080 public void roll(int field, int amount) {
1081 // If amount == 0, do nothing even the given field is out of
1082 // range. This is tested by JCK.
1083 if (amount == 0) {
1084 return;
1085 }
1086
1087 if (field < 0 || field >= ZONE_OFFSET) {
1088 throw new IllegalArgumentException();
1089 }
1090
1091 // Sync the time and calendar fields.
1092 complete();
1093
1094 int min = getMinimum(field);
1095 int max = getMaximum(field);
1096
1097 switch (field) {
1098 case AM_PM:
1099 case ERA:
1100 case YEAR:
1101 case MINUTE:
1102 case SECOND:
1103 case MILLISECOND:
1104 // These fields are handled simply, since they have fixed minima
1105 // and maxima. The field DAY_OF_MONTH is almost as simple. Other
1106 // fields are complicated, since the range within they must roll
1107 // varies depending on the date.
1108 break;
1109
1110 case HOUR:
1111 case HOUR_OF_DAY:
1112 {
1113 int unit = max + 1; // 12 or 24 hours
1114 int h = internalGet(field);
1115 int nh = (h + amount) % unit;
1116 if (nh < 0) {
1117 nh += unit;
1118 }
1119 time += ONE_HOUR * (nh - h);
1120
1121 // The day might have changed, which could happen if
1122 // the daylight saving time transition brings it to
1123 // the next day, although it's very unlikely. But we
1124 // have to make sure not to change the larger fields.
1125 CalendarDate d = calsys.getCalendarDate(time, getZone());
1126 if (internalGet(DAY_OF_MONTH) != d.getDayOfMonth()) {
1127 d.setDate(internalGet(YEAR),
1128 internalGet(MONTH) + 1,
1129 internalGet(DAY_OF_MONTH));
1130 if (field == HOUR) {
1131 assert (internalGet(AM_PM) == PM);
1132 d.addHours(+12); // restore PM
1133 }
1134 time = calsys.getTime(d);
1135 }
1136 int hourOfDay = d.getHours();
1137 internalSet(field, hourOfDay % unit);
1138 if (field == HOUR) {
1139 internalSet(HOUR_OF_DAY, hourOfDay);
1140 } else {
1141 internalSet(AM_PM, hourOfDay / 12);
1142 internalSet(HOUR, hourOfDay % 12);
1143 }
1144
1145 // Time zone offset and/or daylight saving might have changed.
1146 int zoneOffset = d.getZoneOffset();
1147 int saving = d.getDaylightSaving();
1148 internalSet(ZONE_OFFSET, zoneOffset - saving);
1149 internalSet(DST_OFFSET, saving);
1150 return;
1151 }
1152
1153 case MONTH:
1154 // Rolling the month involves both pinning the final value to [0, 11]
1155 // and adjusting the DAY_OF_MONTH if necessary. We only adjust the
1156 // DAY_OF_MONTH if, after updating the MONTH field, it is illegal.
1157 // E.g., <jan31>.roll(MONTH, 1) -> <feb28> or <feb29>.
1158 {
1159 if (!isCutoverYear(cdate.getNormalizedYear())) {
1160 int mon = (internalGet(MONTH) + amount) % 12;
1161 if (mon < 0) {
1162 mon += 12;
1163 }
1164 set(MONTH, mon);
1165
1166 // Keep the day of month in the range. We don't want to spill over
1167 // into the next month; e.g., we don't want jan31 + 1 mo -> feb31 ->
1168 // mar3.
1169 int monthLen = monthLength(mon);
1170 if (internalGet(DAY_OF_MONTH) > monthLen) {
1171 set(DAY_OF_MONTH, monthLen);
1172 }
1173 } else {
1174 // We need to take care of different lengths in
1175 // year and month due to the cutover.
1176 int yearLength = getActualMaximum(MONTH) + 1;
1177 int mon = (internalGet(MONTH) + amount) % yearLength;
1178 if (mon < 0) {
1179 mon += yearLength;
1180 }
1181 set(MONTH, mon);
1182 int monthLen = getActualMaximum(DAY_OF_MONTH);
1183 if (internalGet(DAY_OF_MONTH) > monthLen) {
1184 set(DAY_OF_MONTH, monthLen);
1185 }
1186 }
1187 return;
1188 }
1189
1190 case WEEK_OF_YEAR:
1191 {
1192 int y = cdate.getNormalizedYear();
1193 max = getActualMaximum(WEEK_OF_YEAR);
1194 set(DAY_OF_WEEK, internalGet(DAY_OF_WEEK));
1195 int woy = internalGet(WEEK_OF_YEAR);
1196 int value = woy + amount;
1197 if (!isCutoverYear(y)) {
1198 // If the new value is in between min and max
1199 // (exclusive), then we can use the value.
1200 if (value > min && value < max) {
1201 set(WEEK_OF_YEAR, value);
1202 return;
1203 }
1204 long fd = getCurrentFixedDate();
1205 // Make sure that the min week has the current DAY_OF_WEEK
1206 long day1 = fd - (7 * (woy - min));
1207 if (calsys.getYearFromFixedDate(day1) != y) {
1208 min++;
1209 }
1210
1211 // Make sure the same thing for the max week
1212 fd += 7 * (max - internalGet(WEEK_OF_YEAR));
1213 if (calsys.getYearFromFixedDate(fd) != y) {
1214 max--;
1215 }
1216 break;
1217 }
1218
1219 // Handle cutover here.
1220 long fd = getCurrentFixedDate();
1221 BaseCalendar cal;
1222 if (gregorianCutoverYear == gregorianCutoverYearJulian) {
1223 cal = getCutoverCalendarSystem();
1224 } else if (y == gregorianCutoverYear) {
1225 cal = gcal;
1226 } else {
1227 cal = getJulianCalendarSystem();
1228 }
1229 long day1 = fd - (7 * (woy - min));
1230 // Make sure that the min week has the current DAY_OF_WEEK
1231 if (cal.getYearFromFixedDate(day1) != y) {
1232 min++;
1233 }
1234
1235 // Make sure the same thing for the max week
1236 fd += 7 * (max - woy);
1237 cal = (fd >= gregorianCutoverDate) ? gcal : getJulianCalendarSystem();
1238 if (cal.getYearFromFixedDate(fd) != y) {
1239 max--;
1240 }
1241 // value: the new WEEK_OF_YEAR which must be converted
1242 // to month and day of month.
1243 value = getRolledValue(woy, amount, min, max) - 1;
1244 BaseCalendar.Date d = getCalendarDate(day1 + value * 7);
1245 set(MONTH, d.getMonth() - 1);
1246 set(DAY_OF_MONTH, d.getDayOfMonth());
1247 return;
1248 }
1249
1250 case WEEK_OF_MONTH:
1251 {
1252 boolean isCutoverYear = isCutoverYear(cdate.getNormalizedYear());
1253 // dow: relative day of week from first day of week
1254 int dow = internalGet(DAY_OF_WEEK) - getFirstDayOfWeek();
1255 if (dow < 0) {
1256 dow += 7;
1257 }
1258
1259 long fd = getCurrentFixedDate();
1260 long month1; // fixed date of the first day (usually 1) of the month
1261 int monthLength; // actual month length
1262 if (isCutoverYear) {
1263 month1 = getFixedDateMonth1(cdate, fd);
1264 monthLength = actualMonthLength();
1265 } else {
1266 month1 = fd - internalGet(DAY_OF_MONTH) + 1;
1267 monthLength = calsys.getMonthLength(cdate);
1268 }
1269
1270 // the first day of week of the month.
1271 long monthDay1st = calsys.getDayOfWeekDateOnOrBefore(month1 + 6,
1272 getFirstDayOfWeek());
1273 // if the week has enough days to form a week, the
1274 // week starts from the previous month.
1275 if ((int)(monthDay1st - month1) >= getMinimalDaysInFirstWeek()) {
1276 monthDay1st -= 7;
1277 }
1278 max = getActualMaximum(field);
1279
1280 // value: the new WEEK_OF_MONTH value
1281 int value = getRolledValue(internalGet(field), amount, 1, max) - 1;
1282
1283 // nfd: fixed date of the rolled date
1284 long nfd = monthDay1st + value * 7 + dow;
1285
1286 // Unlike WEEK_OF_YEAR, we need to change day of week if the
1287 // nfd is out of the month.
1288 if (nfd < month1) {
1289 nfd = month1;
1290 } else if (nfd >= (month1 + monthLength)) {
1291 nfd = month1 + monthLength - 1;
1292 }
1293 int dayOfMonth;
1294 if (isCutoverYear) {
1295 // If we are in the cutover year, convert nfd to
1296 // its calendar date and use dayOfMonth.
1297 BaseCalendar.Date d = getCalendarDate(nfd);
1298 dayOfMonth = d.getDayOfMonth();
1299 } else {
1300 dayOfMonth = (int)(nfd - month1) + 1;
1301 }
1302 set(DAY_OF_MONTH, dayOfMonth);
1303 return;
1304 }
1305
1306 case DAY_OF_MONTH:
1307 {
1308 if (!isCutoverYear(cdate.getNormalizedYear())) {
1309 max = calsys.getMonthLength(cdate);
1310 break;
1311 }
1312
1313 // Cutover year handling
1314 long fd = getCurrentFixedDate();
1315 long month1 = getFixedDateMonth1(cdate, fd);
1316 // It may not be a regular month. Convert the date and range to
1317 // the relative values, perform the roll, and
1318 // convert the result back to the rolled date.
1319 int value = getRolledValue((int)(fd - month1), amount, 0, actualMonthLength() - 1);
1320 BaseCalendar.Date d = getCalendarDate(month1 + value);
1321 assert d.getMonth()-1 == internalGet(MONTH);
1322 set(DAY_OF_MONTH, d.getDayOfMonth());
1323 return;
1324 }
1325
1326 case DAY_OF_YEAR:
1327 {
1328 max = getActualMaximum(field);
1329 if (!isCutoverYear(cdate.getNormalizedYear())) {
1330 break;
1331 }
1332
1333 // Handle cutover here.
1334 long fd = getCurrentFixedDate();
1335 long jan1 = fd - internalGet(DAY_OF_YEAR) + 1;
1336 int value = getRolledValue((int)(fd - jan1) + 1, amount, min, max);
1337 BaseCalendar.Date d = getCalendarDate(jan1 + value - 1);
1338 set(MONTH, d.getMonth() - 1);
1339 set(DAY_OF_MONTH, d.getDayOfMonth());
1340 return;
1341 }
1342
1343 case DAY_OF_WEEK:
1344 {
1345 if (!isCutoverYear(cdate.getNormalizedYear())) {
1346 // If the week of year is in the same year, we can
1347 // just change DAY_OF_WEEK.
1348 int weekOfYear = internalGet(WEEK_OF_YEAR);
1349 if (weekOfYear > 1 && weekOfYear < 52) {
1350 set(WEEK_OF_YEAR, weekOfYear); // update stamp[WEEK_OF_YEAR]
1351 max = SATURDAY;
1352 break;
1353 }
1354 }
1355
1356 // We need to handle it in a different way around year
1357 // boundaries and in the cutover year. Note that
1358 // changing era and year values violates the roll
1359 // rule: not changing larger calendar fields...
1360 amount %= 7;
1361 if (amount == 0) {
1362 return;
1363 }
1364 long fd = getCurrentFixedDate();
1365 long dowFirst = calsys.getDayOfWeekDateOnOrBefore(fd, getFirstDayOfWeek());
1366 fd += amount;
1367 if (fd < dowFirst) {
1368 fd += 7;
1369 } else if (fd >= dowFirst + 7) {
1370 fd -= 7;
1371 }
1372 BaseCalendar.Date d = getCalendarDate(fd);
1373 set(ERA, (d.getNormalizedYear() <= 0 ? BCE : CE));
1374 set(d.getYear(), d.getMonth() - 1, d.getDayOfMonth());
1375 return;
1376 }
1377
1378 case DAY_OF_WEEK_IN_MONTH:
1379 {
1380 min = 1; // after normalized, min should be 1.
1381 if (!isCutoverYear(cdate.getNormalizedYear())) {
1382 int dom = internalGet(DAY_OF_MONTH);
1383 int monthLength = calsys.getMonthLength(cdate);
1384 int lastDays = monthLength % 7;
1385 max = monthLength / 7;
1386 int x = (dom - 1) % 7;
1387 if (x < lastDays) {
1388 max++;
1389 }
1390 set(DAY_OF_WEEK, internalGet(DAY_OF_WEEK));
1391 break;
1392 }
1393
1394 // Cutover year handling
1395 long fd = getCurrentFixedDate();
1396 long month1 = getFixedDateMonth1(cdate, fd);
1397 int monthLength = actualMonthLength();
1398 int lastDays = monthLength % 7;
1399 max = monthLength / 7;
1400 int x = (int)(fd - month1) % 7;
1401 if (x < lastDays) {
1402 max++;
1403 }
1404 int value = getRolledValue(internalGet(field), amount, min, max) - 1;
1405 fd = month1 + value * 7 + x;
1406 BaseCalendar cal = (fd >= gregorianCutoverDate) ? gcal : getJulianCalendarSystem();
1407 BaseCalendar.Date d = (BaseCalendar.Date) cal.newCalendarDate(TimeZone.NO_TIMEZONE);
1408 cal.getCalendarDateFromFixedDate(d, fd);
1409 set(DAY_OF_MONTH, d.getDayOfMonth());
1410 return;
1411 }
1412 }
1413
1414 set(field, getRolledValue(internalGet(field), amount, min, max));
1415 }
1416
1417 /**
1418 * Returns the minimum value for the given calendar field of this
1419 * <code>GregorianCalendar</code> instance. The minimum value is
1420 * defined as the smallest value returned by the {@link
1421 * Calendar#get(int) get} method for any possible time value,
1422 * taking into consideration the current values of the
1423 * {@link Calendar#getFirstDayOfWeek() getFirstDayOfWeek},
1424 * {@link Calendar#getMinimalDaysInFirstWeek() getMinimalDaysInFirstWeek},
1425 * {@link #getGregorianChange() getGregorianChange} and
1426 * {@link Calendar#getTimeZone() getTimeZone} methods.
1427 *
1428 * @param field the calendar field.
1429 * @return the minimum value for the given calendar field.
1430 * @see #getMaximum(int)
1431 * @see #getGreatestMinimum(int)
1432 * @see #getLeastMaximum(int)
1433 * @see #getActualMinimum(int)
1434 * @see #getActualMaximum(int)
1435 */
1436 public int getMinimum(int field) {
1437 return MIN_VALUES[field];
1438 }
1439
1440 /**
1441 * Returns the maximum value for the given calendar field of this
1442 * <code>GregorianCalendar</code> instance. The maximum value is
1443 * defined as the largest value returned by the {@link
1444 * Calendar#get(int) get} method for any possible time value,
1445 * taking into consideration the current values of the
1446 * {@link Calendar#getFirstDayOfWeek() getFirstDayOfWeek},
1447 * {@link Calendar#getMinimalDaysInFirstWeek() getMinimalDaysInFirstWeek},
1448 * {@link #getGregorianChange() getGregorianChange} and
1449 * {@link Calendar#getTimeZone() getTimeZone} methods.
1450 *
1451 * @param field the calendar field.
1452 * @return the maximum value for the given calendar field.
1453 * @see #getMinimum(int)
1454 * @see #getGreatestMinimum(int)
1455 * @see #getLeastMaximum(int)
1456 * @see #getActualMinimum(int)
1457 * @see #getActualMaximum(int)
1458 */
1459 public int getMaximum(int field) {
1460 switch (field) {
1461 case MONTH:
1462 case DAY_OF_MONTH:
1463 case DAY_OF_YEAR:
1464 case WEEK_OF_YEAR:
1465 case WEEK_OF_MONTH:
1466 case DAY_OF_WEEK_IN_MONTH:
1467 case YEAR:
1468 {
1469 // On or after Gregorian 200-3-1, Julian and Gregorian
1470 // calendar dates are the same or Gregorian dates are
1471 // larger (i.e., there is a "gap") after 300-3-1.
1472 if (gregorianCutoverYear > 200) {
1473 break;
1474 }
1475 // There might be "overlapping" dates.
1476 GregorianCalendar gc = (GregorianCalendar) clone();
1477 gc.setLenient(true);
1478 gc.setTimeInMillis(gregorianCutover);
1479 int v1 = gc.getActualMaximum(field);
1480 gc.setTimeInMillis(gregorianCutover-1);
1481 int v2 = gc.getActualMaximum(field);
1482 return Math.max(MAX_VALUES[field], Math.max(v1, v2));
1483 }
1484 }
1485 return MAX_VALUES[field];
1486 }
1487
1488 /**
1489 * Returns the highest minimum value for the given calendar field
1490 * of this <code>GregorianCalendar</code> instance. The highest
1491 * minimum value is defined as the largest value returned by
1492 * {@link #getActualMinimum(int)} for any possible time value,
1493 * taking into consideration the current values of the
1494 * {@link Calendar#getFirstDayOfWeek() getFirstDayOfWeek},
1495 * {@link Calendar#getMinimalDaysInFirstWeek() getMinimalDaysInFirstWeek},
1496 * {@link #getGregorianChange() getGregorianChange} and
1497 * {@link Calendar#getTimeZone() getTimeZone} methods.
1498 *
1499 * @param field the calendar field.
1500 * @return the highest minimum value for the given calendar field.
1501 * @see #getMinimum(int)
1502 * @see #getMaximum(int)
1503 * @see #getLeastMaximum(int)
1504 * @see #getActualMinimum(int)
1505 * @see #getActualMaximum(int)
1506 */
1507 public int getGreatestMinimum(int field) {
1508 if (field == DAY_OF_MONTH) {
1509 BaseCalendar.Date d = getGregorianCutoverDate();
1510 long mon1 = getFixedDateMonth1(d, gregorianCutoverDate);
1511 d = getCalendarDate(mon1);
1512 return Math.max(MIN_VALUES[field], d.getDayOfMonth());
1513 }
1514 return MIN_VALUES[field];
1515 }
1516
1517 /**
1518 * Returns the lowest maximum value for the given calendar field
1519 * of this <code>GregorianCalendar</code> instance. The lowest
1520 * maximum value is defined as the smallest value returned by
1521 * {@link #getActualMaximum(int)} for any possible time value,
1522 * taking into consideration the current values of the
1523 * {@link Calendar#getFirstDayOfWeek() getFirstDayOfWeek},
1524 * {@link Calendar#getMinimalDaysInFirstWeek() getMinimalDaysInFirstWeek},
1525 * {@link #getGregorianChange() getGregorianChange} and
1526 * {@link Calendar#getTimeZone() getTimeZone} methods.
1527 *
1528 * @param field the calendar field
1529 * @return the lowest maximum value for the given calendar field.
1530 * @see #getMinimum(int)
1531 * @see #getMaximum(int)
1532 * @see #getGreatestMinimum(int)
1533 * @see #getActualMinimum(int)
1534 * @see #getActualMaximum(int)
1535 */
1536 public int getLeastMaximum(int field) {
1537 switch (field) {
1538 case MONTH:
1539 case DAY_OF_MONTH:
1540 case DAY_OF_YEAR:
1541 case WEEK_OF_YEAR:
1542 case WEEK_OF_MONTH:
1543 case DAY_OF_WEEK_IN_MONTH:
1544 case YEAR:
1545 {
1546 GregorianCalendar gc = (GregorianCalendar) clone();
1547 gc.setLenient(true);
1548 gc.setTimeInMillis(gregorianCutover);
1549 int v1 = gc.getActualMaximum(field);
1550 gc.setTimeInMillis(gregorianCutover-1);
1551 int v2 = gc.getActualMaximum(field);
1552 return Math.min(LEAST_MAX_VALUES[field], Math.min(v1, v2));
1553 }
1554 }
1555 return LEAST_MAX_VALUES[field];
1556 }
1557
1558 /**
1559 * Returns the minimum value that this calendar field could have,
1560 * taking into consideration the given time value and the current
1561 * values of the
1562 * {@link Calendar#getFirstDayOfWeek() getFirstDayOfWeek},
1563 * {@link Calendar#getMinimalDaysInFirstWeek() getMinimalDaysInFirstWeek},
1564 * {@link #getGregorianChange() getGregorianChange} and
1565 * {@link Calendar#getTimeZone() getTimeZone} methods.
1566 *
1567 * <p>For example, if the Gregorian change date is January 10,
1568 * 1970 and the date of this <code>GregorianCalendar</code> is
1569 * January 20, 1970, the actual minimum value of the
1570 * <code>DAY_OF_MONTH</code> field is 10 because the previous date
1571 * of January 10, 1970 is December 27, 1996 (in the Julian
1572 * calendar). Therefore, December 28, 1969 to January 9, 1970
1573 * don't exist.
1574 *
1575 * @param field the calendar field
1576 * @return the minimum of the given field for the time value of
1577 * this <code>GregorianCalendar</code>
1578 * @see #getMinimum(int)
1579 * @see #getMaximum(int)
1580 * @see #getGreatestMinimum(int)
1581 * @see #getLeastMaximum(int)
1582 * @see #getActualMaximum(int)
1583 * @since 1.2
1584 */
1585 public int getActualMinimum(int field) {
1586 if (field == DAY_OF_MONTH) {
1587 GregorianCalendar gc = getNormalizedCalendar();
1588 int year = gc.cdate.getNormalizedYear();
1589 if (year == gregorianCutoverYear || year == gregorianCutoverYearJulian) {
1590 long month1 = getFixedDateMonth1(gc.cdate, gc.calsys.getFixedDate(gc.cdate));
1591 BaseCalendar.Date d = getCalendarDate(month1);
1592 return d.getDayOfMonth();
1593 }
1594 }
1595 return getMinimum(field);
1596 }
1597
1598 /**
1599 * Returns the maximum value that this calendar field could have,
1600 * taking into consideration the given time value and the current
1601 * values of the
1602 * {@link Calendar#getFirstDayOfWeek() getFirstDayOfWeek},
1603 * {@link Calendar#getMinimalDaysInFirstWeek() getMinimalDaysInFirstWeek},
1604 * {@link #getGregorianChange() getGregorianChange} and
1605 * {@link Calendar#getTimeZone() getTimeZone} methods.
1606 * For example, if the date of this instance is February 1, 2004,
1607 * the actual maximum value of the <code>DAY_OF_MONTH</code> field
1608 * is 29 because 2004 is a leap year, and if the date of this
1609 * instance is February 1, 2005, it's 28.
1610 *
1611 * @param field the calendar field
1612 * @return the maximum of the given field for the time value of
1613 * this <code>GregorianCalendar</code>
1614 * @see #getMinimum(int)
1615 * @see #getMaximum(int)
1616 * @see #getGreatestMinimum(int)
1617 * @see #getLeastMaximum(int)
1618 * @see #getActualMinimum(int)
1619 * @since 1.2
1620 */
1621 public int getActualMaximum(int field) {
1622 final int fieldsForFixedMax = ERA_MASK|DAY_OF_WEEK_MASK|HOUR_MASK|AM_PM_MASK|
1623 HOUR_OF_DAY_MASK|MINUTE_MASK|SECOND_MASK|MILLISECOND_MASK|
1624 ZONE_OFFSET_MASK|DST_OFFSET_MASK;
1625 if ((fieldsForFixedMax & (1<<field)) != 0) {
1626 return getMaximum(field);
1627 }
1628
1629 GregorianCalendar gc = getNormalizedCalendar();
1630 BaseCalendar.Date date = gc.cdate;
1631 BaseCalendar cal = gc.calsys;
1632 int normalizedYear = date.getNormalizedYear();
1633
1634 int value = -1;
1635 switch (field) {
1636 case MONTH:
1637 {
1638 if (!gc.isCutoverYear(normalizedYear)) {
1639 value = DECEMBER;
1640 break;
1641 }
1642
1643 // January 1 of the next year may or may not exist.
1644 long nextJan1;
1645 do {
1646 nextJan1 = gcal.getFixedDate(++normalizedYear, BaseCalendar.JANUARY, 1, null);
1647 } while (nextJan1 < gregorianCutoverDate);
1648 BaseCalendar.Date d = (BaseCalendar.Date) date.clone();
1649 cal.getCalendarDateFromFixedDate(d, nextJan1 - 1);
1650 value = d.getMonth() - 1;
1651 }
1652 break;
1653
1654 case DAY_OF_MONTH:
1655 {
1656 value = cal.getMonthLength(date);
1657 if (!gc.isCutoverYear(normalizedYear) || date.getDayOfMonth() == value) {
1658 break;
1659 }
1660
1661 // Handle cutover year.
1662 long fd = gc.getCurrentFixedDate();
1663 if (fd >= gregorianCutoverDate) {
1664 break;
1665 }
1666 int monthLength = gc.actualMonthLength();
1667 long monthEnd = gc.getFixedDateMonth1(gc.cdate, fd) + monthLength - 1;
1668 // Convert the fixed date to its calendar date.
1669 BaseCalendar.Date d = gc.getCalendarDate(monthEnd);
1670 value = d.getDayOfMonth();
1671 }
1672 break;
1673
1674 case DAY_OF_YEAR:
1675 {
1676 if (!gc.isCutoverYear(normalizedYear)) {
1677 value = cal.getYearLength(date);
1678 break;
1679 }
1680
1681 // Handle cutover year.
1682 long jan1;
1683 if (gregorianCutoverYear == gregorianCutoverYearJulian) {
1684 BaseCalendar cocal = gc.getCutoverCalendarSystem();
1685 jan1 = cocal.getFixedDate(normalizedYear, 1, 1, null);
1686 } else if (normalizedYear == gregorianCutoverYearJulian) {
1687 jan1 = cal.getFixedDate(normalizedYear, 1, 1, null);
1688 } else {
1689 jan1 = gregorianCutoverDate;
1690 }
1691 // January 1 of the next year may or may not exist.
1692 long nextJan1 = gcal.getFixedDate(++normalizedYear, 1, 1, null);
1693 if (nextJan1 < gregorianCutoverDate) {
1694 nextJan1 = gregorianCutoverDate;
1695 }
1696 assert jan1 <= cal.getFixedDate(date.getNormalizedYear(), date.getMonth(),
1697 date.getDayOfMonth(), date);
1698 assert nextJan1 >= cal.getFixedDate(date.getNormalizedYear(), date.getMonth(),
1699 date.getDayOfMonth(), date);
1700 value = (int)(nextJan1 - jan1);
1701 }
1702 break;
1703
1704 case WEEK_OF_YEAR:
1705 {
1706 if (!gc.isCutoverYear(normalizedYear)) {
1707 // Get the day of week of January 1 of the year
1708 CalendarDate d = cal.newCalendarDate(TimeZone.NO_TIMEZONE);
1709 d.setDate(date.getYear(), BaseCalendar.JANUARY, 1);
1710 int dayOfWeek = cal.getDayOfWeek(d);
1711 // Normalize the day of week with the firstDayOfWeek value
1712 dayOfWeek -= getFirstDayOfWeek();
1713 if (dayOfWeek < 0) {
1714 dayOfWeek += 7;
1715 }
1716 value = 52;
1717 int magic = dayOfWeek + getMinimalDaysInFirstWeek() - 1;
1718 if ((magic == 6) ||
1719 (date.isLeapYear() && (magic == 5 || magic == 12))) {
1720 value++;
1721 }
1722 break;
1723 }
1724
1725 if (gc == this) {
1726 gc = (GregorianCalendar) gc.clone();
1727 }
1728 gc.set(DAY_OF_YEAR, getActualMaximum(DAY_OF_YEAR));
1729 value = gc.get(WEEK_OF_YEAR);
1730 }
1731 break;
1732
1733 case WEEK_OF_MONTH:
1734 {
1735 if (!gc.isCutoverYear(normalizedYear)) {
1736 CalendarDate d = cal.newCalendarDate(null);
1737 d.setDate(date.getYear(), date.getMonth(), 1);
1738 int dayOfWeek = cal.getDayOfWeek(d);
1739 int monthLength = cal.getMonthLength(d);
1740 dayOfWeek -= getFirstDayOfWeek();
1741 if (dayOfWeek < 0) {
1742 dayOfWeek += 7;
1743 }
1744 int nDaysFirstWeek = 7 - dayOfWeek; // # of days in the first week
1745 value = 3;
1746 if (nDaysFirstWeek >= getMinimalDaysInFirstWeek()) {
1747 value++;
1748 }
1749 monthLength -= nDaysFirstWeek + 7 * 3;
1750 if (monthLength > 0) {
1751 value++;
1752 if (monthLength > 7) {
1753 value++;
1754 }
1755 }
1756 break;
1757 }
1758
1759 // Cutover year handling
1760 if (gc == this) {
1761 gc = (GregorianCalendar) gc.clone();
1762 }
1763 int y = gc.internalGet(YEAR);
1764 int m = gc.internalGet(MONTH);
1765 do {
1766 value = gc.get(WEEK_OF_MONTH);
1767 gc.add(WEEK_OF_MONTH, +1);
1768 } while (gc.get(YEAR) == y && gc.get(MONTH) == m);
1769 }
1770 break;
1771
1772 case DAY_OF_WEEK_IN_MONTH:
1773 {
1774 // may be in the Gregorian cutover month
1775 int ndays, dow1;
1776 int dow = date.getDayOfWeek();
1777 if (!gc.isCutoverYear(normalizedYear)) {
1778 BaseCalendar.Date d = (BaseCalendar.Date) date.clone();
1779 ndays = cal.getMonthLength(d);
1780 d.setDayOfMonth(1);
1781 cal.normalize(d);
1782 dow1 = d.getDayOfWeek();
1783 } else {
1784 // Let a cloned GregorianCalendar take care of the cutover cases.
1785 if (gc == this) {
1786 gc = (GregorianCalendar) clone();
1787 }
1788 ndays = gc.actualMonthLength();
1789 gc.set(DAY_OF_MONTH, gc.getActualMinimum(DAY_OF_MONTH));
1790 dow1 = gc.get(DAY_OF_WEEK);
1791 }
1792 int x = dow - dow1;
1793 if (x < 0) {
1794 x += 7;
1795 }
1796 ndays -= x;
1797 value = (ndays + 6) / 7;
1798 }
1799 break;
1800
1801 case YEAR:
1802 /* The year computation is no different, in principle, from the
1803 * others, however, the range of possible maxima is large. In
1804 * addition, the way we know we've exceeded the range is different.
1805 * For these reasons, we use the special case code below to handle
1806 * this field.
1807 *
1808 * The actual maxima for YEAR depend on the type of calendar:
1809 *
1810 * Gregorian = May 17, 292275056 BCE - Aug 17, 292278994 CE
1811 * Julian = Dec 2, 292269055 BCE - Jan 3, 292272993 CE
1812 * Hybrid = Dec 2, 292269055 BCE - Aug 17, 292278994 CE
1813 *
1814 * We know we've exceeded the maximum when either the month, date,
1815 * time, or era changes in response to setting the year. We don't
1816 * check for month, date, and time here because the year and era are
1817 * sufficient to detect an invalid year setting. NOTE: If code is
1818 * added to check the month and date in the future for some reason,
1819 * Feb 29 must be allowed to shift to Mar 1 when setting the year.
1820 */
1821 {
1822 if (gc == this) {
1823 gc = (GregorianCalendar) clone();
1824 }
1825
1826 // Calculate the millisecond offset from the beginning
1827 // of the year of this calendar and adjust the max
1828 // year value if we are beyond the limit in the max
1829 // year.
1830 long current = gc.getYearOffsetInMillis();
1831
1832 if (gc.internalGetEra() == CE) {
1833 gc.setTimeInMillis(Long.MAX_VALUE);
1834 value = gc.get(YEAR);
1835 long maxEnd = gc.getYearOffsetInMillis();
1836 if (current > maxEnd) {
1837 value--;
1838 }
1839 } else {
1840 CalendarSystem mincal = gc.getTimeInMillis() >= gregorianCutover ?
1841 gcal : getJulianCalendarSystem();
1842 CalendarDate d = mincal.getCalendarDate(Long.MIN_VALUE, getZone());
1843 long maxEnd = (cal.getDayOfYear(d) - 1) * 24 + d.getHours();
1844 maxEnd *= 60;
1845 maxEnd += d.getMinutes();
1846 maxEnd *= 60;
1847 maxEnd += d.getSeconds();
1848 maxEnd *= 1000;
1849 maxEnd += d.getMillis();
1850 value = d.getYear();
1851 if (value <= 0) {
1852 assert mincal == gcal;
1853 value = 1 - value;
1854 }
1855 if (current < maxEnd) {
1856 value--;
1857 }
1858 }
1859 }
1860 break;
1861
1862 default:
1863 throw new ArrayIndexOutOfBoundsException(field);
1864 }
1865 return value;
1866 }
1867
1868 /**
1869 * Returns the millisecond offset from the beginning of this
1870 * year. This Calendar object must have been normalized.
1871 */
1872 private final long getYearOffsetInMillis() {
1873 long t = (internalGet(DAY_OF_YEAR) - 1) * 24;
1874 t += internalGet(HOUR_OF_DAY);
1875 t *= 60;
1876 t += internalGet(MINUTE);
1877 t *= 60;
1878 t += internalGet(SECOND);
1879 t *= 1000;
1880 return t + internalGet(MILLISECOND) -
1881 (internalGet(ZONE_OFFSET) + internalGet(DST_OFFSET));
1882 }
1883
1884 public Object clone()
1885 {
1886 GregorianCalendar other = (GregorianCalendar) super.clone();
1887
1888 other.gdate = (BaseCalendar.Date) gdate.clone();
1889 if (cdate != null) {
1890 if (cdate != gdate) {
1891 other.cdate = (BaseCalendar.Date) cdate.clone();
1892 } else {
1893 other.cdate = other.gdate;
1894 }
1895 }
1896 other.originalFields = null;
1897 other.zoneOffsets = null;
1898 return other;
1899 }
1900
1901 public TimeZone getTimeZone() {
1902 TimeZone zone = super.getTimeZone();
1903 // To share the zone by CalendarDates
1904 gdate.setZone(zone);
1905 if (cdate != null && cdate != gdate) {
1906 cdate.setZone(zone);
1907 }
1908 return zone;
1909 }
1910
1911 public void setTimeZone(TimeZone zone) {
1912 super.setTimeZone(zone);
1913 // To share the zone by CalendarDates
1914 gdate.setZone(zone);
1915 if (cdate != null && cdate != gdate) {
1916 cdate.setZone(zone);
1917 }
1918 }
1919
1920//////////////////////
1921// Proposed public API
1922//////////////////////
1923
1924 /**
1925 * Returns the year that corresponds to the <code>WEEK_OF_YEAR</code> field.
1926 * This may be one year before or after the Gregorian or Julian year stored
1927 * in the <code>YEAR</code> field. For example, January 1, 1999 is considered
1928 * Friday of week 53 of 1998 (if minimal days in first week is
1929 * 2 or less, and the first day of the week is Sunday). Given
1930 * these same settings, the ISO year of January 1, 1999 is
1931 * 1998.
1932 *
1933 * <p>This method calls {@link Calendar#complete} before
1934 * calculating the week-based year.
1935 *
1936 * @return the year corresponding to the <code>WEEK_OF_YEAR</code> field, which
1937 * may be one year before or after the <code>YEAR</code> field.
1938 * @see #YEAR
1939 * @see #WEEK_OF_YEAR
1940 */
1941 /*
1942 public int getWeekBasedYear() {
1943 complete();
1944 // TODO: Below doesn't work for gregorian cutover...
1945 int weekOfYear = internalGet(WEEK_OF_YEAR);
1946 int year = internalGet(YEAR);
1947 if (internalGet(MONTH) == Calendar.JANUARY) {
1948 if (weekOfYear >= 52) {
1949 --year;
1950 }
1951 } else {
1952 if (weekOfYear == 1) {
1953 ++year;
1954 }
1955 }
1956 return year;
1957 }
1958 */
1959
1960
1961/////////////////////////////
1962// Time => Fields computation
1963/////////////////////////////
1964
1965 /**
1966 * The fixed date corresponding to gdate. If the value is
1967 * Long.MIN_VALUE, the fixed date value is unknown. Currently,
1968 * Julian calendar dates are not cached.
1969 */
1970 transient private long cachedFixedDate = Long.MIN_VALUE;
1971
1972 /**
1973 * Converts the time value (millisecond offset from the <a
1974 * href="Calendar.html#Epoch">Epoch</a>) to calendar field values.
1975 * The time is <em>not</em>
1976 * recomputed first; to recompute the time, then the fields, call the
1977 * <code>complete</code> method.
1978 *
1979 * @see Calendar#complete
1980 */
1981 protected void computeFields() {
1982 int mask = 0;
1983 if (isPartiallyNormalized()) {
1984 // Determine which calendar fields need to be computed.
1985 mask = getSetStateFields();
1986 int fieldMask = ~mask & ALL_FIELDS;
1987 // We have to call computTime in case calsys == null in
1988 // order to set calsys and cdate. (6263644)
1989 if (fieldMask != 0 || calsys == null) {
1990 mask |= computeFields(fieldMask,
1991 mask & (ZONE_OFFSET_MASK|DST_OFFSET_MASK));
1992 assert mask == ALL_FIELDS;
1993 }
1994 } else {
1995 mask = ALL_FIELDS;
1996 computeFields(mask, 0);
1997 }
1998 // After computing all the fields, set the field state to `COMPUTED'.
1999 setFieldsComputed(mask);
2000 }
2001
2002 /**
2003 * This computeFields implements the conversion from UTC
2004 * (millisecond offset from the Epoch) to calendar
2005 * field values. fieldMask specifies which fields to change the
2006 * setting state to COMPUTED, although all fields are set to
2007 * the correct values. This is required to fix 4685354.
2008 *
2009 * @param fieldMask a bit mask to specify which fields to change
2010 * the setting state.
2011 * @param tzMask a bit mask to specify which time zone offset
2012 * fields to be used for time calculations
2013 * @return a new field mask that indicates what field values have
2014 * actually been set.
2015 */
2016 private int computeFields(int fieldMask, int tzMask) {
2017 int zoneOffset = 0;
2018 TimeZone tz = getZone();
2019 if (zoneOffsets == null) {
2020 zoneOffsets = new int[2];
2021 }
2022 if (tzMask != (ZONE_OFFSET_MASK|DST_OFFSET_MASK)) {
2023 if (tz instanceof ZoneInfo) {
2024 zoneOffset = ((ZoneInfo)tz).getOffsets(time, zoneOffsets);
2025 } else {
2026 zoneOffset = tz.getOffset(time);
2027 zoneOffsets[0] = tz.getRawOffset();
2028 zoneOffsets[1] = zoneOffset - zoneOffsets[0];
2029 }
2030 }
2031 if (tzMask != 0) {
2032 if (isFieldSet(tzMask, ZONE_OFFSET)) {
2033 zoneOffsets[0] = internalGet(ZONE_OFFSET);
2034 }
2035 if (isFieldSet(tzMask, DST_OFFSET)) {
2036 zoneOffsets[1] = internalGet(DST_OFFSET);
2037 }
2038 zoneOffset = zoneOffsets[0] + zoneOffsets[1];
2039 }
2040
2041 // By computing time and zoneOffset separately, we can take
2042 // the wider range of time+zoneOffset than the previous
2043 // implementation.
2044 long fixedDate = zoneOffset / ONE_DAY;
2045 int timeOfDay = zoneOffset % (int)ONE_DAY;
2046 fixedDate += time / ONE_DAY;
2047 timeOfDay += (int) (time % ONE_DAY);
2048 if (timeOfDay >= ONE_DAY) {
2049 timeOfDay -= ONE_DAY;
2050 ++fixedDate;
2051 } else {
2052 while (timeOfDay < 0) {
2053 timeOfDay += ONE_DAY;
2054 --fixedDate;
2055 }
2056 }
2057 fixedDate += EPOCH_OFFSET;
2058
2059 int era = CE;
2060 int year;
2061 if (fixedDate >= gregorianCutoverDate) {
2062 // Handle Gregorian dates.
2063 assert cachedFixedDate == Long.MIN_VALUE || gdate.isNormalized()
2064 : "cache control: not normalized";
2065 assert cachedFixedDate == Long.MIN_VALUE ||
2066 gcal.getFixedDate(gdate.getNormalizedYear(),
2067 gdate.getMonth(),
2068 gdate.getDayOfMonth(), gdate)
2069 == cachedFixedDate
2070 : "cache control: inconsictency" +
2071 ", cachedFixedDate=" + cachedFixedDate +
2072 ", computed=" +
2073 gcal.getFixedDate(gdate.getNormalizedYear(),
2074 gdate.getMonth(),
2075 gdate.getDayOfMonth(),
2076 gdate) +
2077 ", date=" + gdate;
2078
2079 // See if we can use gdate to avoid date calculation.
2080 if (fixedDate != cachedFixedDate) {
2081 gcal.getCalendarDateFromFixedDate(gdate, fixedDate);
2082 cachedFixedDate = fixedDate;
2083 }
2084
2085 year = gdate.getYear();
2086 if (year <= 0) {
2087 year = 1 - year;
2088 era = BCE;
2089 }
2090 calsys = gcal;
2091 cdate = gdate;
2092 assert cdate.getDayOfWeek() > 0 : "dow="+cdate.getDayOfWeek()+", date="+cdate;
2093 } else {
2094 // Handle Julian calendar dates.
2095 calsys = getJulianCalendarSystem();
2096 cdate = (BaseCalendar.Date) jcal.newCalendarDate(getZone());
2097 jcal.getCalendarDateFromFixedDate(cdate, fixedDate);
2098 Era e = cdate.getEra();
2099 if (e == jeras[0]) {
2100 era = BCE;
2101 }
2102 year = cdate.getYear();
2103 }
2104
2105 // Always set the ERA and YEAR values.
2106 internalSet(ERA, era);
2107 internalSet(YEAR, year);
2108 int mask = fieldMask | (ERA_MASK|YEAR_MASK);
2109
2110 int month = cdate.getMonth() - 1; // 0-based
2111 int dayOfMonth = cdate.getDayOfMonth();
2112
2113 // Set the basic date fields.
2114 if ((fieldMask & (MONTH_MASK|DAY_OF_MONTH_MASK|DAY_OF_WEEK_MASK))
2115 != 0) {
2116 internalSet(MONTH, month);
2117 internalSet(DAY_OF_MONTH, dayOfMonth);
2118 internalSet(DAY_OF_WEEK, cdate.getDayOfWeek());
2119 mask |= MONTH_MASK|DAY_OF_MONTH_MASK|DAY_OF_WEEK_MASK;
2120 }
2121
2122 if ((fieldMask & (HOUR_OF_DAY_MASK|AM_PM_MASK|HOUR_MASK
2123 |MINUTE_MASK|SECOND_MASK|MILLISECOND_MASK)) != 0) {
2124 if (timeOfDay != 0) {
2125 int hours = timeOfDay / ONE_HOUR;
2126 internalSet(HOUR_OF_DAY, hours);
2127 internalSet(AM_PM, hours / 12); // Assume AM == 0
2128 internalSet(HOUR, hours % 12);
2129 int r = timeOfDay % ONE_HOUR;
2130 internalSet(MINUTE, r / ONE_MINUTE);
2131 r %= ONE_MINUTE;
2132 internalSet(SECOND, r / ONE_SECOND);
2133 internalSet(MILLISECOND, r % ONE_SECOND);
2134 } else {
2135 internalSet(HOUR_OF_DAY, 0);
2136 internalSet(AM_PM, AM);
2137 internalSet(HOUR, 0);
2138 internalSet(MINUTE, 0);
2139 internalSet(SECOND, 0);
2140 internalSet(MILLISECOND, 0);
2141 }
2142 mask |= (HOUR_OF_DAY_MASK|AM_PM_MASK|HOUR_MASK
2143 |MINUTE_MASK|SECOND_MASK|MILLISECOND_MASK);
2144 }
2145
2146 if ((fieldMask & (ZONE_OFFSET_MASK|DST_OFFSET_MASK)) != 0) {
2147 internalSet(ZONE_OFFSET, zoneOffsets[0]);
2148 internalSet(DST_OFFSET, zoneOffsets[1]);
2149 mask |= (ZONE_OFFSET_MASK|DST_OFFSET_MASK);
2150 }
2151
2152 if ((fieldMask & (DAY_OF_YEAR_MASK|WEEK_OF_YEAR_MASK|WEEK_OF_MONTH_MASK|DAY_OF_WEEK_IN_MONTH_MASK)) != 0) {
2153 int normalizedYear = cdate.getNormalizedYear();
2154 long fixedDateJan1 = calsys.getFixedDate(normalizedYear, 1, 1, cdate);
2155 int dayOfYear = (int)(fixedDate - fixedDateJan1) + 1;
2156 long fixedDateMonth1 = fixedDate - dayOfMonth + 1;
2157 int cutoverGap = 0;
2158 int cutoverYear = (calsys == gcal) ? gregorianCutoverYear : gregorianCutoverYearJulian;
2159 int relativeDayOfMonth = dayOfMonth - 1;
2160
2161 // If we are in the cutover year, we need some special handling.
2162 if (normalizedYear == cutoverYear) {
2163 // Need to take care of the "missing" days.
2164 if (getCutoverCalendarSystem() == jcal) {
2165 // We need to find out where we are. The cutover
2166 // gap could even be more than one year. (One
2167 // year difference in ~48667 years.)
2168 fixedDateJan1 = getFixedDateJan1(cdate, fixedDate);
2169 if (fixedDate >= gregorianCutoverDate) {
2170 fixedDateMonth1 = getFixedDateMonth1(cdate, fixedDate);
2171 }
2172 }
2173 int realDayOfYear = (int)(fixedDate - fixedDateJan1) + 1;
2174 cutoverGap = dayOfYear - realDayOfYear;
2175 dayOfYear = realDayOfYear;
2176 relativeDayOfMonth = (int)(fixedDate - fixedDateMonth1);
2177 }
2178 internalSet(DAY_OF_YEAR, dayOfYear);
2179 internalSet(DAY_OF_WEEK_IN_MONTH, relativeDayOfMonth / 7 + 1);
2180
2181 int weekOfYear = getWeekNumber(fixedDateJan1, fixedDate);
2182
2183 // The spec is to calculate WEEK_OF_YEAR in the
2184 // ISO8601-style. This creates problems, though.
2185 if (weekOfYear == 0) {
2186 // If the date belongs to the last week of the
2187 // previous year, use the week number of "12/31" of
2188 // the "previous" year. Again, if the previous year is
2189 // the Gregorian cutover year, we need to take care of
2190 // it. Usually the previous day of January 1 is
2191 // December 31, which is not always true in
2192 // GregorianCalendar.
2193 long fixedDec31 = fixedDateJan1 - 1;
2194 long prevJan1;
2195 if (normalizedYear > (cutoverYear + 1)) {
2196 prevJan1 = fixedDateJan1 - 365;
2197 if (CalendarUtils.isGregorianLeapYear(normalizedYear - 1)) {
2198 --prevJan1;
2199 }
2200 } else {
2201 BaseCalendar calForJan1 = calsys;
2202 int prevYear = normalizedYear - 1;
2203 if (prevYear == cutoverYear) {
2204 calForJan1 = getCutoverCalendarSystem();
2205 }
2206 prevJan1 = calForJan1.getFixedDate(prevYear,
2207 BaseCalendar.JANUARY,
2208 1,
2209 null);
2210 while (prevJan1 > fixedDec31) {
2211 prevJan1 = getJulianCalendarSystem().getFixedDate(--prevYear,
2212 BaseCalendar.JANUARY,
2213 1,
2214 null);
2215 }
2216 }
2217 weekOfYear = getWeekNumber(prevJan1, fixedDec31);
2218 } else {
2219 if (normalizedYear > gregorianCutoverYear ||
2220 normalizedYear < (gregorianCutoverYearJulian - 1)) {
2221 // Regular years
2222 if (weekOfYear >= 52) {
2223 long nextJan1 = fixedDateJan1 + 365;
2224 if (cdate.isLeapYear()) {
2225 nextJan1++;
2226 }
2227 long nextJan1st = calsys.getDayOfWeekDateOnOrBefore(nextJan1 + 6,
2228 getFirstDayOfWeek());
2229 int ndays = (int)(nextJan1st - nextJan1);
2230 if (ndays >= getMinimalDaysInFirstWeek() && fixedDate >= (nextJan1st - 7)) {
2231 // The first days forms a week in which the date is included.
2232 weekOfYear = 1;
2233 }
2234 }
2235 } else {
2236 BaseCalendar calForJan1 = calsys;
2237 int nextYear = normalizedYear + 1;
2238 if (nextYear == (gregorianCutoverYearJulian + 1) &&
2239 nextYear < gregorianCutoverYear) {
2240 // In case the gap is more than one year.
2241 nextYear = gregorianCutoverYear;
2242 }
2243 if (nextYear == gregorianCutoverYear) {
2244 calForJan1 = getCutoverCalendarSystem();
2245 }
2246 long nextJan1 = calForJan1.getFixedDate(nextYear,
2247 BaseCalendar.JANUARY,
2248 1,
2249 null);
2250 if (nextJan1 < fixedDate) {
2251 nextJan1 = gregorianCutoverDate;
2252 calForJan1 = gcal;
2253 }
2254 long nextJan1st = calForJan1.getDayOfWeekDateOnOrBefore(nextJan1 + 6,
2255 getFirstDayOfWeek());
2256 int ndays = (int)(nextJan1st - nextJan1);
2257 if (ndays >= getMinimalDaysInFirstWeek() && fixedDate >= (nextJan1st - 7)) {
2258 // The first days forms a week in which the date is included.
2259 weekOfYear = 1;
2260 }
2261 }
2262 }
2263 internalSet(WEEK_OF_YEAR, weekOfYear);
2264 internalSet(WEEK_OF_MONTH, getWeekNumber(fixedDateMonth1, fixedDate));
2265 mask |= (DAY_OF_YEAR_MASK|WEEK_OF_YEAR_MASK|WEEK_OF_MONTH_MASK|DAY_OF_WEEK_IN_MONTH_MASK);
2266 }
2267 return mask;
2268 }
2269
2270 /**
2271 * Returns the number of weeks in a period between fixedDay1 and
2272 * fixedDate. The getFirstDayOfWeek-getMinimalDaysInFirstWeek rule
2273 * is applied to calculate the number of weeks.
2274 *
2275 * @param fixedDay1 the fixed date of the first day of the period
2276 * @param fixedDate the fixed date of the last day of the period
2277 * @return the number of weeks of the given period
2278 */
2279 private final int getWeekNumber(long fixedDay1, long fixedDate) {
2280 // We can always use `gcal' since Julian and Gregorian are the
2281 // same thing for this calculation.
2282 long fixedDay1st = gcal.getDayOfWeekDateOnOrBefore(fixedDay1 + 6,
2283 getFirstDayOfWeek());
2284 int ndays = (int)(fixedDay1st - fixedDay1);
2285 assert ndays <= 7;
2286 if (ndays >= getMinimalDaysInFirstWeek()) {
2287 fixedDay1st -= 7;
2288 }
2289 int normalizedDayOfPeriod = (int)(fixedDate - fixedDay1st);
2290 if (normalizedDayOfPeriod >= 0) {
2291 return normalizedDayOfPeriod / 7 + 1;
2292 }
2293 return CalendarUtils.floorDivide(normalizedDayOfPeriod, 7) + 1;
2294 }
2295
2296 /**
2297 * Converts calendar field values to the time value (millisecond
2298 * offset from the <a href="Calendar.html#Epoch">Epoch</a>).
2299 *
2300 * @exception IllegalArgumentException if any calendar fields are invalid.
2301 */
2302 protected void computeTime() {
2303 // In non-lenient mode, perform brief checking of calendar
2304 // fields which have been set externally. Through this
2305 // checking, the field values are stored in originalFields[]
2306 // to see if any of them are normalized later.
2307 if (!isLenient()) {
2308 if (originalFields == null) {
2309 originalFields = new int[FIELD_COUNT];
2310 }
2311 for (int field = 0; field < FIELD_COUNT; field++) {
2312 int value = internalGet(field);
2313 if (isExternallySet(field)) {
2314 // Quick validation for any out of range values
2315 if (value < getMinimum(field) || value > getMaximum(field)) {
2316 throw new IllegalArgumentException(getFieldName(field));
2317 }
2318 }
2319 originalFields[field] = value;
2320 }
2321 }
2322
2323 // Let the super class determine which calendar fields to be
2324 // used to calculate the time.
2325 int fieldMask = selectFields();
2326
2327 // The year defaults to the epoch start. We don't check
2328 // fieldMask for YEAR because YEAR is a mandatory field to
2329 // determine the date.
2330 int year = isSet(YEAR) ? internalGet(YEAR) : EPOCH_YEAR;
2331
2332 int era = internalGetEra();
2333 if (era == BCE) {
2334 year = 1 - year;
2335 } else if (era != CE) {
2336 // Even in lenient mode we disallow ERA values other than CE & BCE.
2337 // (The same normalization rule as add()/roll() could be
2338 // applied here in lenient mode. But this checking is kept
2339 // unchanged for compatibility as of 1.5.)
2340 throw new IllegalArgumentException("Invalid era");
2341 }
2342
2343 // If year is 0 or negative, we need to set the ERA value later.
2344 if (year <= 0 && !isSet(ERA)) {
2345 fieldMask |= ERA_MASK;
2346 setFieldsComputed(ERA_MASK);
2347 }
2348
2349 // Calculate the time of day. We rely on the convention that
2350 // an UNSET field has 0.
2351 long timeOfDay = 0;
2352 if (isFieldSet(fieldMask, HOUR_OF_DAY)) {
2353 timeOfDay += (long) internalGet(HOUR_OF_DAY);
2354 } else {
2355 timeOfDay += internalGet(HOUR);
2356 // The default value of AM_PM is 0 which designates AM.
2357 if (isFieldSet(fieldMask, AM_PM)) {
2358 timeOfDay += 12 * internalGet(AM_PM);
2359 }
2360 }
2361 timeOfDay *= 60;
2362 timeOfDay += internalGet(MINUTE);
2363 timeOfDay *= 60;
2364 timeOfDay += internalGet(SECOND);
2365 timeOfDay *= 1000;
2366 timeOfDay += internalGet(MILLISECOND);
2367
2368 // Convert the time of day to the number of days and the
2369 // millisecond offset from midnight.
2370 long fixedDate = timeOfDay / ONE_DAY;
2371 timeOfDay %= ONE_DAY;
2372 while (timeOfDay < 0) {
2373 timeOfDay += ONE_DAY;
2374 --fixedDate;
2375 }
2376
2377 // Calculate the fixed date since January 1, 1 (Gregorian).
2378 calculateFixedDate: {
2379 long gfd, jfd;
2380 if (year > gregorianCutoverYear && year > gregorianCutoverYearJulian) {
2381 gfd = fixedDate + getFixedDate(gcal, year, fieldMask);
2382 if (gfd >= gregorianCutoverDate) {
2383 fixedDate = gfd;
2384 break calculateFixedDate;
2385 }
2386 jfd = fixedDate + getFixedDate(getJulianCalendarSystem(), year, fieldMask);
2387 } else if (year < gregorianCutoverYear && year < gregorianCutoverYearJulian) {
2388 jfd = fixedDate + getFixedDate(getJulianCalendarSystem(), year, fieldMask);
2389 if (jfd < gregorianCutoverDate) {
2390 fixedDate = jfd;
2391 break calculateFixedDate;
2392 }
2393 gfd = fixedDate + getFixedDate(gcal, year, fieldMask);
2394 } else {
2395 gfd = fixedDate + getFixedDate(gcal, year, fieldMask);
2396 jfd = fixedDate + getFixedDate(getJulianCalendarSystem(), year, fieldMask);
2397 }
2398 // Now we have to determine which calendar date it is.
2399 if (gfd >= gregorianCutoverDate) {
2400 if (jfd >= gregorianCutoverDate) {
2401 fixedDate = gfd;
2402 } else {
2403 // The date is in an "overlapping" period. No way
2404 // to disambiguate it. Determine it using the
2405 // previous date calculation.
2406 if (calsys == gcal || calsys == null) {
2407 fixedDate = gfd;
2408 } else {
2409 fixedDate = jfd;
2410 }
2411 }
2412 } else {
2413 if (jfd < gregorianCutoverDate) {
2414 fixedDate = jfd;
2415 } else {
2416 // The date is in a "missing" period.
2417 if (!isLenient()) {
2418 throw new IllegalArgumentException("the specified date doesn't exist");
2419 }
2420 // Take the Julian date for compatibility, which
2421 // will produce a Gregorian date.
2422 fixedDate = jfd;
2423 }
2424 }
2425 }
2426
2427 // millis represents local wall-clock time in milliseconds.
2428 long millis = (fixedDate - EPOCH_OFFSET) * ONE_DAY + timeOfDay;
2429
2430 // Compute the time zone offset and DST offset. There are two potential
2431 // ambiguities here. We'll assume a 2:00 am (wall time) switchover time
2432 // for discussion purposes here.
2433 // 1. The transition into DST. Here, a designated time of 2:00 am - 2:59 am
2434 // can be in standard or in DST depending. However, 2:00 am is an invalid
2435 // representation (the representation jumps from 1:59:59 am Std to 3:00:00 am DST).
2436 // We assume standard time.
2437 // 2. The transition out of DST. Here, a designated time of 1:00 am - 1:59 am
2438 // can be in standard or DST. Both are valid representations (the rep
2439 // jumps from 1:59:59 DST to 1:00:00 Std).
2440 // Again, we assume standard time.
2441 // We use the TimeZone object, unless the user has explicitly set the ZONE_OFFSET
2442 // or DST_OFFSET fields; then we use those fields.
2443 TimeZone zone = getZone();
2444 if (zoneOffsets == null) {
2445 zoneOffsets = new int[2];
2446 }
2447 int tzMask = fieldMask & (ZONE_OFFSET_MASK|DST_OFFSET_MASK);
2448 if (tzMask != (ZONE_OFFSET_MASK|DST_OFFSET_MASK)) {
2449 if (zone instanceof ZoneInfo) {
2450 ((ZoneInfo)zone).getOffsetsByWall(millis, zoneOffsets);
2451 } else {
2452 int gmtOffset = isFieldSet(fieldMask, ZONE_OFFSET) ?
2453 internalGet(ZONE_OFFSET) : zone.getRawOffset();
2454 zone.getOffsets(millis - gmtOffset, zoneOffsets);
2455 }
2456 }
2457 if (tzMask != 0) {
2458 if (isFieldSet(tzMask, ZONE_OFFSET)) {
2459 zoneOffsets[0] = internalGet(ZONE_OFFSET);
2460 }
2461 if (isFieldSet(tzMask, DST_OFFSET)) {
2462 zoneOffsets[1] = internalGet(DST_OFFSET);
2463 }
2464 }
2465
2466 // Adjust the time zone offset values to get the UTC time.
2467 millis -= zoneOffsets[0] + zoneOffsets[1];
2468
2469 // Set this calendar's time in milliseconds
2470 time = millis;
2471
2472 int mask = computeFields(fieldMask | getSetStateFields(), tzMask);
2473
2474 if (!isLenient()) {
2475 for (int field = 0; field < FIELD_COUNT; field++) {
2476 if (!isExternallySet(field)) {
2477 continue;
2478 }
2479 if (originalFields[field] != internalGet(field)) {
2480 // Restore the original field values
2481 System.arraycopy(originalFields, 0, fields, 0, fields.length);
2482 throw new IllegalArgumentException(getFieldName(field));
2483 }
2484 }
2485 }
2486 setFieldsNormalized(mask);
2487 }
2488
2489 /**
2490 * Computes the fixed date under either the Gregorian or the
2491 * Julian calendar, using the given year and the specified calendar fields.
2492 *
2493 * @param cal the CalendarSystem to be used for the date calculation
2494 * @param year the normalized year number, with 0 indicating the
2495 * year 1 BCE, -1 indicating 2 BCE, etc.
2496 * @param fieldMask the calendar fields to be used for the date calculation
2497 * @return the fixed date
2498 * @see Calendar#selectFields
2499 */
2500 private long getFixedDate(BaseCalendar cal, int year, int fieldMask) {
2501 int month = JANUARY;
2502 if (isFieldSet(fieldMask, MONTH)) {
2503 // No need to check if MONTH has been set (no isSet(MONTH)
2504 // call) since its unset value happens to be JANUARY (0).
2505 month = internalGet(MONTH);
2506
2507 // If the month is out of range, adjust it into range
2508 if (month > DECEMBER) {
2509 year += month / 12;
2510 month %= 12;
2511 } else if (month < JANUARY) {
2512 int[] rem = new int[1];
2513 year += CalendarUtils.floorDivide(month, 12, rem);
2514 month = rem[0];
2515 }
2516 }
2517
2518 // Get the fixed date since Jan 1, 1 (Gregorian). We are on
2519 // the first day of either `month' or January in 'year'.
2520 long fixedDate = cal.getFixedDate(year, month + 1, 1,
2521 cal == gcal ? gdate : null);
2522 if (isFieldSet(fieldMask, MONTH)) {
2523 // Month-based calculations
2524 if (isFieldSet(fieldMask, DAY_OF_MONTH)) {
2525 // We are on the first day of the month. Just add the
2526 // offset if DAY_OF_MONTH is set. If the isSet call
2527 // returns false, that means DAY_OF_MONTH has been
2528 // selected just because of the selected
2529 // combination. We don't need to add any since the
2530 // default value is the 1st.
2531 if (isSet(DAY_OF_MONTH)) {
2532 // To avoid underflow with DAY_OF_MONTH-1, add
2533 // DAY_OF_MONTH, then subtract 1.
2534 fixedDate += internalGet(DAY_OF_MONTH);
2535 fixedDate--;
2536 }
2537 } else {
2538 if (isFieldSet(fieldMask, WEEK_OF_MONTH)) {
2539 long firstDayOfWeek = cal.getDayOfWeekDateOnOrBefore(fixedDate + 6,
2540 getFirstDayOfWeek());
2541 // If we have enough days in the first week, then
2542 // move to the previous week.
2543 if ((firstDayOfWeek - fixedDate) >= getMinimalDaysInFirstWeek()) {
2544 firstDayOfWeek -= 7;
2545 }
2546 if (isFieldSet(fieldMask, DAY_OF_WEEK)) {
2547 firstDayOfWeek = cal.getDayOfWeekDateOnOrBefore(firstDayOfWeek + 6,
2548 internalGet(DAY_OF_WEEK));
2549 }
2550 // In lenient mode, we treat days of the previous
2551 // months as a part of the specified
2552 // WEEK_OF_MONTH. See 4633646.
2553 fixedDate = firstDayOfWeek + 7 * (internalGet(WEEK_OF_MONTH) - 1);
2554 } else {
2555 int dayOfWeek;
2556 if (isFieldSet(fieldMask, DAY_OF_WEEK)) {
2557 dayOfWeek = internalGet(DAY_OF_WEEK);
2558 } else {
2559 dayOfWeek = getFirstDayOfWeek();
2560 }
2561 // We are basing this on the day-of-week-in-month. The only
2562 // trickiness occurs if the day-of-week-in-month is
2563 // negative.
2564 int dowim;
2565 if (isFieldSet(fieldMask, DAY_OF_WEEK_IN_MONTH)) {
2566 dowim = internalGet(DAY_OF_WEEK_IN_MONTH);
2567 } else {
2568 dowim = 1;
2569 }
2570 if (dowim >= 0) {
2571 fixedDate = cal.getDayOfWeekDateOnOrBefore(fixedDate + (7 * dowim) - 1,
2572 dayOfWeek);
2573 } else {
2574 // Go to the first day of the next week of
2575 // the specified week boundary.
2576 int lastDate = monthLength(month, year) + (7 * (dowim + 1));
2577 // Then, get the day of week date on or before the last date.
2578 fixedDate = cal.getDayOfWeekDateOnOrBefore(fixedDate + lastDate - 1,
2579 dayOfWeek);
2580 }
2581 }
2582 }
2583 } else {
2584 if (year == gregorianCutoverYear && cal == gcal
2585 && fixedDate < gregorianCutoverDate
2586 && gregorianCutoverYear != gregorianCutoverYearJulian) {
2587 // January 1 of the year doesn't exist. Use
2588 // gregorianCutoverDate as the first day of the
2589 // year.
2590 fixedDate = gregorianCutoverDate;
2591 }
2592 // We are on the first day of the year.
2593 if (isFieldSet(fieldMask, DAY_OF_YEAR)) {
2594 // Add the offset, then subtract 1. (Make sure to avoid underflow.)
2595 fixedDate += internalGet(DAY_OF_YEAR);
2596 fixedDate--;
2597 } else {
2598 long firstDayOfWeek = cal.getDayOfWeekDateOnOrBefore(fixedDate + 6,
2599 getFirstDayOfWeek());
2600 // If we have enough days in the first week, then move
2601 // to the previous week.
2602 if ((firstDayOfWeek - fixedDate) >= getMinimalDaysInFirstWeek()) {
2603 firstDayOfWeek -= 7;
2604 }
2605 if (isFieldSet(fieldMask, DAY_OF_WEEK)) {
2606 int dayOfWeek = internalGet(DAY_OF_WEEK);
2607 if (dayOfWeek != getFirstDayOfWeek()) {
2608 firstDayOfWeek = cal.getDayOfWeekDateOnOrBefore(firstDayOfWeek + 6,
2609 dayOfWeek);
2610 }
2611 }
2612 fixedDate = firstDayOfWeek + 7 * ((long)internalGet(WEEK_OF_YEAR) - 1);
2613 }
2614 }
2615
2616 return fixedDate;
2617 }
2618
2619 /**
2620 * Returns this object if it's normalized (all fields and time are
2621 * in sync). Otherwise, a cloned object is returned after calling
2622 * complete() in lenient mode.
2623 */
2624 private final GregorianCalendar getNormalizedCalendar() {
2625 GregorianCalendar gc;
2626 if (isFullyNormalized()) {
2627 gc = this;
2628 } else {
2629 // Create a clone and normalize the calendar fields
2630 gc = (GregorianCalendar) this.clone();
2631 gc.setLenient(true);
2632 gc.complete();
2633 }
2634 return gc;
2635 }
2636
2637 /**
2638 * Returns the Julian calendar system instance (singleton). 'jcal'
2639 * and 'jeras' are set upon the return.
2640 */
2641 synchronized private static final BaseCalendar getJulianCalendarSystem() {
2642 if (jcal == null) {
2643 jcal = (JulianCalendar) CalendarSystem.forName("julian");
2644 jeras = jcal.getEras();
2645 }
2646 return jcal;
2647 }
2648
2649 /**
2650 * Returns the calendar system for dates before the cutover date
2651 * in the cutover year. If the cutover date is January 1, the
2652 * method returns Gregorian. Otherwise, Julian.
2653 */
2654 private BaseCalendar getCutoverCalendarSystem() {
2655 CalendarDate date = getGregorianCutoverDate();
2656 if (date.getMonth() == BaseCalendar.JANUARY
2657 && date.getDayOfMonth() == 1) {
2658 return gcal;
2659 }
2660 return getJulianCalendarSystem();
2661 }
2662
2663 /**
2664 * Determines if the specified year (normalized) is the Gregorian
2665 * cutover year. This object must have been normalized.
2666 */
2667 private final boolean isCutoverYear(int normalizedYear) {
2668 int cutoverYear = (calsys == gcal) ? gregorianCutoverYear : gregorianCutoverYearJulian;
2669 return normalizedYear == cutoverYear;
2670 }
2671
2672 /**
2673 * Returns the fixed date of the first day of the year (usually
2674 * January 1) before the specified date.
2675 *
2676 * @param date the date for which the first day of the year is
2677 * calculated. The date has to be in the cut-over year (Gregorian
2678 * or Julian).
2679 * @param fixedDate the fixed date representation of the date
2680 */
2681 private final long getFixedDateJan1(BaseCalendar.Date date, long fixedDate) {
2682 assert date.getNormalizedYear() == gregorianCutoverYear ||
2683 date.getNormalizedYear() == gregorianCutoverYearJulian;
2684 if (gregorianCutoverYear != gregorianCutoverYearJulian) {
2685 if (fixedDate >= gregorianCutoverDate) {
2686 // Dates before the cutover date don't exist
2687 // in the same (Gregorian) year. So, no
2688 // January 1 exists in the year. Use the
2689 // cutover date as the first day of the year.
2690 return gregorianCutoverDate;
2691 }
2692 }
2693 // January 1 of the normalized year should exist.
2694 BaseCalendar jcal = getJulianCalendarSystem();
2695 return jcal.getFixedDate(date.getNormalizedYear(), BaseCalendar.JANUARY, 1, null);
2696 }
2697
2698 /**
2699 * Returns the fixed date of the first date of the month (usually
2700 * the 1st of the month) before the specified date.
2701 *
2702 * @param date the date for which the first day of the month is
2703 * calculated. The date has to be in the cut-over year (Gregorian
2704 * or Julian).
2705 * @param fixedDate the fixed date representation of the date
2706 */
2707 private final long getFixedDateMonth1(BaseCalendar.Date date, long fixedDate) {
2708 assert date.getNormalizedYear() == gregorianCutoverYear ||
2709 date.getNormalizedYear() == gregorianCutoverYearJulian;
2710 BaseCalendar.Date gCutover = getGregorianCutoverDate();
2711 if (gCutover.getMonth() == BaseCalendar.JANUARY
2712 && gCutover.getDayOfMonth() == 1) {
2713 // The cutover happened on January 1.
2714 return fixedDate - date.getDayOfMonth() + 1;
2715 }
2716
2717 long fixedDateMonth1;
2718 // The cutover happened sometime during the year.
2719 if (date.getMonth() == gCutover.getMonth()) {
2720 // The cutover happened in the month.
2721 BaseCalendar.Date jLastDate = getLastJulianDate();
2722 if (gregorianCutoverYear == gregorianCutoverYearJulian
2723 && gCutover.getMonth() == jLastDate.getMonth()) {
2724 // The "gap" fits in the same month.
2725 fixedDateMonth1 = jcal.getFixedDate(date.getNormalizedYear(),
2726 date.getMonth(),
2727 1,
2728 null);
2729 } else {
2730 // Use the cutover date as the first day of the month.
2731 fixedDateMonth1 = gregorianCutoverDate;
2732 }
2733 } else {
2734 // The cutover happened before the month.
2735 fixedDateMonth1 = fixedDate - date.getDayOfMonth() + 1;
2736 }
2737
2738 return fixedDateMonth1;
2739 }
2740
2741 /**
2742 * Returns a CalendarDate produced from the specified fixed date.
2743 *
2744 * @param fd the fixed date
2745 */
2746 private final BaseCalendar.Date getCalendarDate(long fd) {
2747 BaseCalendar cal = (fd >= gregorianCutoverDate) ? gcal : getJulianCalendarSystem();
2748 BaseCalendar.Date d = (BaseCalendar.Date) cal.newCalendarDate(TimeZone.NO_TIMEZONE);
2749 cal.getCalendarDateFromFixedDate(d, fd);
2750 return d;
2751 }
2752
2753 /**
2754 * Returns the Gregorian cutover date as a BaseCalendar.Date. The
2755 * date is a Gregorian date.
2756 */
2757 private final BaseCalendar.Date getGregorianCutoverDate() {
2758 return getCalendarDate(gregorianCutoverDate);
2759 }
2760
2761 /**
2762 * Returns the day before the Gregorian cutover date as a
2763 * BaseCalendar.Date. The date is a Julian date.
2764 */
2765 private final BaseCalendar.Date getLastJulianDate() {
2766 return getCalendarDate(gregorianCutoverDate - 1);
2767 }
2768
2769 /**
2770 * Returns the length of the specified month in the specified
2771 * year. The year number must be normalized.
2772 *
2773 * @see #isLeapYear(int)
2774 */
2775 private final int monthLength(int month, int year) {
2776 return isLeapYear(year) ? LEAP_MONTH_LENGTH[month] : MONTH_LENGTH[month];
2777 }
2778
2779 /**
2780 * Returns the length of the specified month in the year provided
2781 * by internalGet(YEAR).
2782 *
2783 * @see #isLeapYear(int)
2784 */
2785 private final int monthLength(int month) {
2786 int year = internalGet(YEAR);
2787 if (internalGetEra() == BCE) {
2788 year = 1 - year;
2789 }
2790 return monthLength(month, year);
2791 }
2792
2793 private final int actualMonthLength() {
2794 int year = cdate.getNormalizedYear();
2795 if (year != gregorianCutoverYear && year != gregorianCutoverYearJulian) {
2796 return calsys.getMonthLength(cdate);
2797 }
2798 BaseCalendar.Date date = (BaseCalendar.Date) cdate.clone();
2799 long fd = calsys.getFixedDate(date);
2800 long month1 = getFixedDateMonth1(date, fd);
2801 long next1 = month1 + calsys.getMonthLength(date);
2802 if (next1 < gregorianCutoverDate) {
2803 return (int)(next1 - month1);
2804 }
2805 if (cdate != gdate) {
2806 date = (BaseCalendar.Date) gcal.newCalendarDate(TimeZone.NO_TIMEZONE);
2807 }
2808 gcal.getCalendarDateFromFixedDate(date, next1);
2809 next1 = getFixedDateMonth1(date, next1);
2810 return (int)(next1 - month1);
2811 }
2812
2813 /**
2814 * Returns the length (in days) of the specified year. The year
2815 * must be normalized.
2816 */
2817 private final int yearLength(int year) {
2818 return isLeapYear(year) ? 366 : 365;
2819 }
2820
2821 /**
2822 * Returns the length (in days) of the year provided by
2823 * internalGet(YEAR).
2824 */
2825 private final int yearLength() {
2826 int year = internalGet(YEAR);
2827 if (internalGetEra() == BCE) {
2828 year = 1 - year;
2829 }
2830 return yearLength(year);
2831 }
2832
2833 /**
2834 * After adjustments such as add(MONTH), add(YEAR), we don't want the
2835 * month to jump around. E.g., we don't want Jan 31 + 1 month to go to Mar
2836 * 3, we want it to go to Feb 28. Adjustments which might run into this
2837 * problem call this method to retain the proper month.
2838 */
2839 private final void pinDayOfMonth() {
2840 int year = internalGet(YEAR);
2841 int monthLen;
2842 if (year > gregorianCutoverYear || year < gregorianCutoverYearJulian) {
2843 monthLen = monthLength(internalGet(MONTH));
2844 } else {
2845 GregorianCalendar gc = getNormalizedCalendar();
2846 monthLen = gc.getActualMaximum(DAY_OF_MONTH);
2847 }
2848 int dom = internalGet(DAY_OF_MONTH);
2849 if (dom > monthLen) {
2850 set(DAY_OF_MONTH, monthLen);
2851 }
2852 }
2853
2854 /**
2855 * Returns the fixed date value of this object. The time value and
2856 * calendar fields must be in synch.
2857 */
2858 private final long getCurrentFixedDate() {
2859 return (calsys == gcal) ? cachedFixedDate : calsys.getFixedDate(cdate);
2860 }
2861
2862 /**
2863 * Returns the new value after 'roll'ing the specified value and amount.
2864 */
2865 private static final int getRolledValue(int value, int amount, int min, int max) {
2866 assert value >= min && value <= max;
2867 int range = max - min + 1;
2868 amount %= range;
2869 int n = value + amount;
2870 if (n > max) {
2871 n -= range;
2872 } else if (n < min) {
2873 n += range;
2874 }
2875 assert n >= min && n <= max;
2876 return n;
2877 }
2878
2879 /**
2880 * Returns the ERA. We need a special method for this because the
2881 * default ERA is CE, but a zero (unset) ERA is BCE.
2882 */
2883 private final int internalGetEra() {
2884 return isSet(ERA) ? internalGet(ERA) : CE;
2885 }
2886
2887 /**
2888 * Updates internal state.
2889 */
2890 private void readObject(ObjectInputStream stream)
2891 throws IOException, ClassNotFoundException {
2892 stream.defaultReadObject();
2893 if (gdate == null) {
2894 gdate = (BaseCalendar.Date) gcal.newCalendarDate(getZone());
2895 cachedFixedDate = Long.MIN_VALUE;
2896 }
2897 setGregorianChange(gregorianCutover);
2898 }
2899}
2900