History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/java/util/GregorianCalendar.java (1 of 18352 files). Show all

Unified · Split

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