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