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