KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > java > util > GregorianCalendar


1 /*
2  * @(#)GregorianCalendar.java 1.90 06/07/31
3  *
4  * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7
8 /*
9  * (C) Copyright Taligent, Inc. 1996-1998 - All Rights Reserved
10  * (C) Copyright IBM Corp. 1996-1998 - All Rights Reserved
11  *
12  * The original version of this source code and documentation is copyrighted
13  * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
14  * materials are provided under terms of a License Agreement between Taligent
15  * and Sun. This technology is protected by multiple US and International
16  * patents. This notice and attribution to Taligent may not be removed.
17  * Taligent is a registered trademark of Taligent, Inc.
18  *
19  */

20
21 package java.util;
22
23 import java.io.IOException JavaDoc;
24 import java.io.ObjectInputStream JavaDoc;
25 import sun.util.calendar.BaseCalendar;
26 import sun.util.calendar.CalendarDate;
27 import sun.util.calendar.CalendarSystem;
28 import sun.util.calendar.CalendarUtils;
29 import sun.util.calendar.Era;
30 import sun.util.calendar.Gregorian;
31 import sun.util.calendar.JulianCalendar;
32 import sun.util.calendar.ZoneInfo;
33
34 /**
35  * <code>GregorianCalendar</code> is a concrete subclass of
36  * <code>Calendar</code> and provides the standard calendar system
37  * used by most of the world.
38  *
39  * <p> <code>GregorianCalendar</code> is a hybrid calendar that
40  * supports both the Julian and Gregorian calendar systems with the
41  * support of a single discontinuity, which corresponds by default to
42  * the Gregorian date when the Gregorian calendar was instituted
43  * (October 15, 1582 in some countries, later in others). The cutover
44  * date may be changed by the caller by calling {@link
45  * #setGregorianChange(Date) setGregorianChange()}.
46  *
47  * <p>
48  * Historically, in those countries which adopted the Gregorian calendar first,
49  * October 4, 1582 (Julian) was thus followed by October 15, 1582 (Gregorian). This calendar models
50  * this correctly. Before the Gregorian cutover, <code>GregorianCalendar</code>
51  * implements the Julian calendar. The only difference between the Gregorian
52  * and the Julian calendar is the leap year rule. The Julian calendar specifies
53  * leap years every four years, whereas the Gregorian calendar omits century
54  * years which are not divisible by 400.
55  *
56  * <p>
57  * <code>GregorianCalendar</code> implements <em>proleptic</em> Gregorian and
58  * Julian calendars. That is, dates are computed by extrapolating the current
59  * rules indefinitely far backward and forward in time. As a result,
60  * <code>GregorianCalendar</code> may be used for all years to generate
61  * meaningful and consistent results. However, dates obtained using
62  * <code>GregorianCalendar</code> are historically accurate only from March 1, 4
63  * AD onward, when modern Julian calendar rules were adopted. Before this date,
64  * leap year rules were applied irregularly, and before 45 BC the Julian
65  * calendar did not even exist.
66  *
67  * <p>
68  * Prior to the institution of the Gregorian calendar, New Year's Day was
69  * March 25. To avoid confusion, this calendar always uses January 1. A manual
70  * adjustment may be made if desired for dates that are prior to the Gregorian
71  * changeover and which fall between January 1 and March 24.
72  *
73  * <p>Values calculated for the <code>WEEK_OF_YEAR</code> field range from 1 to
74  * 53. Week 1 for a year is the earliest seven day period starting on
75  * <code>getFirstDayOfWeek()</code> that contains at least
76  * <code>getMinimalDaysInFirstWeek()</code> days from that year. It thus
77  * depends on the values of <code>getMinimalDaysInFirstWeek()</code>,
78  * <code>getFirstDayOfWeek()</code>, and the day of the week of January 1.
79  * Weeks between week 1 of one year and week 1 of the following year are
80  * numbered sequentially from 2 to 52 or 53 (as needed).
81
82  * <p>For example, January 1, 1998 was a Thursday. If
83  * <code>getFirstDayOfWeek()</code> is <code>MONDAY</code> and
84  * <code>getMinimalDaysInFirstWeek()</code> is 4 (these are the values
85  * reflecting ISO 8601 and many national standards), then week 1 of 1998 starts
86  * on December 29, 1997, and ends on January 4, 1998. If, however,
87  * <code>getFirstDayOfWeek()</code> is <code>SUNDAY</code>, then week 1 of 1998
88  * starts on January 4, 1998, and ends on January 10, 1998; the first three days
89  * of 1998 then are part of week 53 of 1997.
90  *
91  * <p>Values calculated for the <code>WEEK_OF_MONTH</code> field range from 0
92  * to 6. Week 1 of a month (the days with <code>WEEK_OF_MONTH =
93  * 1</code>) is the earliest set of at least
94  * <code>getMinimalDaysInFirstWeek()</code> contiguous days in that month,
95  * ending on the day before <code>getFirstDayOfWeek()</code>. Unlike
96  * week 1 of a year, week 1 of a month may be shorter than 7 days, need
97  * not start on <code>getFirstDayOfWeek()</code>, and will not include days of
98  * the previous month. Days of a month before week 1 have a
99  * <code>WEEK_OF_MONTH</code> of 0.
100  *
101  * <p>For example, if <code>getFirstDayOfWeek()</code> is <code>SUNDAY</code>
102  * and <code>getMinimalDaysInFirstWeek()</code> is 4, then the first week of
103  * January 1998 is Sunday, January 4 through Saturday, January 10. These days
104  * have a <code>WEEK_OF_MONTH</code> of 1. Thursday, January 1 through
105  * Saturday, January 3 have a <code>WEEK_OF_MONTH</code> of 0. If
106  * <code>getMinimalDaysInFirstWeek()</code> is changed to 3, then January 1
107  * through January 3 have a <code>WEEK_OF_MONTH</code> of 1.
108  *
109  * <p>The <code>clear</code> methods set calendar field(s)
110  * undefined. <code>GregorianCalendar</code> uses the following
111  * default value for each calendar field if its value is undefined.
112  *
113  * <table cellpadding="0" cellspacing="3" border="0"
114  * summary="GregorianCalendar default field values"
115  * style="text-align: left; width: 66%;">
116  * <tbody>
117  * <tr>
118  * <th style="vertical-align: top; background-color: rgb(204, 204, 255);
119  * text-align: center;">Field<br>
120  * </th>
121  * <th style="vertical-align: top; background-color: rgb(204, 204, 255);
122  * text-align: center;">Default Value<br>
123  * </th>
124  * </tr>
125  * <tr>
126  * <td style="vertical-align: middle;">
127  * <code>ERA<br></code>
128  * </td>
129  * <td style="vertical-align: middle;">
130  * <code>AD<br></code>
131  * </td>
132  * </tr>
133  * <tr>
134  * <td style="vertical-align: middle; background-color: rgb(238, 238, 255);">
135  * <code>YEAR<br></code>
136  * </td>
137  * <td style="vertical-align: middle; background-color: rgb(238, 238, 255);">
138  * <code>1970<br></code>
139  * </td>
140  * </tr>
141  * <tr>
142  * <td style="vertical-align: middle;">
143  * <code>MONTH<br></code>
144  * </td>
145  * <td style="vertical-align: middle;">
146  * <code>JANUARY<br></code>
147  * </td>
148  * </tr>
149  * <tr>
150  * <td style="vertical-align: top; background-color: rgb(238, 238, 255);">
151  * <code>DAY_OF_MONTH<br></code>
152  * </td>
153  * <td style="vertical-align: top; background-color: rgb(238, 238, 255);">
154  * <code>1<br></code>
155  * </td>
156  * </tr>
157  * <tr>
158  * <td style="vertical-align: middle;">
159  * <code>DAY_OF_WEEK<br></code>
160  * </td>
161  * <td style="vertical-align: middle;">
162  * <code>the first day of week<br></code>
163  * </td>
164  * </tr>
165  * <tr>
166  * <td style="vertical-align: top; background-color: rgb(238, 238, 255);">
167  * <code>WEEK_OF_MONTH<br></code>
168  * </td>
169  * <td style="vertical-align: top; background-color: rgb(238, 238, 255);">
170  * <code>0<br></code>
171  * </td>
172  * </tr>
173  * <tr>
174  * <td style="vertical-align: top;">
175  * <code>DAY_OF_WEEK_IN_MONTH<br></code>
176  * </td>
177  * <td style="vertical-align: top;">
178  * <code>1<br></code>
179  * </td>
180  * </tr>
181  * <tr>
182  * <td style="vertical-align: middle; background-color: rgb(238, 238, 255);">
183  * <code>AM_PM<br></code>
184  * </td>
185  * <td style="vertical-align: middle; background-color: rgb(238, 238, 255);">
186  * <code>AM<br></code>
187  * </td>
188  * </tr>
189  * <tr>
190  * <td style="vertical-align: middle;">
191  * <code>HOUR, HOUR_OF_DAY, MINUTE, SECOND, MILLISECOND<br></code>
192  * </td>
193  * <td style="vertical-align: middle;">
194  * <code>0<br></code>
195  * </td>
196  * </tr>
197  * </tbody>
198  * </table>
199  * <br>Default values are not applicable for the fields not listed above.
200  *
201  * <p>
202  * <strong>Example:</strong>
203  * <blockquote>
204  * <pre>
205  * // get the supported ids for GMT-08:00 (Pacific Standard Time)
206  * String[] ids = TimeZone.getAvailableIDs(-8 * 60 * 60 * 1000);
207  * // if no ids were returned, something is wrong. get out.
208  * if (ids.length == 0)
209  * System.exit(0);
210  *
211  * // begin output
212  * System.out.println("Current Time");
213  *
214  * // create a Pacific Standard Time time zone
215  * SimpleTimeZone pdt = new SimpleTimeZone(-8 * 60 * 60 * 1000, ids[0]);
216  *
217  * // set up rules for daylight savings time
218  * pdt.setStartRule(Calendar.APRIL, 1, Calendar.SUNDAY, 2 * 60 * 60 * 1000);
219  * pdt.setEndRule(Calendar.OCTOBER, -1, Calendar.SUNDAY, 2 * 60 * 60 * 1000);
220  *
221  * // create a GregorianCalendar with the Pacific Daylight time zone
222  * // and the current date and time
223  * Calendar calendar = new GregorianCalendar(pdt);
224  * Date trialTime = new Date();
225  * calendar.setTime(trialTime);
226  *
227  * // print out a bunch of interesting things
228  * System.out.println("ERA: " + calendar.get(Calendar.ERA));
229  * System.out.println("YEAR: " + calendar.get(Calendar.YEAR));
230  * System.out.println("MONTH: " + calendar.get(Calendar.MONTH));
231  * System.out.println("WEEK_OF_YEAR: " + calendar.get(Calendar.WEEK_OF_YEAR));
232  * System.out.println("WEEK_OF_MONTH: " + calendar.get(Calendar.WEEK_OF_MONTH));
233  * System.out.println("DATE: " + calendar.get(Calendar.DATE));
234  * System.out.println("DAY_OF_MONTH: " + calendar.get(Calendar.DAY_OF_MONTH));
235  * System.out.println("DAY_OF_YEAR: " + calendar.get(Calendar.DAY_OF_YEAR));
236  * System.out.println("DAY_OF_WEEK: " + calendar.get(Calendar.DAY_OF_WEEK));
237  * System.out.println("DAY_OF_WEEK_IN_MONTH: "
238  * + calendar.get(Calendar.DAY_OF_WEEK_IN_MONTH));
239  * System.out.println("AM_PM: " + calendar.get(Calendar.AM_PM));
240  * System.out.println("HOUR: " + calendar.get(Calendar.HOUR));
241  * System.out.println("HOUR_OF_DAY: " + calendar.get(Calendar.HOUR_OF_DAY));
242  * System.out.println("MINUTE: " + calendar.get(Calendar.MINUTE));
243  * System.out.println("SECOND: " + calendar.get(Calendar.SECOND));
244  * System.out.println("MILLISECOND: " + calendar.get(Calendar.MILLISECOND));
245  * System.out.println("ZONE_OFFSET: "
246  * + (calendar.get(Calendar.ZONE_OFFSET)/(60*60*1000)));
247  * System.out.println("DST_OFFSET: "
248  * + (calendar.get(Calendar.DST_OFFSET)/(60*60*1000)));
249
250  * System.out.println("Current Time, with hour reset to 3");
251  * calendar.clear(Calendar.HOUR_OF_DAY); // so doesn't override
252  * calendar.set(Calendar.HOUR, 3);
253  * System.out.println("ERA: " + calendar.get(Calendar.ERA));
254  * System.out.println("YEAR: " + calendar.get(Calendar.YEAR));
255  * System.out.println("MONTH: " + calendar.get(Calendar.MONTH));
256  * System.out.println("WEEK_OF_YEAR: " + calendar.get(Calendar.WEEK_OF_YEAR));
257  * System.out.println("WEEK_OF_MONTH: " + calendar.get(Calendar.WEEK_OF_MONTH));
258  * System.out.println("DATE: " + calendar.get(Calendar.DATE));
259  * System.out.println("DAY_OF_MONTH: " + calendar.get(Calendar.DAY_OF_MONTH));
260  * System.out.println("DAY_OF_YEAR: " + calendar.get(Calendar.DAY_OF_YEAR));
261  * System.out.println("DAY_OF_WEEK: " + calendar.get(Calendar.DAY_OF_WEEK));
262  * System.out.println("DAY_OF_WEEK_IN_MONTH: "
263  * + calendar.get(Calendar.DAY_OF_WEEK_IN_MONTH));
264  * System.out.println("AM_PM: " + calendar.get(Calendar.AM_PM));
265  * System.out.println("HOUR: " + calendar.get(Calendar.HOUR));
266  * System.out.println("HOUR_OF_DAY: " + calendar.get(Calendar.HOUR_OF_DAY));
267  * System.out.println("MINUTE: " + calendar.get(Calendar.MINUTE));
268  * System.out.println("SECOND: " + calendar.get(Calendar.SECOND));
269  * System.out.println("MILLISECOND: " + calendar.get(Calendar.MILLISECOND));
270  * System.out.println("ZONE_OFFSET: "
271  * + (calendar.get(Calendar.ZONE_OFFSET)/(60*60*1000))); // in hours
272  * System.out.println("DST_OFFSET: "
273  * + (calendar.get(Calendar.DST_OFFSET)/(60*60*1000))); // in hours
274  * </pre>
275  * </blockquote>
276  *
277  * @see TimeZone
278  * @version 1.90
279  * @author David Goldsmith, Mark Davis, Chen-Lieh Huang, Alan Liu
280  * @since JDK1.1
281  */

282 public class GregorianCalendar extends Calendar JavaDoc {
283     /*
284      * Implementation Notes
285      *
286      * The epoch is the number of days or milliseconds from some defined
287      * starting point. The epoch for java.util.Date is used here; that is,
288      * milliseconds from January 1, 1970 (Gregorian), midnight UTC. Other
289      * epochs which are used are January 1, year 1 (Gregorian), which is day 1
290      * of the Gregorian calendar, and December 30, year 0 (Gregorian), which is
291      * day 1 of the Julian calendar.
292      *
293      * We implement the proleptic Julian and Gregorian calendars. This means we
294      * implement the modern definition of the calendar even though the
295      * historical usage differs. For example, if the Gregorian change is set
296      * to new Date(Long.MIN_VALUE), we have a pure Gregorian calendar which
297      * labels dates preceding the invention of the Gregorian calendar in 1582 as
298      * if the calendar existed then.
299      *
300      * Likewise, with the Julian calendar, we assume a consistent
301      * 4-year leap year rule, even though the historical pattern of
302      * leap years is irregular, being every 3 years from 45 BCE
303      * through 9 BCE, then every 4 years from 8 CE onwards, with no
304      * leap years in-between. Thus date computations and functions
305      * such as isLeapYear() are not intended to be historically
306      * accurate.
307      */

308
309 //////////////////
310
// Class Variables
311
//////////////////
312

313     /**
314      * Value of the <code>ERA</code> field indicating
315      * the period before the common era (before Christ), also known as BCE.
316      * The sequence of years at the transition from <code>BC</code> to <code>AD</code> is
317      * ..., 2 BC, 1 BC, 1 AD, 2 AD,...
318      *
319      * @see #ERA
320      */

321     public static final int BC = 0;
322
323     /**
324      * Value of the {@link #ERA} field indicating
325      * the period before the common era, the same value as {@link #BC}.
326      *
327      * @see #CE
328      */

329     static final int BCE = 0;
330
331     /**
332      * Value of the <code>ERA</code> field indicating
333      * the common era (Anno Domini), also known as CE.
334      * The sequence of years at the transition from <code>BC</code> to <code>AD</code> is
335      * ..., 2 BC, 1 BC, 1 AD, 2 AD,...
336      *
337      * @see #ERA
338      */

339     public static final int AD = 1;
340
341     /**
342      * Value of the {@link #ERA} field indicating
343      * the common era, the same value as {@link #AD}.
344      *
345      * @see #BCE
346      */

347     static final int CE = 1;
348
349     private static final int EPOCH_OFFSET = 719163; // Fixed date of January 1, 1970 (Gregorian)
350
private static final int EPOCH_YEAR = 1970;
351
352     static final int MONTH_LENGTH[]
353         = {31,28,31,30,31,30,31,31,30,31,30,31}; // 0-based
354
static final int LEAP_MONTH_LENGTH[]
355         = {31,29,31,30,31,30,31,31,30,31,30,31}; // 0-based
356

357     // Useful millisecond constants. Although ONE_DAY and ONE_WEEK can fit
358
// into ints, they must be longs in order to prevent arithmetic overflow
359
// when performing (bug 4173516).
360
private static final int ONE_SECOND = 1000;
361     private static final int ONE_MINUTE = 60*ONE_SECOND;
362     private static final int ONE_HOUR = 60*ONE_MINUTE;
363     private static final long ONE_DAY = 24*ONE_HOUR;
364     private static final long ONE_WEEK = 7*ONE_DAY;
365
366     /*
367      * <pre>
368      * Greatest Least
369      * Field name Minimum Minimum Maximum Maximum
370      * ---------- ------- ------- ------- -------
371      * ERA 0 0 1 1
372      * YEAR 1 1 292269054 292278994
373      * MONTH 0 0 11 11
374      * WEEK_OF_YEAR 1 1 52* 53
375      * WEEK_OF_MONTH 0 0 4* 6
376      * DAY_OF_MONTH 1 1 28* 31
377      * DAY_OF_YEAR 1 1 365* 366
378      * DAY_OF_WEEK 1 1 7 7
379      * DAY_OF_WEEK_IN_MONTH -1 -1 4* 6
380      * AM_PM 0 0 1 1
381      * HOUR 0 0 11 11
382      * HOUR_OF_DAY 0 0 23 23
383      * MINUTE 0 0 59 59
384      * SECOND 0 0 59 59
385      * MILLISECOND 0 0 999 999
386      * ZONE_OFFSET -13:00 -13:00 14:00 14:00
387      * DST_OFFSET 0:00 0:00 0:20 2:00
388      * </pre>
389      * *: depends on the Gregorian change date
390      */

391     static final int MIN_VALUES[] = {
392         BCE, // ERA
393
1, // YEAR
394
JANUARY, // MONTH
395
1, // WEEK_OF_YEAR
396
0, // WEEK_OF_MONTH
397
1, // DAY_OF_MONTH
398
1, // DAY_OF_YEAR
399
SUNDAY, // DAY_OF_WEEK
400
1, // DAY_OF_WEEK_IN_MONTH
401
AM, // AM_PM
402
0, // HOUR
403
0, // HOUR_OF_DAY
404
0, // MINUTE
405
0, // SECOND
406
0, // MILLISECOND
407
-13*ONE_HOUR, // ZONE_OFFSET (UNIX compatibility)
408
0 // DST_OFFSET
409
};
410     static final int LEAST_MAX_VALUES[] = {
411         CE, // ERA
412
292269054, // YEAR
413
DECEMBER, // MONTH
414
52, // WEEK_OF_YEAR
415
4, // WEEK_OF_MONTH
416
28, // DAY_OF_MONTH
417
365, // DAY_OF_YEAR
418
SATURDAY, // DAY_OF_WEEK
419
4, // DAY_OF_WEEK_IN
420
PM, // AM_PM
421
11, // HOUR
422
23, // HOUR_OF_DAY
423
59, // MINUTE
424
59, // SECOND
425
999, // MILLISECOND
426
14*ONE_HOUR, // ZONE_OFFSET
427
20*ONE_MINUTE // DST_OFFSET (historical least maximum)
428
};
429     static final int MAX_VALUES[] = {
430         CE, // ERA
431
292278994, // YEAR
432
DECEMBER, // MONTH
433
53, // WEEK_OF_YEAR
434
6, // WEEK_OF_MONTH
435
31, // DAY_OF_MONTH
436
366, // DAY_OF_YEAR
437
SATURDAY, // DAY_OF_WEEK
438
6, // DAY_OF_WEEK_IN
439
PM, // AM_PM
440
11, // HOUR
441
23, // HOUR_OF_DAY
442
59, // MINUTE
443
59, // SECOND
444
999, // MILLISECOND
445
14*ONE_HOUR, // ZONE_OFFSET
446
2*ONE_HOUR // DST_OFFSET (double summer time)
447
};
448
449     // Proclaim serialization compatibility with JDK 1.1
450
static final long serialVersionUID = -8125100834729963327L;
451
452     // Reference to the sun.util.calendar.Gregorian instance (singleton).
453
private static final Gregorian gcal =
454                 CalendarSystem.getGregorianCalendar();
455
456     // Reference to the JulianCalendar instance (singleton), set as needed. See
457
// getJulianCalendarSystem().
458
private static JulianCalendar jcal;
459
460     // JulianCalendar eras. See getJulianCalendarSystem().
461
private static Era[] jeras;
462
463     // The default value of gregorianCutover.
464
static final long DEFAULT_GREGORIAN_CUTOVER = -12219292800000L;
465
466 /////////////////////
467
// Instance Variables
468
/////////////////////
469

470     /**
471      * The point at which the Gregorian calendar rules are used, measured in
472      * milliseconds from the standard epoch. Default is October 15, 1582
473      * (Gregorian) 00:00:00 UTC or -12219292800000L. For this value, October 4,
474      * 1582 (Julian) is followed by October 15, 1582 (Gregorian). This
475      * corresponds to Julian day number 2299161.
476      * @serial
477      */

478     private long gregorianCutover = DEFAULT_GREGORIAN_CUTOVER;
479
480     /**
481      * The fixed date of the gregorianCutover.
482      */

483     private transient long gregorianCutoverDate =
484         (((DEFAULT_GREGORIAN_CUTOVER + 1)/ONE_DAY) - 1) + EPOCH_OFFSET; // == 577736
485

486     /**
487      * The normalized year of the gregorianCutover in Gregorian, with
488      * 0 representing 1 BCE, -1 representing 2 BCE, etc.
489      */

490     private transient int gregorianCutoverYear = 1582;
491
492     /**
493      * The normalized year of the gregorianCutover in Julian, with 0
494      * representing 1 BCE, -1 representing 2 BCE, etc.
495      */

496     private transient int gregorianCutoverYearJulian = 1582;
497
498     /**
499      * gdate always has a sun.util.calendar.Gregorian.Date instance to
500      * avoid overhead of creating it. The assumption is that most
501      * applications will need only Gregorian calendar calculations.
502      */

503     private transient BaseCalendar.Date gdate;
504
505     /**
506      * Reference to either gdate or a JulianCalendar.Date
507      * instance. After calling complete(), this value is guaranteed to
508      * be set.
509      */

510     private transient BaseCalendar.Date cdate;
511
512     /**
513      * The CalendarSystem used to calculate the date in cdate. After
514      * calling complete(), this value is guaranteed to be set and
515      * consistent with the cdate value.
516      */

517     private transient BaseCalendar calsys;
518
519     /**
520      * Temporary int[2] to get time zone offsets. zoneOffsets[0] gets
521      * the GMT offset value and zoneOffsets[1] gets the DST saving
522      * value.
523      */

524     private transient int[] zoneOffsets;
525
526     /**
527      * Temporary storage for saving original fields[] values in
528      * non-lenient mode.
529      */

530     private transient int[] originalFields;
531
532 ///////////////
533
// Constructors
534
///////////////
535

536     /**
537      * Constructs a default <code>GregorianCalendar</code> using the current time
538      * in the default time zone with the default locale.
539      */

540     public GregorianCalendar() {
541         this(TimeZone.getDefaultRef(), Locale.getDefault());
542     setZoneShared(true);
543     }
544
545     /**
546      * Constructs a <code>GregorianCalendar</code> based on the current time
547      * in the given time zone with the default locale.
548      *
549      * @param zone the given time zone.
550      */

551     public GregorianCalendar(TimeZone JavaDoc zone) {
552         this(zone, Locale.getDefault());
553     }
554
555     /**
556      * Constructs a <code>GregorianCalendar</code> based on the current time
557      * in the default time zone with the given locale.
558      *
559      * @param aLocale the given locale.
560      */

561     public GregorianCalendar(Locale JavaDoc aLocale) {
562         this(TimeZone.getDefaultRef(), aLocale);
563     setZoneShared(true);
564     }
565
566     /**
567      * Constructs a <code>GregorianCalendar</code> based on the current time
568      * in the given time zone with the given locale.
569      *
570      * @param zone the given time zone.
571      * @param aLocale the given locale.
572      */

573     public GregorianCalendar(TimeZone JavaDoc zone, Locale JavaDoc aLocale) {
574         super(zone, aLocale);
575     gdate = (BaseCalendar.Date) gcal.newCalendarDate(zone);
576         setTimeInMillis(System.currentTimeMillis());
577     }
578
579     /**
580      * Constructs a <code>GregorianCalendar</code> with the given date set
581      * in the default time zone with the default locale.
582      *
583      * @param year the value used to set the <code>YEAR</code> calendar field in the calendar.
584      * @param month the value used to set the <code>MONTH</code> calendar field in the calendar.
585      * Month value is 0-based. e.g., 0 for January.
586      * @param dayOfMonth the value used to set the <code>DAY_OF_MONTH</code> calendar field in the calendar.
587      */

588     public GregorianCalendar(int year, int month, int dayOfMonth) {
589     this(year, month, dayOfMonth, 0, 0, 0, 0);
590     }
591
592     /**
593      * Constructs a <code>GregorianCalendar</code> with the given date
594      * and time set for the default time zone with the default locale.
595      *
596      * @param year the value used to set the <code>YEAR</code> calendar field in the calendar.
597      * @param month the value used to set the <code>MONTH</code> calendar field in the calendar.
598      * Month value is 0-based. e.g., 0 for January.
599      * @param dayOfMonth the value used to set the <code>DAY_OF_MONTH</code> calendar field in the calendar.
600      * @param hourOfDay the value used to set the <code>HOUR_OF_DAY</code> calendar field
601      * in the calendar.
602      * @param minute the value used to set the <code>MINUTE</code> calendar field
603      * in the calendar.
604      */

605     public GregorianCalendar(int year, int month, int dayOfMonth, int hourOfDay,
606                              int minute) {
607     this(year, month, dayOfMonth, hourOfDay, minute, 0, 0);
608     }
609
610     /**
611      * Constructs a GregorianCalendar with the given date
612      * and time set for the default time zone with the default locale.
613      *
614      * @param year the value used to set the <code>YEAR</code> calendar field in the calendar.
615      * @param month the value used to set the <code>MONTH</code> calendar field in the calendar.
616      * Month value is 0-based. e.g., 0 for January.
617      * @param dayOfMonth the value used to set the <code>DAY_OF_MONTH</code> calendar field in the calendar.
618      * @param hourOfDay the value used to set the <code>HOUR_OF_DAY</code> calendar field
619      * in the calendar.
620      * @param minute the value used to set the <code>MINUTE</code> calendar field
621      * in the calendar.
622      * @param second the value used to set the <code>SECOND</code> calendar field
623      * in the calendar.
624      */

625     public GregorianCalendar(int year, int month, int dayOfMonth, int hourOfDay,
626                              int minute, int second) {
627     this(year, month, dayOfMonth, hourOfDay, minute, second, 0);
628     }
629
630     /**
631      * Constructs a <code>GregorianCalendar</code> with the given date
632      * and time set for the default time zone with the default locale.
633      *
634      * @param year the value used to set the <code>YEAR</code> calendar field in the calendar.
635      * @param month the value used to set the <code>MONTH</code> calendar field in the calendar.
636      * Month value is 0-based. e.g., 0 for January.
637      * @param dayOfMonth the value used to set the <code>DAY_OF_MONTH</code> calendar field in the calendar.
638      * @param hourOfDay the value used to set the <code>HOUR_OF_DAY</code> calendar field
639      * in the calendar.
640      * @param minute the value used to set the <code>MINUTE</code> calendar field
641      * in the calendar.
642      * @param second the value used to set the <code>SECOND</code> calendar field
643      * in the calendar.
644      * @param millis the value used to set the <code>MILLISECOND</code> calendar field
645      */

646     GregorianCalendar(int year, int month, int dayOfMonth,
647               int hourOfDay, int minute, int second, int millis) {
648         super();
649     gdate = (BaseCalendar.Date) gcal.newCalendarDate(getZone());
650         this.set(YEAR, year);
651         this.set(MONTH, month);
652         this.set(DAY_OF_MONTH, dayOfMonth);
653
654     // Set AM_PM and HOUR here to set their stamp values before
655
// setting HOUR_OF_DAY (6178071).
656
if (hourOfDay >= 12 && hourOfDay <= 23) {
657         // If hourOfDay is a valid PM hour, set the correct PM values
658
// so that it won't throw an exception in case it's set to
659
// non-lenient later.
660
this.internalSet(AM_PM, PM);
661         this.internalSet(HOUR, hourOfDay - 12);
662     } else {
663         // The default value for AM_PM is AM.
664
// We don't care any out of range value here for leniency.
665
this.internalSet(HOUR, hourOfDay);
666     }
667     // The stamp values of AM_PM and HOUR must be COMPUTED. (6440854)
668
setFieldsComputed(HOUR_MASK|AM_PM_MASK);
669
670         this.set(HOUR_OF_DAY, hourOfDay);
671         this.set(MINUTE, minute);
672         this.set(SECOND, second);
673     // should be changed to set() when this constructor is made
674
// public.
675
this.internalSet(MILLISECOND, millis);
676     }
677  
678 /////////////////
679
// Public methods
680
/////////////////
681

682     /**
683      * Sets the <code>GregorianCalendar</code> change date. This is the point when the switch
684      * from Julian dates to Gregorian dates occurred. Default is October 15,
685      * 1582 (Gregorian). Previous to this, dates will be in the Julian calendar.
686      * <p>
687      * To obtain a pure Julian calendar, set the change date to
688      * <code>Date(Long.MAX_VALUE)</code>. To obtain a pure Gregorian calendar,
689      * set the change date to <code>Date(Long.MIN_VALUE)</code>.
690      *
691      * @param date the given Gregorian cutover date.
692      */

693     public void setGregorianChange(Date JavaDoc date) {
694     long cutoverTime = date.getTime();
695     if (cutoverTime == gregorianCutover) {
696         return;
697     }
698     // Before changing the cutover date, make sure to have the
699
// time of this calendar.
700
complete();
701     setGregorianChange(cutoverTime);
702     }
703
704     private void setGregorianChange(long cutoverTime) {
705         gregorianCutover = cutoverTime;
706         gregorianCutoverDate = CalendarUtils.floorDivide(cutoverTime, ONE_DAY)
707                 + EPOCH_OFFSET;
708
709     // To provide the "pure" Julian calendar as advertised.
710
// Strictly speaking, the last millisecond should be a
711
// Gregorian date. However, the API doc specifies that setting
712
// the cutover date to Long.MAX_VALUE will make this calendar
713
// a pure Julian calendar. (See 4167995)
714
if (cutoverTime == Long.MAX_VALUE) {
715         gregorianCutoverDate++;
716     }
717
718     BaseCalendar.Date d = getGregorianCutoverDate();
719
720     // Set the cutover year (in the Gregorian year numbering)
721
gregorianCutoverYear = d.getYear();
722
723     BaseCalendar jcal = getJulianCalendarSystem();
724     d = (BaseCalendar.Date) jcal.newCalendarDate(TimeZone.NO_TIMEZONE);
725     jcal.getCalendarDateFromFixedDate(d, gregorianCutoverDate - 1);
726     gregorianCutoverYearJulian = d.getNormalizedYear();
727
728     if (time < gregorianCutover) {
729         // The field values are no longer valid under the new
730
// cutover date.
731
setUnnormalized();
732     }
733     }
734
735     /**
736      * Gets the Gregorian Calendar change date. This is the point when the
737      * switch from Julian dates to Gregorian dates occurred. Default is
738      * October 15, 1582 (Gregorian). Previous to this, dates will be in the Julian
739      * calendar.
740      *
741      * @return the Gregorian cutover date for this <code>GregorianCalendar</code> object.
742      */

743     public final Date JavaDoc getGregorianChange() {
744         return new Date JavaDoc(gregorianCutover);
745     }
746
747     /**
748      * Determines if the given year is a leap year. Returns <code>true</code> if
749      * the given year is a leap year. To specify BC year numbers,
750      * <code>1 - year number</code> must be given. For example, year BC 4 is
751      * specified as -3.
752      *
753      * @param year the given year.
754      * @return <code>true</code> if the given year is a leap year; <code>false</code> otherwise.
755      */

756     public boolean isLeapYear(int year) {
757     if ((year & 3) != 0) {
758         return false;
759     }
760
761         if (year > gregorianCutoverYear) {
762             return (year%100 != 0) || (year%400 == 0); // Gregorian
763
}
764     if (year < gregorianCutoverYearJulian) {
765             return true; // Julian
766
}
767     boolean gregorian;
768     // If the given year is the Gregorian cutover year, we need to
769
// determine which calendar system to be applied to February in the year.
770
if (gregorianCutoverYear == gregorianCutoverYearJulian) {
771         BaseCalendar.Date d = getCalendarDate(gregorianCutoverDate); // Gregorian
772
gregorian = d.getMonth() < BaseCalendar.MARCH;
773     } else {
774         gregorian = year == gregorianCutoverYear;
775     }
776     return gregorian ? (year%100 != 0) || (year%400 == 0) : true;
777     }
778
779     /**
780      * Compares this <code>GregorianCalendar</code> to the specified
781      * <code>Object</code>. The result is <code>true</code> if and
782      * only if the argument is a <code>GregorianCalendar</code> object
783      * that represents the same time value (millisecond offset from
784      * the <a HREF="Calendar.html#Epoch">Epoch</a>) under the same
785      * <code>Calendar</code> parameters and Gregorian change date as
786      * this object.
787      *
788      * @param obj the object to compare with.
789      * @return <code>true</code> if this object is equal to <code>obj</code>;
790      * <code>false</code> otherwise.
791      * @see Calendar#compareTo(Calendar)
792      */

793     public boolean equals(Object JavaDoc obj) {
794         return obj instanceof GregorianCalendar JavaDoc &&
795         super.equals(obj) &&
796             gregorianCutover == ((GregorianCalendar JavaDoc)obj).gregorianCutover;
797     }
798     
799     /**
800      * Generates the hash code for this <code>GregorianCalendar</code> object.
801      */

802     public int hashCode() {
803         return super.hashCode() ^ (int)gregorianCutoverDate;
804     }
805
806     /**
807      * Adds the specified (signed) amount of time to the given calendar field,
808      * based on the calendar's rules.
809      *
810      * <p><em>Add rule 1</em>. The value of <code>field</code>
811      * after the call minus the value of <code>field</code> before the
812      * call is <code>amount</code>, modulo any overflow that has occurred in
813      * <code>field</code>. Overflow occurs when a field value exceeds its
814      * range and, as a result, the next larger field is incremented or
815      * decremented and the field value is adjusted back into its range.</p>
816      *
817      * <p><em>Add rule 2</em>. If a smaller field is expected to be
818      * invariant, but it is impossible for it to be equal to its
819      * prior value because of changes in its minimum or maximum after
820      * <code>field</code> is changed, then its value is adjusted to be as close
821      * as possible to its expected value. A smaller field represents a
822      * smaller unit of time. <code>HOUR</code> is a smaller field than
823      * <code>DAY_OF_MONTH</code>. No adjustment is made to smaller fields
824      * that are not expected to be invariant. The calendar system
825      * determines what fields are expected to be invariant.</p>
826      *
827      * @param field the calendar field.
828      * @param amount the amount of date or time to be added to the field.
829      * @exception IllegalArgumentException if <code>field</code> is
830      * <code>ZONE_OFFSET</code>, <code>DST_OFFSET</code>, or unknown,
831      * or if any calendar fields have out-of-range values in
832      * non-lenient mode.
833      */

834     public void add(int field, int amount) {
835     // If amount == 0, do nothing even the given field is out of
836
// range. This is tested by JCK.
837
if (amount == 0) {
838         return; // Do nothing!
839
}
840
841     if (field < 0 || field >= ZONE_OFFSET) {
842         throw new IllegalArgumentException JavaDoc();
843     }
844
845     // Sync the time and calendar fields.
846
complete();
847
848         if (field == YEAR) {
849             int year = internalGet(YEAR);
850             if (internalGetEra() == CE) {
851                 year += amount;
852                 if (year > 0) {
853                     set(YEAR, year);
854                 } else { // year <= 0
855
set(YEAR, 1 - year);
856                     // if year == 0, you get 1 BCE.
857
set(ERA, BCE);
858                 }
859             }
860             else { // era == BCE
861
year -= amount;
862                 if (year > 0) {
863                     set(YEAR, year);
864                 } else { // year <= 0
865
set(YEAR, 1 - year);
866                     // if year == 0, you get 1 CE
867
set(ERA, CE);
868                 }
869             }
870             pinDayOfMonth();
871         } else if (field == MONTH) {
872             int month = internalGet(MONTH) + amount;
873         int year = internalGet(YEAR);
874         int y_amount;
875
876         if (month >= 0) {
877                 y_amount = month/12;
878         } else {
879                 y_amount = (month+1)/12 - 1;
880         }
881         if (y_amount != 0) {
882                 if (internalGetEra() == CE) {
883                     year += y_amount;
884                     if (year > 0) {
885                         set(YEAR, year);
886                     } else { // year <= 0
887
set(YEAR, 1 - year);
888                         // if year == 0, you get 1 BCE
889
set(ERA, BCE);
890                     }
891                 }
892                 else { // era == BCE
893
year -= y_amount;
894                     if (year > 0) {
895                         set(YEAR, year);
896                     } else { // year <= 0
897
set(YEAR, 1 - year);
898                         // if year == 0, you get 1 CE
899
set(ERA, CE);
900                     }
901                 }
902             }
903
904             if (month >= 0) {
905                 set(MONTH, (int) (month % 12));
906             } else {
907         // month < 0
908
month %= 12;
909                 if (month < 0) {
910             month += 12;
911         }
912                 set(MONTH, JANUARY + month);
913             }
914             pinDayOfMonth();
915         } else if (field == ERA) {
916             int era = internalGet(ERA) + amount;
917             if (era < 0) {
918         era = 0;
919         }
920             if (era > 1) {
921         era = 1;
922         }
923             set(ERA, era);
924         } else {
925         long delta = amount;
926         long timeOfDay = 0;
927         switch (field) {
928         // Handle the time fields here. Convert the given
929
// amount to milliseconds and call setTimeInMillis.
930
case HOUR:
931             case HOUR_OF_DAY:
932                 delta *= 60 * 60 * 1000; // hours to minutes
933
break;
934
935             case MINUTE:
936                 delta *= 60 * 1000; // minutes to seconds
937
break;
938
939             case SECOND:
940                 delta *= 1000; // seconds to milliseconds
941
break;
942
943             case MILLISECOND:
944                 break;
945
946         // Handle week, day and AM_PM fields which involves
947
// time zone offset change adjustment. Convert the
948
// given amount to the number of days.
949
case WEEK_OF_YEAR:
950             case WEEK_OF_MONTH:
951             case DAY_OF_WEEK_IN_MONTH:
952                 delta *= 7;
953         break;
954
955             case DAY_OF_MONTH: // synonym of DATE
956
case DAY_OF_YEAR:
957             case DAY_OF_WEEK:
958         break;
959
960         case AM_PM:
961         // Convert the amount to the number of days (delta)
962
// and +12 or -12 hours (timeOfDay).
963
delta = amount / 2;
964         timeOfDay = 12 * (amount % 2);
965         break;
966         }
967
968         // The time fields don't require time zone offset change
969
// adjustment.
970
if (field >= HOUR) {
971         setTimeInMillis(time + delta);
972         return;
973         }
974
975         // The rest of the fields (week, day or AM_PM fields)
976
// require time zone offset (both GMT and DST) change
977
// adjustment.
978

979         // Translate the current time to the fixed date and time
980
// of the day.
981
long fd = getCurrentFixedDate();
982         timeOfDay += internalGet(HOUR_OF_DAY);
983         timeOfDay *= 60;
984         timeOfDay += internalGet(MINUTE);
985         timeOfDay *= 60;
986         timeOfDay += internalGet(SECOND);
987         timeOfDay *= 1000;
988         timeOfDay += internalGet(MILLISECOND);
989         if (timeOfDay >= ONE_DAY) {
990         fd++;
991         timeOfDay -= ONE_DAY;
992         } else if (timeOfDay < 0) {
993         fd--;
994         timeOfDay += ONE_DAY;
995         }
996
997         fd += delta; // fd is the expected fixed date after the calculation
998
int zoneOffset = internalGet(ZONE_OFFSET) + internalGet(DST_OFFSET);
999         setTimeInMillis((fd - EPOCH_OFFSET) * ONE_DAY + timeOfDay - zoneOffset);
1000        zoneOffset -= internalGet(ZONE_OFFSET) + internalGet(DST_OFFSET);
1001        // If the time zone offset has changed, then adjust the difference.
1002
if (zoneOffset != 0) {
1003        setTimeInMillis(time + zoneOffset);
1004        long fd2 = getCurrentFixedDate();
1005        // If the adjustment has changed the date, then take
1006
// the previous one.
1007
if (fd2 != fd) {
1008            setTimeInMillis(time - zoneOffset);
1009        }
1010        }
1011    }
1012    }
1013
1014    /**
1015     * Adds or subtracts (up/down) a single unit of time on the given time
1016     * field without changing larger fields.
1017     * <p>
1018     * <em>Example</em>: Consider a <code>GregorianCalendar</code>
1019     * originally set to December 31, 1999. Calling {@link #roll(int,boolean) roll(Calendar.MONTH, true)}
1020     * sets the calendar to January 31, 1999. The <code>YEAR</code> field is unchanged
1021     * because it is a larger field than <code>MONTH</code>.</p>
1022     *
1023     * @param up indicates if the value of the specified calendar field is to be
1024     * rolled up or rolled down. Use <code>true</code> if rolling up, <code>false</code> otherwise.
1025     * @exception IllegalArgumentException if <code>field</code> is
1026     * <code>ZONE_OFFSET</code>, <code>DST_OFFSET</code>, or unknown,
1027     * or if any calendar fields have out-of-range values in
1028     * non-lenient mode.
1029     * @see #add(int,int)
1030     * @see #set(int,int)
1031     */

1032    public void roll(int field, boolean up) {
1033        roll(field, up ? +1 : -1);
1034    }
1035
1036    /**
1037     * Adds a signed amount to the specified calendar field without changing larger fields.
1038     * A negative roll amount means to subtract from field without changing
1039     * larger fields. If the specified amount is 0, this method performs nothing.
1040     *
1041     * <p>This method calls {@link #complete()} before adding the
1042     * amount so that all the calendar fields are normalized. If there
1043     * is any calendar field having an out-of-range value in non-lenient mode, then an
1044     * <code>IllegalArgumentException</code> is thrown.
1045     *
1046     * <p>
1047     * <em>Example</em>: Consider a <code>GregorianCalendar</code>
1048     * originally set to August 31, 1999. Calling <code>roll(Calendar.MONTH,
1049     * 8)</code> sets the calendar to April 30, <strong>1999</strong>. Using a
1050     * <code>GregorianCalendar</code>, the <code>DAY_OF_MONTH</code> field cannot
1051     * be 31 in the month April. <code>DAY_OF_MONTH</code> is set to the closest possible
1052     * value, 30. The <code>YEAR</code> field maintains the value of 1999 because it
1053     * is a larger field than <code>MONTH</code>.
1054     * <p>
1055     * <em>Example</em>: Consider a <code>GregorianCalendar</code>
1056     * originally set to Sunday June 6, 1999. Calling
1057     * <code>roll(Calendar.WEEK_OF_MONTH, -1)</code> sets the calendar to
1058     * Tuesday June 1, 1999, whereas calling
1059     * <code>add(Calendar.WEEK_OF_MONTH, -1)</code> sets the calendar to
1060     * Sunday May 30, 1999. This is because the roll rule imposes an
1061     * additional constraint: The <code>MONTH</code> must not change when the
1062     * <code>WEEK_OF_MONTH</code> is rolled. Taken together with add rule 1,
1063     * the resultant date must be between Tuesday June 1 and Saturday June
1064     * 5. According to add rule 2, the <code>DAY_OF_WEEK</code>, an invariant
1065     * when changing the <code>WEEK_OF_MONTH</code>, is set to Tuesday, the
1066     * closest possible value to Sunday (where Sunday is the first day of the
1067     * week).</p>
1068     *
1069     * @param field the calendar field.
1070     * @param amount the signed amount to add to <code>field</code>.
1071     * @exception IllegalArgumentException if <code>field</code> is
1072     * <code>ZONE_OFFSET</code>, <code>DST_OFFSET</code>, or unknown,
1073     * or if any calendar fields have out-of-range values in
1074     * non-lenient mode.
1075     * @see #roll(int,boolean)
1076     * @see #add(int,int)
1077     * @see #set(int,int)
1078     * @since 1.2
1079     */

1080    public void roll(int field, int amount) {
1081    // If amount == 0, do nothing even the given field is out of
1082
// range. This is tested by JCK.
1083
if (amount == 0) {
1084        return;
1085    }
1086
1087    if (field < 0 || field >= ZONE_OFFSET) {
1088        throw new IllegalArgumentException JavaDoc();
1089    }
1090
1091    // Sync the time and calendar fields.
1092
complete();
1093
1094    int min = getMinimum(field);
1095    int max = getMaximum(field);
1096
1097        switch (field) {
1098        case AM_PM:
1099        case ERA:
1100        case YEAR:
1101        case MINUTE:
1102        case SECOND:
1103        case MILLISECOND:
1104            // These fields are handled simply, since they have fixed minima
1105
// and maxima. The field DAY_OF_MONTH is almost as simple. Other
1106
// fields are complicated, since the range within they must roll
1107
// varies depending on the date.
1108
break;
1109
1110        case HOUR:
1111        case HOUR_OF_DAY:
1112        {
1113        int unit = max + 1; // 12 or 24 hours
1114
int h = internalGet(field);
1115        int nh = (h + amount) % unit;
1116        if (nh < 0) {
1117            nh += unit;
1118        }
1119        time += ONE_HOUR * (nh - h);
1120
1121        // The day might have changed, which could happen if
1122
// the daylight saving time transition brings it to
1123
// the next day, although it's very unlikely. But we
1124
// have to make sure not to change the larger fields.
1125
CalendarDate d = calsys.getCalendarDate(time, getZone());
1126        if (internalGet(DAY_OF_MONTH) != d.getDayOfMonth()) {
1127            d.setDate(internalGet(YEAR),
1128                  internalGet(MONTH) + 1,
1129                  internalGet(DAY_OF_MONTH));
1130            if (field == HOUR) {
1131            assert (internalGet(AM_PM) == PM);
1132            d.addHours(+12); // restore PM
1133
}
1134            time = calsys.getTime(d);
1135        }
1136        int hourOfDay = d.getHours();
1137        internalSet(field, hourOfDay % unit);
1138        if (field == HOUR) {
1139            internalSet(HOUR_OF_DAY, hourOfDay);
1140        } else {
1141            internalSet(AM_PM, hourOfDay / 12);
1142            internalSet(HOUR, hourOfDay % 12);
1143        }
1144
1145        // Time zone offset and/or daylight saving might have changed.
1146
int zoneOffset = d.getZoneOffset();
1147        int saving = d.getDaylightSaving();
1148        internalSet(ZONE_OFFSET, zoneOffset - saving);
1149        internalSet(DST_OFFSET, saving);
1150        return;
1151        }
1152
1153        case MONTH:
1154            // Rolling the month involves both pinning the final value to [0, 11]
1155
// and adjusting the DAY_OF_MONTH if necessary. We only adjust the
1156
// DAY_OF_MONTH if, after updating the MONTH field, it is illegal.
1157
// E.g., <jan31>.roll(MONTH, 1) -> <feb28> or <feb29>.
1158
{
1159        if (!isCutoverYear(cdate.getNormalizedYear())) {
1160            int mon = (internalGet(MONTH) + amount) % 12;
1161            if (mon < 0) {
1162            mon += 12;
1163            }
1164            set(MONTH, mon);
1165                
1166            // Keep the day of month in the range. We don't want to spill over
1167
// into the next month; e.g., we don't want jan31 + 1 mo -> feb31 ->
1168
// mar3.
1169
int monthLen = monthLength(mon);
1170            if (internalGet(DAY_OF_MONTH) > monthLen) {
1171            set(DAY_OF_MONTH, monthLen);
1172            }
1173        } else {
1174            // We need to take care of different lengths in
1175
// year and month due to the cutover.
1176
int yearLength = getActualMaximum(MONTH) + 1;
1177            int mon = (internalGet(MONTH) + amount) % yearLength;
1178            if (mon < 0) {
1179            mon += yearLength;
1180            }
1181            set(MONTH, mon);
1182            int monthLen = getActualMaximum(DAY_OF_MONTH);
1183            if (internalGet(DAY_OF_MONTH) > monthLen) {
1184            set(DAY_OF_MONTH, monthLen);
1185            }
1186        }
1187        return;
1188            }
1189
1190        case WEEK_OF_YEAR:
1191        {
1192        int y = cdate.getNormalizedYear();
1193        max = getActualMaximum(WEEK_OF_YEAR);
1194        set(DAY_OF_WEEK, internalGet(DAY_OF_WEEK));
1195        int woy = internalGet(WEEK_OF_YEAR);
1196        int value = woy + amount;
1197        if (!isCutoverYear(y)) {
1198            // If the new value is in between min and max
1199
// (exclusive), then we can use the value.
1200
if (value > min && value < max) {
1201            set(WEEK_OF_YEAR, value);
1202            return;
1203            }
1204            long fd = getCurrentFixedDate();
1205            // Make sure that the min week has the current DAY_OF_WEEK
1206
long day1 = fd - (7 * (woy - min));
1207            if (calsys.getYearFromFixedDate(day1) != y) {
1208            min++;
1209            }
1210
1211            // Make sure the same thing for the max week
1212
fd += 7 * (max - internalGet(WEEK_OF_YEAR));
1213            if (calsys.getYearFromFixedDate(fd) != y) {
1214            max--;
1215            }
1216            break;
1217        }
1218
1219        // Handle cutover here.
1220
long fd = getCurrentFixedDate();
1221        BaseCalendar cal;
1222        if (gregorianCutoverYear == gregorianCutoverYearJulian) {
1223            cal = getCutoverCalendarSystem();
1224        } else if (y == gregorianCutoverYear) {
1225            cal = gcal;
1226        } else {
1227            cal = getJulianCalendarSystem();
1228        }
1229        long day1 = fd - (7 * (woy - min));
1230        // Make sure that the min week has the current DAY_OF_WEEK
1231
if (cal.getYearFromFixedDate(day1) != y) {
1232            min++;
1233        }
1234
1235        // Make sure the same thing for the max week
1236
fd += 7 * (max - woy);
1237        cal = (fd >= gregorianCutoverDate) ? gcal : getJulianCalendarSystem();
1238        if (cal.getYearFromFixedDate(fd) != y) {
1239            max--;
1240        }
1241        // value: the new WEEK_OF_YEAR which must be converted
1242
// to month and day of month.
1243
value = getRolledValue(woy, amount, min, max) - 1;
1244        BaseCalendar.Date d = getCalendarDate(day1 + value * 7);
1245        set(MONTH, d.getMonth() - 1);
1246        set(DAY_OF_MONTH, d.getDayOfMonth());
1247        return;
1248        }
1249
1250        case WEEK_OF_MONTH:
1251        {
1252        boolean isCutoverYear = isCutoverYear(cdate.getNormalizedYear());
1253        // dow: relative day of week from first day of week
1254
int dow = internalGet(DAY_OF_WEEK) - getFirstDayOfWeek();
1255        if (dow < 0) {
1256            dow += 7;
1257        }
1258
1259        long fd = getCurrentFixedDate();
1260        long month1; // fixed date of the first day (usually 1) of the month
1261
int monthLength; // actual month length
1262
if (isCutoverYear) {
1263            month1 = getFixedDateMonth1(cdate, fd);
1264            monthLength = actualMonthLength();
1265        } else {
1266            month1 = fd - internalGet(DAY_OF_MONTH) + 1;
1267            monthLength = calsys.getMonthLength(cdate);
1268        }
1269
1270        // the first day of week of the month.
1271
long monthDay1st = calsys.getDayOfWeekDateOnOrBefore(month1 + 6,
1272                                     getFirstDayOfWeek());
1273        // if the week has enough days to form a week, the
1274
// week starts from the previous month.
1275
if ((int)(monthDay1st - month1) >= getMinimalDaysInFirstWeek()) {
1276            monthDay1st -= 7;
1277        }
1278        max = getActualMaximum(field);
1279
1280        // value: the new WEEK_OF_MONTH value
1281
int value = getRolledValue(internalGet(field), amount, 1, max) - 1;
1282
1283        // nfd: fixed date of the rolled date
1284
long nfd = monthDay1st + value * 7 + dow;
1285
1286        // Unlike WEEK_OF_YEAR, we need to change day of week if the
1287
// nfd is out of the month.
1288
if (nfd < month1) {
1289            nfd = month1;
1290        } else if (nfd >= (month1 + monthLength)) {
1291            nfd = month1 + monthLength - 1;
1292        }
1293        int dayOfMonth;
1294        if (isCutoverYear) {
1295            // If we are in the cutover year, convert nfd to
1296
// its calendar date and use dayOfMonth.
1297
BaseCalendar.Date d = getCalendarDate(nfd);
1298            dayOfMonth = d.getDayOfMonth();
1299        } else {
1300            dayOfMonth = (int)(nfd - month1) + 1;
1301        }
1302        set(DAY_OF_MONTH, dayOfMonth);
1303        return;
1304        }
1305
1306        case DAY_OF_MONTH:
1307        {
1308        if (!isCutoverYear(cdate.getNormalizedYear())) {
1309            max = calsys.getMonthLength(cdate);
1310            break;
1311        }
1312
1313        // Cutover year handling
1314
long fd = getCurrentFixedDate();
1315        long month1 = getFixedDateMonth1(cdate, fd);
1316        // It may not be a regular month. Convert the date and range to
1317
// the relative values, perform the roll, and
1318
// convert the result back to the rolled date.
1319
int value = getRolledValue((int)(fd - month1), amount, 0, actualMonthLength() - 1);
1320        BaseCalendar.Date d = getCalendarDate(month1 + value);
1321        assert d.getMonth()-1 == internalGet(MONTH);
1322        set(DAY_OF_MONTH, d.getDayOfMonth());
1323        return;
1324        }
1325
1326        case DAY_OF_YEAR:
1327        {
1328        max = getActualMaximum(field);
1329        if (!isCutoverYear(cdate.getNormalizedYear())) {
1330            break;
1331        }
1332
1333        // Handle cutover here.
1334
long fd = getCurrentFixedDate();
1335        long jan1 = fd - internalGet(DAY_OF_YEAR) + 1;
1336        int value = getRolledValue((int)(fd - jan1) + 1, amount, min, max);
1337        BaseCalendar.Date d = getCalendarDate(jan1 + value - 1);
1338        set(MONTH, d.getMonth() - 1);
1339        set(DAY_OF_MONTH, d.getDayOfMonth());
1340        return;
1341        }
1342
1343        case DAY_OF_WEEK:
1344        {
1345        if (!isCutoverYear(cdate.getNormalizedYear())) {
1346            // If the week of year is in the same year, we can
1347
// just change DAY_OF_WEEK.
1348
int weekOfYear = internalGet(WEEK_OF_YEAR);
1349            if (weekOfYear > 1 && weekOfYear < 52) {
1350            set(WEEK_OF_YEAR, weekOfYear); // update stamp[WEEK_OF_YEAR]
1351
max = SATURDAY;
1352            break;
1353            }
1354        }
1355
1356        // We need to handle it in a different way around year
1357
// boundaries and in the cutover year. Note that
1358
// changing era and year values violates the roll
1359
// rule: not changing larger calendar fields...
1360
amount %= 7;
1361        if (amount == 0) {
1362            return;
1363        }
1364        long fd = getCurrentFixedDate();
1365        long dowFirst = calsys.getDayOfWeekDateOnOrBefore(fd, getFirstDayOfWeek());
1366        fd += amount;
1367        if (fd < dowFirst) {
1368            fd += 7;
1369        } else if (fd >= dowFirst + 7) {
1370            fd -= 7;
1371        }
1372        BaseCalendar.Date d = getCalendarDate(fd);
1373        set(ERA, (d.getNormalizedYear() <= 0 ? BCE : CE));
1374        set(d.getYear(), d.getMonth() - 1, d.getDayOfMonth());
1375        return;
1376        }
1377
1378        case DAY_OF_WEEK_IN_MONTH:
1379            {
1380        min = 1; // after normalized, min should be 1.
1381
if (!isCutoverYear(cdate.getNormalizedYear())) {
1382            int dom = internalGet(DAY_OF_MONTH);
1383            int monthLength = calsys.getMonthLength(cdate);
1384            int lastDays = monthLength % 7;
1385            max = monthLength / 7;
1386            int x = (dom - 1) % 7;
1387            if (x < lastDays) {
1388            max++;
1389            }
1390            set(DAY_OF_WEEK, internalGet(DAY_OF_WEEK));
1391            break;
1392        }
1393
1394        // Cutover year handling
1395
long fd = getCurrentFixedDate();
1396        long month1 = getFixedDateMonth1(cdate, fd);
1397        int monthLength = actualMonthLength();
1398        int lastDays = monthLength % 7;
1399        max = monthLength / 7;
1400        int x = (int)(fd - month1) % 7;
1401        if (x < lastDays) {
1402            max++;
1403        }
1404        int value = getRolledValue(internalGet(field), amount, min, max) - 1;
1405        fd = month1 + value * 7 + x;
1406        BaseCalendar cal = (fd >= gregorianCutoverDate) ? gcal : getJulianCalendarSystem();
1407        BaseCalendar.Date d = (BaseCalendar.Date) cal.newCalendarDate(TimeZone.NO_TIMEZONE);
1408        cal.getCalendarDateFromFixedDate(d, fd);
1409        set(DAY_OF_MONTH, d.getDayOfMonth());
1410        return;
1411            }
1412    }
1413
1414    set(field, getRolledValue(internalGet(field), amount, min, max));
1415    }
1416
1417    /**
1418     * Returns the minimum value for the given calendar field of this
1419     * <code>GregorianCalendar</code> instance. The minimum value is
1420     * defined as the smallest value returned by the {@link
1421     * Calendar#get(int) get} method for any possible time value,
1422     * taking into consideration the current values of the
1423     * {@link Calendar#getFirstDayOfWeek() getFirstDayOfWeek},
1424     * {@link Calendar#getMinimalDaysInFirstWeek() getMinimalDaysInFirstWeek},
1425     * {@link #getGregorianChange(Date) getGregorianChange} and
1426     * {@link Calendar#getTimeZone() getTimeZone} methods.
1427     *
1428     * @param field the calendar field.
1429     * @return the minimum value for the given calendar field.
1430     * @see #getMaximum(int)
1431     * @see #getGreatestMinimum(int)
1432     * @see #getLeastMaximum(int)
1433     * @see #getActualMinimum(int)
1434     * @see #getActualMaximum(int)
1435     */

1436    public int getMinimum(int field) {
1437        return MIN_VALUES[field];
1438    }
1439
1440    /**
1441     * Returns the maximum value for the given calendar field of this
1442     * <code>GregorianCalendar</code> instance. The maximum value is
1443     * defined as the largest value returned by the {@link
1444     * Calendar#get(int) get} method for any possible time value,
1445     * taking into consideration the current values of the
1446     * {@link Calendar#getFirstDayOfWeek() getFirstDayOfWeek},
1447     * {@link Calendar#getMinimalDaysInFirstWeek() getMinimalDaysInFirstWeek},
1448     * {@link #getGregorianChange(Date) getGregorianChange} and
1449     * {@link Calendar#getTimeZone() getTimeZone} methods.
1450     *
1451     * @param field the calendar field.
1452     * @return the maximum value for the given calendar field.
1453     * @see #getMinimum(int)
1454     * @see #getGreatestMinimum(int)
1455     * @see #getLeastMaximum(int)
1456     * @see #getActualMinimum(int)
1457     * @see #getActualMaximum(int)
1458     */

1459    public int getMaximum(int field) {
1460    switch (field) {
1461    case MONTH:
1462        case DAY_OF_MONTH:
1463        case DAY_OF_YEAR:
1464        case WEEK_OF_YEAR:
1465        case WEEK_OF_MONTH:
1466        case DAY_OF_WEEK_IN_MONTH:
1467    case YEAR:
1468        {
1469        // On or after Gregorian 200-3-1, Julian and Gregorian
1470
// calendar dates are the same or Gregorian dates are
1471
// larger (i.e., there is a "gap") after 300-3-1.
1472
if (gregorianCutoverYear > 200) {
1473            break;
1474        }
1475        // There might be "overlapping" dates.
1476
GregorianCalendar JavaDoc gc = (GregorianCalendar JavaDoc) clone();
1477        gc.setLenient(true);
1478        gc.setTimeInMillis(gregorianCutover);
1479        int v1 = gc.getActualMaximum(field);
1480        gc.setTimeInMillis(gregorianCutover-1);
1481        int v2 = gc.getActualMaximum(field);
1482        return Math.max(MAX_VALUES[field], Math.max(v1, v2));
1483        }
1484    }
1485        return MAX_VALUES[field];
1486    }
1487
1488    /**
1489     * Returns the highest minimum value for the given calendar field
1490     * of this <code>GregorianCalendar</code> instance. The highest
1491     * minimum value is defined as the largest value returned by
1492     * {@link #getActualMinimum(int)} for any possible time value,
1493     * taking into consideration the current values of the
1494     * {@link Calendar#getFirstDayOfWeek() getFirstDayOfWeek},
1495     * {@link Calendar#getMinimalDaysInFirstWeek() getMinimalDaysInFirstWeek},
1496     * {@link #getGregorianChange(Date) getGregorianChange} and
1497     * {@link Calendar#getTimeZone() getTimeZone} methods.
1498     *
1499     * @param field the calendar field.
1500     * @return the highest minimum value for the given calendar field.
1501     * @see #getMinimum(int)
1502     * @see #getMaximum(int)
1503     * @see #getLeastMaximum(int)
1504     * @see #getActualMinimum(int)
1505     * @see #getActualMaximum(int)
1506     */

1507    public int getGreatestMinimum(int field) {
1508    if (field == DAY_OF_MONTH) {
1509        BaseCalendar.Date d = getGregorianCutoverDate();
1510        long mon1 = getFixedDateMonth1(d, gregorianCutoverDate);
1511        d = getCalendarDate(mon1);
1512        return Math.max(MIN_VALUES[field], d.getDayOfMonth());
1513    }
1514        return MIN_VALUES[field];
1515    }
1516
1517    /**
1518     * Returns the lowest maximum value for the given calendar field
1519     * of this <code>GregorianCalendar</code> instance. The lowest
1520     * maximum value is defined as the smallest value returned by
1521     * {@link #getActualMaximum(int)} for any possible time value,
1522     * taking into consideration the current values of the
1523     * {@link Calendar#getFirstDayOfWeek() getFirstDayOfWeek},
1524     * {@link Calendar#getMinimalDaysInFirstWeek() getMinimalDaysInFirstWeek},
1525     * {@link #getGregorianChange(Date) getGregorianChange} and
1526     * {@link Calendar#getTimeZone() getTimeZone} methods.
1527     *
1528     * @param field the calendar field
1529     * @return the lowest maximum value for the given calendar field.
1530     * @see #getMinimum(int)
1531     * @see #getMaximum(int)
1532     * @see #getGreatestMinimum(int)
1533     * @see #getActualMinimum(int)
1534     * @see #getActualMaximum(int)
1535     */

1536    public int getLeastMaximum(int field) {
1537    switch (field) {
1538    case MONTH:
1539        case DAY_OF_MONTH:
1540        case DAY_OF_YEAR:
1541        case WEEK_OF_YEAR:
1542        case WEEK_OF_MONTH:
1543        case DAY_OF_WEEK_IN_MONTH:
1544    case YEAR:
1545        {
1546        GregorianCalendar JavaDoc gc = (GregorianCalendar JavaDoc) clone();
1547        gc.setLenient(true);
1548        gc.setTimeInMillis(gregorianCutover);
1549        int v1 = gc.getActualMaximum(field);
1550        gc.setTimeInMillis(gregorianCutover-1);
1551        int v2 = gc.getActualMaximum(field);
1552        return Math.min(LEAST_MAX_VALUES[field], Math.min(v1, v2));
1553        }
1554    }
1555        return LEAST_MAX_VALUES[field];
1556    }
1557
1558    /**
1559     * Returns the minimum value that this calendar field could have,
1560     * taking into consideration the given time value and the current
1561     * values of the
1562     * {@link Calendar#getFirstDayOfWeek() getFirstDayOfWeek},
1563     * {@link Calendar#getMinimalDaysInFirstWeek() getMinimalDaysInFirstWeek},
1564     * {@link #getGregorianChange(Date) getGregorianChange} and
1565     * {@link Calendar#getTimeZone() getTimeZone} methods.
1566     *
1567     * <p>For example, if the Gregorian change date is January 10,
1568     * 1970 and the date of this <code>GregorianCalendar</code> is
1569     * January 20, 1970, the actual minimum value of the
1570     * <code>DAY_OF_MONTH</code> field is 10 because the previous date
1571     * of January 10, 1970 is December 27, 1996 (in the Julian
1572     * calendar). Therefore, December 28, 1969 to January 9, 1970
1573     * don't exist.
1574     *
1575     * @param field the calendar field
1576     * @return the minimum of the given field for the time value of
1577     * this <code>GregorianCalendar</code>
1578     * @see #getMinimum(int)
1579     * @see #getMaximum(int)
1580     * @see #getGreatestMinimum(int)
1581     * @see #getLeastMaximum(int)
1582     * @see #getActualMaximum(int)
1583     * @since 1.2
1584     */

1585    public int getActualMinimum(int field) {
1586    if (field == DAY_OF_MONTH) {
1587        GregorianCalendar JavaDoc gc = getNormalizedCalendar();
1588        int year = gc.cdate.getNormalizedYear();
1589        if (year == gregorianCutoverYear || year == gregorianCutoverYearJulian) {
1590        long month1 = getFixedDateMonth1(gc.cdate, gc.calsys.getFixedDate(gc.cdate));
1591        BaseCalendar.Date d = getCalendarDate(month1);
1592        return d.getDayOfMonth();
1593        }
1594    }
1595        return getMinimum(field);
1596    }
1597
1598    /**
1599     * Returns the maximum value that this calendar field could have,
1600     * taking into consideration the given time value and the current
1601     * values of the
1602     * {@link Calendar#getFirstDayOfWeek() getFirstDayOfWeek},
1603     * {@link Calendar#getMinimalDaysInFirstWeek() getMinimalDaysInFirstWeek},
1604     * {@link #getGregorianChange(Date) getGregorianChange} and
1605     * {@link Calendar#getTimeZone() getTimeZone} methods.
1606     * For example, if the date of this instance is February 1, 2004,
1607     * the actual maximum value of the <code>DAY_OF_MONTH</code> field
1608     * is 29 because 2004 is a leap year, and if the date of this
1609     * instance is February 1, 2005, it's 28.
1610     *
1611     * @param field the calendar field
1612     * @return the maximum of the given field for the time value of
1613     * this <code>GregorianCalendar</code>
1614     * @see #getMinimum(int)
1615     * @see #getMaximum(int)
1616     * @see #getGreatestMinimum(int)
1617     * @see #getLeastMaximum(int)
1618     * @see #getActualMinimum(int)
1619     * @since 1.2
1620     */

1621    public int getActualMaximum(int field) {
1622    final int fieldsForFixedMax = ERA_MASK|DAY_OF_WEEK_MASK|HOUR_MASK|AM_PM_MASK|
1623        HOUR_OF_DAY_MASK|MINUTE_MASK|SECOND_MASK|MILLISECOND_MASK|
1624        ZONE_OFFSET_MASK|DST_OFFSET_MASK;
1625    if ((fieldsForFixedMax & (1<<field)) != 0) {
1626        return getMaximum(field);
1627    }
1628
1629    GregorianCalendar JavaDoc gc = getNormalizedCalendar();
1630    BaseCalendar.Date date = gc.cdate;
1631    BaseCalendar cal = gc.calsys;
1632    int normalizedYear = date.getNormalizedYear();
1633
1634    int value = -1;
1635        switch (field) {
1636    case MONTH:
1637        {
1638        if (!gc.isCutoverYear(normalizedYear)) {
1639            value = DECEMBER;
1640            break;
1641        }
1642
1643        // January 1 of the next year may or may not exist.
1644
long nextJan1;
1645        do {
1646            nextJan1 = gcal.getFixedDate(++normalizedYear, BaseCalendar.JANUARY, 1, null);
1647        } while (nextJan1 < gregorianCutoverDate);
1648        BaseCalendar.Date d = (BaseCalendar.Date) date.clone();
1649        cal.getCalendarDateFromFixedDate(d, nextJan1 - 1);
1650        value = d.getMonth() - 1;
1651        }
1652        break;
1653
1654        case DAY_OF_MONTH:
1655        {
1656        value = cal.getMonthLength(date);
1657        if (!gc.isCutoverYear(normalizedYear) || date.getDayOfMonth() == value) {
1658            break;
1659        }
1660
1661        // Handle cutover year.
1662
long fd = gc.getCurrentFixedDate();
1663        if (fd >= gregorianCutoverDate) {
1664            break;
1665        }
1666        int monthLength = gc.actualMonthLength();
1667        long monthEnd = gc.getFixedDateMonth1(gc.cdate, fd) + monthLength - 1;
1668        // Convert the fixed date to its calendar date.
1669
BaseCalendar.Date d = gc.getCalendarDate(monthEnd);
1670        value = d.getDayOfMonth();
1671        }
1672        break;
1673
1674        case DAY_OF_YEAR:
1675        {
1676        if (!gc.isCutoverYear(normalizedYear)) {
1677            value = cal.getYearLength(date);
1678            break;
1679        }
1680
1681        // Handle cutover year.
1682
long jan1;
1683        if (gregorianCutoverYear == gregorianCutoverYearJulian) {
1684            BaseCalendar cocal = gc.getCutoverCalendarSystem();
1685            jan1 = cocal.getFixedDate(normalizedYear, 1, 1, null);
1686        } else if (normalizedYear == gregorianCutoverYearJulian) {
1687            jan1 = cal.getFixedDate(normalizedYear, 1, 1, null);
1688        } else {
1689            jan1 = gregorianCutoverDate;
1690        }
1691        // January 1 of the next year may or may not exist.
1692
long nextJan1 = gcal.getFixedDate(++normalizedYear, 1, 1, null);
1693        if (nextJan1 < gregorianCutoverDate) {
1694            nextJan1 = gregorianCutoverDate;
1695        }
1696        assert jan1 <= cal.getFixedDate(date.getNormalizedYear(), date.getMonth(),
1697                        date.getDayOfMonth(), date);
1698        assert nextJan1 >= cal.getFixedDate(date.getNormalizedYear(), date.getMonth(),
1699                        date.getDayOfMonth(), date);
1700        value = (int)(nextJan1 - jan1);
1701        }
1702        break;
1703
1704        case WEEK_OF_YEAR:
1705        {
1706        if (!gc.isCutoverYear(normalizedYear)) {
1707            // Get the day of week of January 1 of the year
1708
CalendarDate d = cal.newCalendarDate(TimeZone.NO_TIMEZONE);
1709            d.setDate(date.getYear(), BaseCalendar.JANUARY, 1);
1710            int dayOfWeek = cal.getDayOfWeek(d);
1711            // Normalize the day of week with the firstDayOfWeek value
1712
dayOfWeek -= getFirstDayOfWeek();
1713            if (dayOfWeek < 0) {
1714            dayOfWeek += 7;
1715            }
1716            value = 52;
1717            int magic = dayOfWeek + getMinimalDaysInFirstWeek() - 1;
1718            if ((magic == 6) ||
1719            (date.isLeapYear() && (magic == 5 || magic == 12))) {
1720            value++;
1721            }
1722            break;
1723        }
1724
1725        if (gc == this) {
1726            gc = (GregorianCalendar JavaDoc) gc.clone();
1727        }
1728        gc.set(DAY_OF_YEAR, getActualMaximum(DAY_OF_YEAR));
1729        value = gc.get(WEEK_OF_YEAR);
1730        }
1731        break;
1732
1733        case WEEK_OF_MONTH:
1734        {
1735        if (!gc.isCutoverYear(normalizedYear)) {
1736            CalendarDate d = cal.newCalendarDate(null);
1737            d.setDate(date.getYear(), date.getMonth(), 1);
1738            int dayOfWeek = cal.getDayOfWeek(d);
1739            int monthLength = cal.getMonthLength(d);
1740            dayOfWeek -= getFirstDayOfWeek();
1741            if (dayOfWeek < 0) {
1742            dayOfWeek += 7;
1743            }
1744            int nDaysFirstWeek = 7 - dayOfWeek; // # of days in the first week
1745
value = 3;
1746            if (nDaysFirstWeek >= getMinimalDaysInFirstWeek()) {
1747            value++;
1748            }
1749            monthLength -= nDaysFirstWeek + 7 * 3;
1750            if (monthLength > 0) {
1751            value++;
1752            if (monthLength > 7) {
1753                value++;
1754            }
1755            }
1756            break;
1757        }
1758
1759        // Cutover year handling
1760
if (gc == this) {
1761            gc = (GregorianCalendar JavaDoc) gc.clone();
1762        }
1763        int y = gc.internalGet(YEAR);
1764        int m = gc.internalGet(MONTH);
1765        do {
1766            value = gc.get(WEEK_OF_MONTH);
1767            gc.add(WEEK_OF_MONTH, +1);
1768        } while (gc.get(YEAR) == y && gc.get(MONTH) == m);
1769        }
1770        break;
1771
1772        case DAY_OF_WEEK_IN_MONTH:
1773        {
1774        // may be in the Gregorian cutover month
1775
int ndays, dow1;
1776        int dow = date.getDayOfWeek();
1777        if (!gc.isCutoverYear(normalizedYear)) {
1778            BaseCalendar.Date d = (BaseCalendar.Date) date.clone();
1779            ndays = cal.getMonthLength(d);
1780            d.setDayOfMonth(1);
1781            cal.normalize(d);
1782            dow1 = d.getDayOfWeek();
1783        } else {
1784            // Let a cloned GregorianCalendar take care of the cutover cases.
1785
if (gc == this) {
1786            gc = (GregorianCalendar JavaDoc) clone();
1787            }
1788            ndays = gc.actualMonthLength();
1789            gc.set(DAY_OF_MONTH, gc.getActualMinimum(DAY_OF_MONTH));
1790            dow1 = gc.get(DAY_OF_WEEK);
1791        }
1792        int x = dow - dow1;
1793        if (x < 0) {
1794            x += 7;
1795        }
1796        ndays -= x;
1797        value = (ndays + 6) / 7;
1798        }
1799        break;
1800
1801    case YEAR:
1802            /* The year computation is no different, in principle, from the
1803             * others, however, the range of possible maxima is large. In
1804             * addition, the way we know we've exceeded the range is different.
1805             * For these reasons, we use the special case code below to handle
1806             * this field.
1807             *
1808             * The actual maxima for YEAR depend on the type of calendar:
1809             *
1810             * Gregorian = May 17, 292275056 BCE - Aug 17, 292278994 CE
1811             * Julian = Dec 2, 292269055 BCE - Jan 3, 292272993 CE
1812             * Hybrid = Dec 2, 292269055 BCE - Aug 17, 292278994 CE
1813             *
1814             * We know we've exceeded the maximum when either the month, date,
1815             * time, or era changes in response to setting the year. We don't
1816             * check for month, date, and time here because the year and era are
1817             * sufficient to detect an invalid year setting. NOTE: If code is
1818             * added to check the month and date in the future for some reason,
1819             * Feb 29 must be allowed to shift to Mar 1 when setting the year.
1820             */

1821        {
1822        if (gc == this) {
1823            gc = (GregorianCalendar JavaDoc) clone();
1824        }
1825
1826        // Calculate the millisecond offset from the beginning
1827
// of the year of this calendar and adjust the max
1828
// year value if we are beyond the limit in the max
1829
// year.
1830
long current = gc.getYearOffsetInMillis();
1831
1832        if (gc.internalGetEra() == CE) {
1833            gc.setTimeInMillis(Long.MAX_VALUE);
1834            value = gc.get(YEAR);
1835            long maxEnd = gc.getYearOffsetInMillis();
1836            if (current > maxEnd) {
1837            value--;
1838            }
1839        } else {
1840            CalendarSystem mincal = gc.getTimeInMillis() >= gregorianCutover ?
1841            gcal : getJulianCalendarSystem();
1842            CalendarDate d = mincal.getCalendarDate(Long.MIN_VALUE, getZone());
1843            long maxEnd = (cal.getDayOfYear(d) - 1) * 24 + d.getHours();
1844            maxEnd *= 60;
1845            maxEnd += d.getMinutes();
1846            maxEnd *= 60;
1847            maxEnd += d.getSeconds();
1848            maxEnd *= 1000;
1849            maxEnd += d.getMillis();
1850            value = d.getYear();
1851            if (value <= 0) {
1852            assert mincal == gcal;
1853            value = 1 - value;
1854            }
1855            if (current < maxEnd) {
1856            value--;
1857            }
1858        }
1859        }
1860        break;
1861
1862    default:
1863        throw new ArrayIndexOutOfBoundsException JavaDoc(field);
1864    }
1865    return value;
1866    }
1867
1868    /**
1869     * Returns the millisecond offset from the beginning of this
1870     * year. This Calendar object must have been normalized.
1871     */

1872    private final long getYearOffsetInMillis() {
1873    long t = (internalGet(DAY_OF_YEAR) - 1) * 24;
1874    t += internalGet(HOUR_OF_DAY);
1875    t *= 60;
1876    t += internalGet(MINUTE);
1877    t *= 60;
1878    t += internalGet(SECOND);
1879    t *= 1000;
1880    return t + internalGet(MILLISECOND) -
1881        (internalGet(ZONE_OFFSET) + internalGet(DST_OFFSET));
1882    }
1883
1884    public Object JavaDoc clone()
1885    {
1886    GregorianCalendar JavaDoc other = (GregorianCalendar JavaDoc) super.clone();
1887
1888    other.gdate = (BaseCalendar.Date) gdate.clone();
1889    if (cdate != null) {
1890        if (cdate != gdate) {
1891        other.cdate = (BaseCalendar.Date) cdate.clone();
1892        } else {
1893        other.cdate = other.gdate;
1894        }
1895    }
1896    other.originalFields = null;
1897    other.zoneOffsets = null;
1898    return other;
1899    }
1900
1901    public TimeZone JavaDoc getTimeZone() {
1902    TimeZone JavaDoc zone = super.getTimeZone();
1903    // To share the zone by CalendarDates
1904
gdate.setZone(zone);
1905    if (cdate != null && cdate != gdate) {
1906        cdate.setZone(zone);
1907    }
1908    return zone;
1909    }
1910
1911    public void setTimeZone(TimeZone JavaDoc zone) {
1912    super.setTimeZone(zone);
1913    // To share the zone by CalendarDates
1914
gdate.setZone(zone);
1915    if (cdate != null && cdate != gdate) {
1916        cdate.setZone(zone);
1917    }
1918    }
1919
1920//////////////////////
1921
// Proposed public API
1922
//////////////////////
1923

1924    /**
1925     * Returns the year that corresponds to the <code>WEEK_OF_YEAR</code> field.
1926     * This may be one year before or after the Gregorian or Julian year stored
1927     * in the <code>YEAR</code> field. For example, January 1, 1999 is considered
1928     * Friday of week 53 of 1998 (if minimal days in first week is
1929     * 2 or less, and the first day of the week is Sunday). Given
1930     * these same settings, the ISO year of January 1, 1999 is
1931     * 1998.
1932     *
1933     * <p>This method calls {@link Calendar#complete} before
1934     * calculating the week-based year.
1935     *
1936     * @return the year corresponding to the <code>WEEK_OF_YEAR</code> field, which
1937     * may be one year before or after the <code>YEAR</code> field.
1938     * @see #YEAR
1939     * @see #WEEK_OF_YEAR
1940     */

1941    /*
1942    public int getWeekBasedYear() {
1943        complete();
1944    // TODO: Below doesn't work for gregorian cutover...
1945        int weekOfYear = internalGet(WEEK_OF_YEAR);
1946        int year = internalGet(YEAR);
1947        if (internalGet(MONTH) == Calendar.JANUARY) {
1948            if (weekOfYear >= 52) {
1949                --year;
1950            }
1951        } else {
1952            if (weekOfYear == 1) {
1953                ++year;
1954            }
1955        }
1956        return year;
1957    }
1958    */

1959
1960
1961/////////////////////////////
1962
// Time => Fields computation
1963
/////////////////////////////
1964

1965    /**
1966     * The fixed date corresponding to gdate. If the value is
1967     * Long.MIN_VALUE, the fixed date value is unknown. Currently,
1968     * Julian calendar dates are not cached.
1969     */

1970    transient private long cachedFixedDate = Long.MIN_VALUE;
1971
1972    /**
1973     * Converts the time value (millisecond offset from the <a
1974     * HREF="Calendar.html#Epoch">Epoch</a>) to calendar field values.
1975     * The time is <em>not</em>
1976     * recomputed first; to recompute the time, then the fields, call the
1977     * <code>complete</code> method.
1978     *
1979     * @see Calendar#complete
1980     */

1981    protected void computeFields() {
1982    int mask = 0;
1983    if (isPartiallyNormalized()) {
1984        // Determine which calendar fields need to be computed.
1985
mask = getSetStateFields();
1986        int fieldMask = ~mask & ALL_FIELDS;
1987        // We have to call computeFields(int, int) in case calsys == null
1988
// in order to set calsys and cdate. (6263644)
1989
if (fieldMask != 0 || calsys == null) {
1990        mask |= computeFields(fieldMask,
1991                      mask & (ZONE_OFFSET_MASK|DST_OFFSET_MASK));
1992        assert mask == ALL_FIELDS;
1993        }
1994    } else {
1995        mask = ALL_FIELDS;
1996        computeFields(mask, 0);
1997    }
1998    // After computing all the fields, set the field state to `COMPUTED'.
1999
setFieldsComputed(mask);
2000    }
2001
2002    /**
2003     * This computeFields implements the conversion from UTC
2004     * (millisecond offset from the Epoch) to calendar
2005     * field values. fieldMask specifies which fields to change the
2006     * setting state to COMPUTED, although all fields are set to
2007     * the correct values. This is required to fix 4685354.
2008     *
2009     * @param fieldMask a bit mask to specify which fields to change
2010     * the setting state.
2011     * @param tzMask a bit mask to specify which time zone offset
2012     * fields to be used for time calculations
2013     * @return a new field mask that indicates what field values have
2014     * actually been set.
2015     */

2016    private int computeFields(int fieldMask, int tzMask) {
2017    int zoneOffset = 0;
2018    TimeZone JavaDoc tz = getZone();
2019    if (zoneOffsets == null) {
2020        zoneOffsets = new int[2];
2021    }
2022    if (tzMask != (ZONE_OFFSET_MASK|DST_OFFSET_MASK)) {
2023        if (tz instanceof ZoneInfo) {
2024        zoneOffset = ((ZoneInfo)tz).getOffsets(time, zoneOffsets);
2025        } else {
2026        zoneOffset = tz.getOffset(time);
2027        zoneOffsets[0] = tz.getRawOffset();
2028        zoneOffsets[1] = zoneOffset - zoneOffsets[0];
2029        }
2030    }
2031    if (tzMask != 0) {
2032        if (isFieldSet(tzMask, ZONE_OFFSET)) {
2033        zoneOffsets[0] = internalGet(ZONE_OFFSET);
2034        }
2035        if (isFieldSet(tzMask, DST_OFFSET)) {
2036        zoneOffsets[1] = internalGet(DST_OFFSET);
2037        }
2038        zoneOffset = zoneOffsets[0] + zoneOffsets[1];
2039    }
2040
2041    // By computing time and zoneOffset separately, we can take
2042
// the wider range of time+zoneOffset than the previous
2043
// implementation.
2044
long fixedDate = zoneOffset / ONE_DAY;
2045    int timeOfDay = zoneOffset % (int)ONE_DAY;
2046    fixedDate += time / ONE_DAY;
2047    timeOfDay += (int) (time % ONE_DAY);
2048    if (timeOfDay >= ONE_DAY) {
2049        timeOfDay -= ONE_DAY;
2050        ++fixedDate;
2051    } else {
2052        while (timeOfDay < 0) {
2053        timeOfDay += ONE_DAY;
2054        --fixedDate;
2055        }
2056    }
2057    fixedDate += EPOCH_OFFSET;
2058
2059    int era = CE;
2060    int year;
2061    if (fixedDate >= gregorianCutoverDate) {
2062        // Handle Gregorian dates.
2063
assert cachedFixedDate == Long.MIN_VALUE || gdate.isNormalized()
2064            : "cache control: not normalized";
2065        assert cachedFixedDate == Long.MIN_VALUE ||
2066           gcal.getFixedDate(gdate.getNormalizedYear(),
2067                      gdate.getMonth(),
2068                      gdate.getDayOfMonth(), gdate)
2069                == cachedFixedDate
2070            : "cache control: inconsictency" +
2071              ", cachedFixedDate=" + cachedFixedDate +
2072              ", computed=" +
2073                  gcal.getFixedDate(gdate.getNormalizedYear(),
2074                         gdate.getMonth(),
2075                         gdate.getDayOfMonth(),
2076                         gdate) +
2077              ", date=" + gdate;
2078
2079        // See if we can use gdate to avoid date calculation.
2080
if (fixedDate != cachedFixedDate) {
2081        gcal.getCalendarDateFromFixedDate(gdate, fixedDate);
2082        cachedFixedDate = fixedDate;
2083        }
2084
2085        year = gdate.getYear();
2086        if (year <= 0) {
2087        year = 1 - year;
2088        era = BCE;
2089        }
2090        calsys = gcal;
2091        cdate = gdate;
2092        assert cdate.getDayOfWeek() > 0 : "dow="+cdate.getDayOfWeek()+", date="+cdate;
2093    } else {
2094        // Handle Julian calendar dates.
2095
calsys = getJulianCalendarSystem();
2096        cdate = (BaseCalendar.Date) jcal.newCalendarDate(getZone());
2097        jcal.getCalendarDateFromFixedDate(cdate, fixedDate);
2098        Era e = cdate.getEra();
2099        if (e == jeras[0]) {
2100        era = BCE;
2101        }
2102        year = cdate.getYear();
2103    }
2104
2105    // Always set the ERA and YEAR values.
2106
internalSet(ERA, era);
2107    internalSet(YEAR, year);
2108    int mask = fieldMask | (ERA_MASK|YEAR_MASK);
2109
2110    int month = cdate.getMonth() - 1; // 0-based
2111
int dayOfMonth = cdate.getDayOfMonth();
2112
2113    // Set the basic date fields.
2114
if ((fieldMask & (MONTH_MASK|DAY_OF_MONTH_MASK|DAY_OF_WEEK_MASK))
2115        != 0) {
2116        internalSet(MONTH, month);
2117        internalSet(DAY_OF_MONTH, dayOfMonth);
2118        internalSet(DAY_OF_WEEK, cdate.getDayOfWeek());
2119        mask |= MONTH_MASK|DAY_OF_MONTH_MASK|DAY_OF_WEEK_MASK;
2120    }
2121
2122    if ((fieldMask & (HOUR_OF_DAY_MASK|AM_PM_MASK|HOUR_MASK
2123              |MINUTE_MASK|SECOND_MASK|MILLISECOND_MASK)) != 0) {
2124        if (timeOfDay != 0) {
2125        int hours = timeOfDay / ONE_HOUR;
2126        internalSet(HOUR_OF_DAY, hours);
2127        internalSet(AM_PM, hours / 12); // Assume AM == 0
2128
internalSet(HOUR, hours % 12);
2129        int r = timeOfDay % ONE_HOUR;
2130        internalSet(MINUTE, r / ONE_MINUTE);
2131        r %= ONE_MINUTE;
2132        internalSet(SECOND, r / ONE_SECOND);
2133        internalSet(MILLISECOND, r % ONE_SECOND);
2134        } else {
2135        internalSet(HOUR_OF_DAY, 0);
2136        internalSet(AM_PM, AM);
2137        internalSet(HOUR, 0);
2138        internalSet(MINUTE, 0);
2139        internalSet(SECOND, 0);
2140        internalSet(MILLISECOND, 0);
2141        }
2142        mask |= (HOUR_OF_DAY_MASK|AM_PM_MASK|HOUR_MASK
2143             |MINUTE_MASK|SECOND_MASK|MILLISECOND_MASK);
2144    }
2145
2146    if ((fieldMask & (ZONE_OFFSET_MASK|DST_OFFSET_MASK)) != 0) {
2147        internalSet(ZONE_OFFSET, zoneOffsets[0]);
2148        internalSet(DST_OFFSET, zoneOffsets[1]);
2149        mask |= (ZONE_OFFSET_MASK|DST_OFFSET_MASK);
2150    }
2151
2152    if ((fieldMask & (DAY_OF_YEAR_MASK|WEEK_OF_YEAR_MASK|WEEK_OF_MONTH_MASK|DAY_OF_WEEK_IN_MONTH_MASK)) != 0) {
2153        int normalizedYear = cdate.getNormalizedYear();
2154        long fixedDateJan1 = calsys.getFixedDate(normalizedYear, 1, 1, cdate);
2155        int dayOfYear = (int)(fixedDate - fixedDateJan1) + 1;
2156        long fixedDateMonth1 = fixedDate - dayOfMonth + 1;
2157        int cutoverGap = 0;
2158        int cutoverYear = (calsys == gcal) ? gregorianCutoverYear : gregorianCutoverYearJulian;
2159        int relativeDayOfMonth = dayOfMonth - 1;
2160
2161        // If we are in the cutover year, we need some special handling.
2162
if (normalizedYear == cutoverYear) {
2163        // Need to take care of the "missing" days.
2164
if (getCutoverCalendarSystem() == jcal) {
2165            // We need to find out where we are. The cutover
2166
// gap could even be more than one year. (One
2167
// year difference in ~48667 years.)
2168
fixedDateJan1 = getFixedDateJan1(cdate, fixedDate);
2169            if (fixedDate >= gregorianCutoverDate) {
2170            fixedDateMonth1 = getFixedDateMonth1(cdate, fixedDate);
2171            }
2172        }
2173        int realDayOfYear = (int)(fixedDate - fixedDateJan1) + 1;
2174        cutoverGap = dayOfYear - realDayOfYear;
2175        dayOfYear = realDayOfYear;
2176        relativeDayOfMonth = (int)(fixedDate - fixedDateMonth1);
2177        }
2178        internalSet(DAY_OF_YEAR, dayOfYear);
2179        internalSet(DAY_OF_WEEK_IN_MONTH, relativeDayOfMonth / 7 + 1);
2180
2181        int weekOfYear = getWeekNumber(fixedDateJan1, fixedDate);
2182
2183        // The spec is to calculate WEEK_OF_YEAR in the
2184
// ISO8601-style. This creates problems, though.
2185
if (weekOfYear == 0) {
2186        // If the date belongs to the last week of the
2187
// previous year, use the week number of "12/31" of
2188
// the "previous" year. Again, if the previous year is
2189
// the Gregorian cutover year, we need to take care of
2190
// it. Usually the previous day of January 1 is
2191
// December 31, which is not always true in
2192
// GregorianCalendar.
2193
long fixedDec31 = fixedDateJan1 - 1;
2194        long prevJan1;
2195        if (normalizedYear > (cutoverYear + 1)) {
2196            prevJan1 = fixedDateJan1 - 365;
2197            if (CalendarUtils.isGregorianLeapYear(normalizedYear - 1)) {
2198            --prevJan1;
2199            }
2200        } else {
2201            BaseCalendar calForJan1 = calsys;
2202            int prevYear = normalizedYear - 1;
2203            if (prevYear == cutoverYear) {
2204            calForJan1 = getCutoverCalendarSystem();
2205            }
2206            prevJan1 = calForJan1.getFixedDate(prevYear,
2207                               BaseCalendar.JANUARY,
2208                               1,
2209                               null);
2210            while (prevJan1 > fixedDec31) {
2211            prevJan1 = getJulianCalendarSystem().getFixedDate(--prevYear,
2212                                    BaseCalendar.JANUARY,
2213                                    1,
2214                                    null);
2215            }
2216        }
2217        weekOfYear = getWeekNumber(prevJan1, fixedDec31);
2218        } else {
2219        if (normalizedYear > gregorianCutoverYear ||
2220            normalizedYear < (gregorianCutoverYearJulian - 1)) {
2221            // Regular years
2222
if (weekOfYear >= 52) {
2223            long nextJan1 = fixedDateJan1 + 365;
2224            if (cdate.isLeapYear()) {
2225                nextJan1++;
2226            }
2227            long nextJan1st = calsys.getDayOfWeekDateOnOrBefore(nextJan1 + 6,
2228                                        getFirstDayOfWeek());
2229            int ndays = (int)(nextJan1st - nextJan1);
2230            if (ndays >= getMinimalDaysInFirstWeek() && fixedDate >= (nextJan1st - 7)) {
2231                // The first days forms a week in which the date is included.
2232
weekOfYear = 1;
2233            }
2234            }
2235        } else {
2236            BaseCalendar calForJan1 = calsys;
2237            int nextYear = normalizedYear + 1;
2238            if (nextYear == (gregorianCutoverYearJulian + 1) &&
2239            nextYear < gregorianCutoverYear) {
2240            // In case the gap is more than one year.
2241
nextYear = gregorianCutoverYear;
2242            }
2243            if (nextYear == gregorianCutoverYear) {
2244            calForJan1 = getCutoverCalendarSystem();
2245            }
2246            long nextJan1 = calForJan1.getFixedDate(nextYear,
2247                                BaseCalendar.JANUARY,
2248                                1,
2249                                null);
2250            if (nextJan1 < fixedDate) {
2251            nextJan1 = gregorianCutoverDate;
2252            calForJan1 = gcal;
2253            }
2254            long nextJan1st = calForJan1.getDayOfWeekDateOnOrBefore(nextJan1 + 6,
2255                                        getFirstDayOfWeek());
2256            int ndays = (int)(nextJan1st - nextJan1);
2257            if (ndays >= getMinimalDaysInFirstWeek() && fixedDate >= (nextJan1st - 7)) {
2258            // The first days forms a week in which the date is included.
2259
weekOfYear = 1;
2260            }
2261        }
2262        }
2263        internalSet(WEEK_OF_YEAR, weekOfYear);
2264        internalSet(WEEK_OF_MONTH, getWeekNumber(fixedDateMonth1, fixedDate));
2265        mask |= (DAY_OF_YEAR_MASK|WEEK_OF_YEAR_MASK|WEEK_OF_MONTH_MASK|DAY_OF_WEEK_IN_MONTH_MASK);
2266    }
2267    return mask;
2268    }
2269
2270    /**
2271     * Returns the number of weeks in a period between fixedDay1 and
2272     * fixedDate. The getFirstDayOfWeek-getMinimalDaysInFirstWeek rule
2273     * is applied to calculate the number of weeks.
2274     *
2275     * @param fixedDay1 the fixed date of the first day of the period
2276     * @param fixedDate the fixed date of the last day of the period
2277     * @return the number of weeks of the given period
2278     */

2279    private final int getWeekNumber(long fixedDay1, long fixedDate) {
2280    // We can always use `gcal' since Julian and Gregorian are the
2281
// same thing for this calculation.
2282
long fixedDay1st = gcal.getDayOfWeekDateOnOrBefore(fixedDay1 + 6,
2283                               getFirstDayOfWeek());
2284    int ndays = (int)(fixedDay1st - fixedDay1);
2285    assert ndays <= 7;
2286    if (ndays >= getMinimalDaysInFirstWeek()) {
2287        fixedDay1st -= 7;
2288    }
2289    int normalizedDayOfPeriod = (int)(fixedDate - fixedDay1st);
2290    if (normalizedDayOfPeriod >= 0) {
2291        return normalizedDayOfPeriod / 7 + 1;
2292    }
2293    return CalendarUtils.floorDivide(normalizedDayOfPeriod, 7) + 1;
2294    }
2295
2296    /**
2297     * Converts calendar field values to the time value (millisecond
2298     * offset from the <a HREF="Calendar.html#Epoch">Epoch</a>).
2299     *
2300     * @exception IllegalArgumentException if any calendar fields are invalid.
2301     */

2302    protected void computeTime() {
2303    // In non-lenient mode, perform brief checking of calendar
2304
// fields which have been set externally. Through this
2305
// checking, the field values are stored in originalFields[]
2306
// to see if any of them are normalized later.
2307
if (!isLenient()) {
2308        if (originalFields == null) {
2309        originalFields = new int[FIELD_COUNT];
2310        }
2311        for (int field = 0; field < FIELD_COUNT; field++) {
2312        int value = internalGet(field);
2313        if (isExternallySet(field)) {
2314            // Quick validation for any out of range values
2315
if (value < getMinimum(field) || value > getMaximum(field)) {
2316            throw new IllegalArgumentException JavaDoc(getFieldName(field));
2317            }
2318        }
2319        originalFields[field] = value;
2320        }
2321    }
2322
2323    // Let the super class determine which calendar fields to be
2324
// used to calculate the time.
2325
int fieldMask = selectFields();
2326
2327        // The year defaults to the epoch start. We don't check
2328
// fieldMask for YEAR because YEAR is a mandatory field to
2329
// determine the date.
2330
int year = isSet(YEAR) ? internalGet(YEAR) : EPOCH_YEAR;
2331
2332        int era = internalGetEra();
2333    if (era == BCE) {
2334        year = 1 - year;
2335    } else if (era != CE) {
2336        // Even in lenient mode we disallow ERA values other than CE & BCE.
2337
// (The same normalization rule as add()/roll() could be
2338
// applied here in lenient mode. But this checking is kept
2339
// unchanged for compatibility as of 1.5.)
2340
throw new IllegalArgumentException JavaDoc("Invalid era");
2341    }
2342        
2343    // If year is 0 or negative, we need to set the ERA value later.
2344
if (year <= 0 && !isSet(ERA)) {
2345        fieldMask |= ERA_MASK;
2346        setFieldsComputed(ERA_MASK);
2347    }
2348
2349        // Calculate the time of day. We rely on the convention that
2350
// an UNSET field has 0.
2351
long timeOfDay = 0;
2352    if (isFieldSet(fieldMask, HOUR_OF_DAY)) {
2353        timeOfDay += (long) internalGet(HOUR_OF_DAY);
2354    } else {
2355        timeOfDay += internalGet(HOUR);
2356        // The default value of AM_PM is 0 which designates AM.
2357
if (isFieldSet(fieldMask, AM_PM)) {
2358        timeOfDay += 12 * internalGet(AM_PM);
2359        }
2360        }
2361        timeOfDay *= 60;
2362    timeOfDay += internalGet(MINUTE);
2363        timeOfDay *= 60;
2364    timeOfDay += internalGet(SECOND);
2365        timeOfDay *= 1000;
2366    timeOfDay += internalGet(MILLISECOND);
2367
2368    // Convert the time of day to the number of days and the
2369
// millisecond offset from midnight.
2370
long fixedDate = timeOfDay / ONE_DAY;
2371    timeOfDay %= ONE_DAY;
2372    while (timeOfDay < 0) {
2373        timeOfDay += ONE_DAY;
2374        --fixedDate;
2375    }
2376
2377    // Calculate the fixed date since January 1, 1 (Gregorian).
2378
calculateFixedDate: {
2379        long gfd, jfd;
2380        if (year > gregorianCutoverYear && year > gregorianCutoverYearJulian) {
2381        gfd = fixedDate + getFixedDate(gcal, year, fieldMask);
2382        if (gfd >= gregorianCutoverDate) {
2383            fixedDate = gfd;
2384            break calculateFixedDate;
2385        }
2386        jfd = fixedDate + getFixedDate(getJulianCalendarSystem(), year, fieldMask);
2387        } else if (year < gregorianCutoverYear && year < gregorianCutoverYearJulian) {
2388        jfd = fixedDate + getFixedDate(getJulianCalendarSystem(), year, fieldMask);
2389        if (jfd < gregorianCutoverDate) {
2390            fixedDate = jfd;
2391            break calculateFixedDate;
2392        }
2393        gfd = fixedDate + getFixedDate(gcal, year, fieldMask);
2394        } else {
2395        gfd = fixedDate + getFixedDate(gcal, year, fieldMask);
2396        jfd = fixedDate + getFixedDate(getJulianCalendarSystem(), year, fieldMask);
2397        }
2398        // Now we have to determine which calendar date it is.
2399
if (gfd >= gregorianCutoverDate) {
2400        if (jfd >= gregorianCutoverDate) {
2401            fixedDate = gfd;
2402        } else {
2403            // The date is in an "overlapping" period. No way
2404
// to disambiguate it. Determine it using the
2405
// previous date calculation.
2406
if (calsys == gcal || calsys == null) {
2407            fixedDate = gfd;
2408            } else {
2409            fixedDate = jfd;
2410            }
2411        }
2412        } else {
2413        if (jfd < gregorianCutoverDate) {
2414            fixedDate = jfd;
2415        } else {
2416            // The date is in a "missing" period.
2417
if (!isLenient()) {
2418            throw new IllegalArgumentException JavaDoc("the specified date doesn't exist");
2419            }
2420            // Take the Julian date for compatibility, which
2421
// will produce a Gregorian date.
2422
fixedDate = jfd;
2423        }
2424        }
2425    }
2426
2427        // millis represents local wall-clock time in milliseconds.
2428
long millis = (fixedDate - EPOCH_OFFSET) * ONE_DAY + timeOfDay;
2429
2430        // Compute the time zone offset and DST offset. There are two potential
2431
// ambiguities here. We'll assume a 2:00 am (wall time) switchover time
2432
// for discussion purposes here.
2433
// 1. The transition into DST. Here, a designated time of 2:00 am - 2:59 am
2434
// can be in standard or in DST depending. However, 2:00 am is an invalid
2435
// representation (the representation jumps from 1:59:59 am Std to 3:00:00 am DST).
2436
// We assume standard time.
2437
// 2. The transition out of DST. Here, a designated time of 1:00 am - 1:59 am
2438
// can be in standard or DST. Both are valid representations (the rep
2439
// jumps from 1:59:59 DST to 1:00:00 Std).
2440
// Again, we assume standard time.
2441
// We use the TimeZone object, unless the user has explicitly set the ZONE_OFFSET
2442
// or DST_OFFSET fields; then we use those fields.
2443
TimeZone JavaDoc zone = getZone();
2444    if (zoneOffsets == null) {
2445        zoneOffsets = new int[2];
2446    }
2447    int tzMask = fieldMask & (ZONE_OFFSET_MASK|DST_OFFSET_MASK);
2448    if (tzMask != (ZONE_OFFSET_MASK|DST_OFFSET_MASK)) {
2449        if (zone instanceof ZoneInfo) {
2450        ((ZoneInfo)zone).getOffsetsByWall(millis, zoneOffsets);
2451        } else {
2452        int gmtOffset = isFieldSet(fieldMask, ZONE_OFFSET) ?
2453                    internalGet(ZONE_OFFSET) : zone.getRawOffset();
2454        zone.getOffsets(millis - gmtOffset, zoneOffsets);
2455        }
2456    }
2457    if (tzMask != 0) {
2458        if (isFieldSet(tzMask, ZONE_OFFSET)) {
2459        zoneOffsets[0] = internalGet(ZONE_OFFSET);
2460        }
2461        if (isFieldSet(tzMask, DST_OFFSET)) {
2462        zoneOffsets[1] = internalGet(DST_OFFSET);
2463        }
2464    }
2465
2466    // Adjust the time zone offset values to get the UTC time.
2467
millis -= zoneOffsets[0] + zoneOffsets[1];
2468
2469    // Set this calendar's time in milliseconds
2470
time = millis;
2471
2472    int mask = computeFields(fieldMask | getSetStateFields(), tzMask);
2473
2474    if (!isLenient()) {
2475        for (int field = 0; field < FIELD_COUNT; field++) {
2476        if (!isExternallySet(field)) {
2477            continue;
2478        }
2479        if (originalFields[field] != internalGet(field)) {
2480            // Restore the original field values
2481
System.arraycopy(originalFields, 0, fields, 0, fields.length);
2482            throw new IllegalArgumentException JavaDoc(getFieldName(field));
2483        }
2484        }
2485    }
2486    setFieldsNormalized(mask);
2487    }
2488
2489    /**
2490     * Computes the fixed date under either the Gregorian or the
2491     * Julian calendar, using the given year and the specified calendar fields.
2492     *
2493     * @param cal the CalendarSystem to be used for the date calculation
2494     * @param year the normalized year number, with 0 indicating the
2495     * year 1 BCE, -1 indicating 2 BCE, etc.
2496     * @param fieldMask the calendar fields to be used for the date calculation
2497     * @return the fixed date
2498     * @see Calendar#selectFields
2499     */

2500    private long getFixedDate(BaseCalendar cal, int year, int fieldMask) {
2501    int month = JANUARY;
2502    if (isFieldSet(fieldMask, MONTH)) {
2503            // No need to check if MONTH has been set (no isSet(MONTH)
2504
// call) since its unset value happens to be JANUARY (0).
2505
month = internalGet(MONTH);
2506
2507            // If the month is out of range, adjust it into range
2508
if (month > DECEMBER) {
2509        year += month / 12;
2510        month %= 12;
2511        } else if (month < JANUARY) {
2512                int[] rem = new int[1];
2513                year += CalendarUtils.floorDivide(month, 12, rem);
2514                month = rem[0];
2515            }
2516    }
2517
2518    // Get the fixed date since Jan 1, 1 (Gregorian). We are on
2519
// the first day of either `month' or January in 'year'.
2520
long fixedDate = cal.getFixedDate(year, month + 1, 1,
2521                      cal == gcal ? gdate : null);
2522    if (isFieldSet(fieldMask, MONTH)) {
2523        // Month-based calculations
2524
if (isFieldSet(fieldMask, DAY_OF_MONTH)) {
2525        // We are on the first day of the month. Just add the
2526
// offset if DAY_OF_MONTH is set. If the isSet call
2527
// returns false, that means DAY_OF_MONTH has been
2528
// selected just because of the selected
2529
// combination. We don't need to add any since the
2530
// default value is the 1st.
2531
if (isSet(DAY_OF_MONTH)) {
2532            // To avoid underflow with DAY_OF_MONTH-1, add
2533
// DAY_OF_MONTH, then subtract 1.
2534
fixedDate += internalGet(DAY_OF_MONTH);
2535            fixedDate--;
2536        }
2537            } else {
2538                if (isFieldSet(fieldMask, WEEK_OF_MONTH)) {
2539            long firstDayOfWeek = cal.getDayOfWeekDateOnOrBefore(fixedDate + 6,
2540                                     getFirstDayOfWeek());
2541                    // If we have enough days in the first week, then
2542
// move to the previous week.
2543
if ((firstDayOfWeek - fixedDate) >= getMinimalDaysInFirstWeek()) {
2544            firstDayOfWeek -= 7;
2545            }
2546            if (isFieldSet(fieldMask, DAY_OF_WEEK)) {
2547            firstDayOfWeek = cal.getDayOfWeekDateOnOrBefore(firstDayOfWeek + 6,
2548                                    internalGet(DAY_OF_WEEK));
2549            }
2550            // In lenient mode, we treat days of the previous
2551
// months as a part of the specified
2552
// WEEK_OF_MONTH. See 4633646.
2553
fixedDate = firstDayOfWeek + 7 * (internalGet(WEEK_OF_MONTH) - 1);
2554                } else {
2555            int dayOfWeek;
2556            if (isFieldSet(fieldMask, DAY_OF_WEEK)) {
2557            dayOfWeek = internalGet(DAY_OF_WEEK);
2558            } else {
2559            dayOfWeek = getFirstDayOfWeek();
2560            }
2561                    // We are basing this on the day-of-week-in-month. The only
2562
// trickiness occurs if the day-of-week-in-month is
2563
// negative.
2564
int dowim;
2565            if (isFieldSet(fieldMask, DAY_OF_WEEK_IN_MONTH)) {
2566            dowim = internalGet(DAY_OF_WEEK_IN_MONTH);
2567            } else {
2568            dowim = 1;
2569            }
2570            if (dowim >= 0) {
2571            fixedDate = cal.getDayOfWeekDateOnOrBefore(fixedDate + (7 * dowim) - 1,
2572                                   dayOfWeek);
2573            } else {
2574            // Go to the first day of the next week of
2575
// the specified week boundary.
2576
int lastDate = monthLength(month, year) + (7 * (dowim + 1));
2577            // Then, get the day of week date on or before the last date.
2578
fixedDate = cal.getDayOfWeekDateOnOrBefore(fixedDate + lastDate - 1,
2579                                   dayOfWeek);
2580                    }
2581                }
2582            }
2583        } else {
2584        if (year == gregorianCutoverYear && cal == gcal
2585        && fixedDate < gregorianCutoverDate
2586        && gregorianCutoverYear != gregorianCutoverYearJulian) {
2587        // January 1 of the year doesn't exist. Use
2588
// gregorianCutoverDate as the first day of the
2589
// year.
2590
fixedDate = gregorianCutoverDate;
2591        }
2592        // We are on the first day of the year.
2593
if (isFieldSet(fieldMask, DAY_OF_YEAR)) {
2594        // Add the offset, then subtract 1. (Make sure to avoid underflow.)
2595
fixedDate += internalGet(DAY_OF_YEAR);
2596        fixedDate--;
2597            } else {
2598        long firstDayOfWeek = cal.getDayOfWeekDateOnOrBefore(fixedDate + 6,
2599                                     getFirstDayOfWeek());
2600        // If we have enough days in the first week, then move
2601
// to the previous week.
2602
if ((firstDayOfWeek - fixedDate) >= getMinimalDaysInFirstWeek()) {
2603            firstDayOfWeek -= 7;
2604        }
2605        if (isFieldSet(fieldMask, DAY_OF_WEEK)) {
2606            int dayOfWeek = internalGet(DAY_OF_WEEK);
2607            if (dayOfWeek != getFirstDayOfWeek()) {
2608            firstDayOfWeek = cal.getDayOfWeekDateOnOrBefore(firstDayOfWeek + 6,
2609                                    dayOfWeek);
2610            }
2611        }
2612        fixedDate = firstDayOfWeek + 7 * ((long)internalGet(WEEK_OF_YEAR) - 1);
2613            }
2614        }
2615
2616        return fixedDate;
2617    }
2618
2619    /**
2620     * Returns this object if it's normalized (all fields and time are
2621     * in sync). Otherwise, a cloned object is returned after calling
2622     * complete() in lenient mode.
2623     */

2624    private final GregorianCalendar JavaDoc getNormalizedCalendar() {
2625    GregorianCalendar JavaDoc gc;
2626    if (isFullyNormalized()) {
2627        gc = this;
2628    } else {
2629        // Create a clone and normalize the calendar fields
2630
gc = (GregorianCalendar JavaDoc) this.clone();
2631        gc.setLenient(true);
2632        gc.complete();
2633    }
2634    return gc;
2635    }
2636
2637    /**
2638     * Returns the Julian calendar system instance (singleton). 'jcal'
2639     * and 'jeras' are set upon the return.
2640     */

2641    synchronized private static final BaseCalendar getJulianCalendarSystem() {
2642    if (jcal == null) {
2643        jcal = (JulianCalendar) CalendarSystem.forName("julian");
2644        jeras = jcal.getEras();
2645    }
2646    return jcal;
2647    }
2648
2649    /**
2650     * Returns the calendar system for dates before the cutover date
2651     * in the cutover year. If the cutover date is January 1, the
2652     * method returns Gregorian. Otherwise, Julian.
2653     */

2654    private BaseCalendar getCutoverCalendarSystem() {
2655    CalendarDate date = getGregorianCutoverDate();
2656    if (date.getMonth() == BaseCalendar.JANUARY
2657        && date.getDayOfMonth() == 1) {
2658        return gcal;
2659    }
2660    return getJulianCalendarSystem();
2661    }
2662
2663    /**
2664     * Determines if the specified year (normalized) is the Gregorian
2665     * cutover year. This object must have been normalized.
2666     */

2667    private final boolean isCutoverYear(int normalizedYear) {
2668    int cutoverYear = (calsys == gcal) ? gregorianCutoverYear : gregorianCutoverYearJulian;
2669    return normalizedYear == cutoverYear;
2670    }
2671
2672    /**
2673     * Returns the fixed date of the first day of the year (usually
2674     * January 1) before the specified date.
2675     *
2676     * @param date the date for which the first day of the year is
2677     * calculated. The date has to be in the cut-over year (Gregorian
2678     * or Julian).
2679     * @param fixedDate the fixed date representation of the date
2680     */

2681    private final long getFixedDateJan1(BaseCalendar.Date date, long fixedDate) {
2682    assert date.getNormalizedYear() == gregorianCutoverYear ||
2683        date.getNormalizedYear() == gregorianCutoverYearJulian;
2684    if (gregorianCutoverYear != gregorianCutoverYearJulian) {
2685        if (fixedDate >= gregorianCutoverDate) {
2686        // Dates before the cutover date don't exist
2687
// in the same (Gregorian) year. So, no
2688
// January 1 exists in the year. Use the
2689
// cutover date as the first day of the year.
2690
return gregorianCutoverDate;
2691        }
2692    }
2693    // January 1 of the normalized year should exist.
2694
BaseCalendar jcal = getJulianCalendarSystem();
2695    return jcal.getFixedDate(date.getNormalizedYear(), BaseCalendar.JANUARY, 1, null);
2696    }
2697
2698    /**
2699     * Returns the fixed date of the first date of the month (usually
2700     * the 1st of the month) before the specified date.
2701     *
2702     * @param date the date for which the first day of the month is
2703     * calculated. The date has to be in the cut-over year (Gregorian
2704     * or Julian).
2705     * @param fixedDate the fixed date representation of the date
2706     */

2707    private final long getFixedDateMonth1(BaseCalendar.Date date, long fixedDate) {
2708    assert date.getNormalizedYear() == gregorianCutoverYear ||
2709        date.getNormalizedYear() == gregorianCutoverYearJulian;
2710    BaseCalendar.Date gCutover = getGregorianCutoverDate();
2711    if (gCutover.getMonth() == BaseCalendar.JANUARY
2712        && gCutover.getDayOfMonth() == 1) {
2713        // The cutover happened on January 1.
2714
return fixedDate - date.getDayOfMonth() + 1;
2715    }
2716
2717    long fixedDateMonth1;
2718    // The cutover happened sometime during the year.
2719
if (date.getMonth() == gCutover.getMonth()) {
2720        // The cutover happened in the month.
2721
BaseCalendar.Date jLastDate = getLastJulianDate();
2722        if (gregorianCutoverYear == gregorianCutoverYearJulian
2723        && gCutover.getMonth() == jLastDate.getMonth()) {
2724        // The "gap" fits in the same month.
2725
fixedDateMonth1 = jcal.getFixedDate(date.getNormalizedYear(),
2726                            date.getMonth(),
2727                            1,
2728                            null);
2729        } else {
2730        // Use the cutover date as the first day of the month.
2731
fixedDateMonth1 = gregorianCutoverDate;
2732        }
2733    } else {
2734        // The cutover happened before the month.
2735
fixedDateMonth1 = fixedDate - date.getDayOfMonth() + 1;
2736    }
2737
2738    return fixedDateMonth1;
2739    }
2740
2741    /**
2742     * Returns a CalendarDate produced from the specified fixed date.
2743     *
2744     * @param fd the fixed date
2745     */

2746    private final BaseCalendar.Date getCalendarDate(long fd) {
2747    BaseCalendar cal = (fd >= gregorianCutoverDate) ? gcal : getJulianCalendarSystem();
2748    BaseCalendar.Date d = (BaseCalendar.Date) cal.newCalendarDate(TimeZone.NO_TIMEZONE);
2749    cal.getCalendarDateFromFixedDate(d, fd);
2750    return d;
2751    }
2752
2753    /**
2754     * Returns the Gregorian cutover date as a BaseCalendar.Date. The
2755     * date is a Gregorian date.
2756     */

2757    private final BaseCalendar.Date getGregorianCutoverDate() {
2758    return getCalendarDate(gregorianCutoverDate);
2759    }
2760
2761    /**
2762     * Returns the day before the Gregorian cutover date as a
2763     * BaseCalendar.Date. The date is a Julian date.
2764     */

2765    private final BaseCalendar.Date getLastJulianDate() {
2766    return getCalendarDate(gregorianCutoverDate - 1);
2767    }
2768
2769    /**
2770     * Returns the length of the specified month in the specified
2771     * year. The year number must be normalized.
2772     *
2773     * @see #isLeapYear(int)
2774     */

2775    private final int monthLength(int month, int year) {
2776        return isLeapYear(year) ? LEAP_MONTH_LENGTH[month] : MONTH_LENGTH[month];
2777    }
2778
2779    /**
2780     * Returns the length of the specified month in the year provided
2781     * by internalGet(YEAR).
2782     *
2783     * @see #isLeapYear(int)
2784     */

2785    private final int monthLength(int month) {
2786        int year = internalGet(YEAR);
2787        if (internalGetEra() == BCE) {
2788            year = 1 - year;
2789        }
2790        return monthLength(month, year);
2791    }
2792
2793    private final int actualMonthLength() {
2794        int year = cdate.getNormalizedYear();
2795    if (year != gregorianCutoverYear && year != gregorianCutoverYearJulian) {
2796        return calsys.getMonthLength(cdate);
2797    }
2798    BaseCalendar.Date date = (BaseCalendar.Date) cdate.clone();
2799    long fd = calsys.getFixedDate(date);
2800    long month1 = getFixedDateMonth1(date, fd);
2801    long next1 = month1 + calsys.getMonthLength(date);
2802    if (next1 < gregorianCutoverDate) {
2803        return (int)(next1 - month1);
2804    }
2805    if (cdate != gdate) {
2806        date = (BaseCalendar.Date) gcal.newCalendarDate(TimeZone.NO_TIMEZONE);
2807    }
2808    gcal.getCalendarDateFromFixedDate(date, next1);
2809    next1 = getFixedDateMonth1(date, next1);
2810    return (int)(next1 - month1);
2811    }
2812
2813    /**
2814     * Returns the length (in days) of the specified year. The year
2815     * must be normalized.
2816     */

2817    private final int yearLength(int year) {
2818        return isLeapYear(year) ? 366 : 365;
2819    }
2820
2821    /**
2822     * Returns the length (in days) of the year provided by
2823     * internalGet(YEAR).
2824     */

2825    private final int yearLength() {
2826        int year = internalGet(YEAR);
2827        if (internalGetEra() == BCE) {
2828            year = 1 - year;
2829        }
2830        return yearLength(year);
2831    }
2832
2833    /**
2834     * After adjustments such as add(MONTH), add(YEAR), we don't want the
2835     * month to jump around. E.g., we don't want Jan 31 + 1 month to go to Mar
2836     * 3, we want it to go to Feb 28. Adjustments which might run into this
2837     * problem call this method to retain the proper month.
2838     */

2839    private final void pinDayOfMonth() {
2840    int year = internalGet(YEAR);
2841    int monthLen;
2842    if (year > gregorianCutoverYear || year < gregorianCutoverYearJulian) {
2843        monthLen = monthLength(internalGet(MONTH));
2844    } else {
2845        GregorianCalendar JavaDoc gc = getNormalizedCalendar();
2846        monthLen = gc.getActualMaximum(DAY_OF_MONTH);
2847    }
2848    int dom = internalGet(DAY_OF_MONTH);
2849    if (dom > monthLen) {
2850        set(DAY_OF_MONTH, monthLen);
2851    }
2852    }
2853
2854    /**
2855     * Returns the fixed date value of this object. The time value and
2856     * calendar fields must be in synch.
2857     */

2858    private final long getCurrentFixedDate() {
2859    return (calsys == gcal) ? cachedFixedDate : calsys.getFixedDate(cdate);
2860    }
2861
2862    /**
2863     * Returns the new value after 'roll'ing the specified value and amount.
2864     */

2865    private static final int getRolledValue(int value, int amount, int min, int max) {
2866    assert value >= min && value <= max;
2867    int range = max - min + 1;
2868    amount %= range;
2869    int n = value + amount;
2870    if (n > max) {
2871        n -= range;
2872    } else if (n < min) {
2873        n += range;
2874    }
2875    assert n >= min && n <= max;
2876    return n;
2877    }
2878
2879    /**
2880     * Returns the ERA. We need a special method for this because the
2881     * default ERA is CE, but a zero (unset) ERA is BCE.
2882     */

2883    private final int internalGetEra() {
2884        return isSet(ERA) ? internalGet(ERA) : CE;
2885    }
2886
2887    /**
2888     * Updates internal state.
2889     */

2890    private void readObject(ObjectInputStream JavaDoc stream)
2891        throws IOException JavaDoc, ClassNotFoundException JavaDoc {
2892    stream.defaultReadObject();
2893    if (gdate == null) {
2894        gdate = (BaseCalendar.Date) gcal.newCalendarDate(getZone());
2895        cachedFixedDate = Long.MIN_VALUE;
2896    }
2897    setGregorianChange(gregorianCutover);
2898    }
2899}
2900
Popular Tags