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
39package java.util;
40
41import java.io.IOException;
42import java.io.ObjectInputStream;
43import sun.util.calendar.BaseCalendar;
44import sun.util.calendar.CalendarDate;
45import sun.util.calendar.CalendarSystem;
46import sun.util.calendar.CalendarUtils;
47import sun.util.calendar.Era;
48import sun.util.calendar.Gregorian;
49import sun.util.calendar.JulianCalendar;
50import 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 */
327public 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}