Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: java/util/GregorianCalendar.java


1   /* java.util.GregorianCalendar
2      Copyright (C) 1998, 1999, 2001, 2002, 2003, 2004
3      Free Software Foundation, Inc.
4   
5   This file is part of GNU Classpath.
6   
7   GNU Classpath is free software; you can redistribute it and/or modify
8   it under the terms of the GNU General Public License as published by
9   the Free Software Foundation; either version 2, or (at your option)
10  any later version.
11  
12  GNU Classpath is distributed in the hope that it will be useful, but
13  WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  General Public License for more details.
16  
17  You should have received a copy of the GNU General Public License
18  along with GNU Classpath; see the file COPYING.  If not, write to the
19  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20  02110-1301 USA.
21  
22  Linking this library statically or dynamically with other modules is
23  making a combined work based on this library.  Thus, the terms and
24  conditions of the GNU General Public License cover the whole
25  combination.
26  
27  As a special exception, the copyright holders of this library give you
28  permission to link this library with independent modules to produce an
29  executable, regardless of the license terms of these independent
30  modules, and to copy and distribute the resulting executable under
31  terms of your choice, provided that you also meet, for each linked
32  independent module, the terms and conditions of the license of that
33  module.  An independent module is a module which is not derived from
34  or based on this library.  If you modify this library, you may extend
35  this exception to your version of the library, but you are not
36  obligated to do so.  If you do not wish to do so, delete this
37  exception statement from your version. */
38  
39  
40  package java.util;
41  
42  
43  /**
44   * <p>
45   * This class represents the Gregorian calendar, that is used in most
46   * countries all over the world.  It does also handle the Julian calendar
47   * for dates smaller than the date of the change to the Gregorian calendar.
48   * The Gregorian calendar differs from the Julian calendar by a different
49   * leap year rule (no leap year every 100 years, except if year is divisible
50   * by 400).
51   * </p>
52   * <p>
53   * This change date is different from country to country, and can be changed with
54   * <code>setGregorianChange</code>.  The first countries to adopt the Gregorian
55   * calendar did so on the 15th of October, 1582.  This date followed October
56   * the 4th, 1582 in the Julian calendar system.  The non-existant days that were
57   * omitted when the change took place are interpreted as Gregorian dates.
58   * </p>
59   * <p>
60   * Prior to the changeover date, New Year's Day occurred on the 25th of March.
61   * However, this class always takes New Year's Day as being the 1st of January.
62   * Client code should manually adapt the year value, if required, for dates
63   * between January the 1st and March the 24th in years prior to the changeover.
64   * </p>
65   * <p>
66   * Any date infinitely forwards or backwards in time can be represented by
67   * this class.  A <em>proleptic</em> calendar system is used, which allows
68   * future dates to be created via the existing rules.  This allows meaningful
69   * and consistent dates to be produced for all years.  However, dates are only
70   * historically accurate following March the 1st, 4AD when the Julian calendar
71   * system was adopted.  Prior to this, leap year rules were applied erraticly.
72   * </p>
73   * <p>
74   * There are two eras available for the Gregorian calendar, namely BC and AD.
75   * </p>
76   * <p>
77   * Weeks are defined as a period of seven days, beginning on the first day
78   * of the week, as returned by <code>getFirstDayOfWeek()</code>, and ending
79   * on the day prior to this.
80   * </p>
81   * <p>
82   * The weeks of the year are numbered from 1 to a possible 53.  The first week
83   * of the year is defined as the first week that contains at least the minimum
84   * number of days of the first week in the new year (retrieved via
85   * <code>getMinimalDaysInFirstWeek()</code>).  All weeks after this are numbered
86   * from 2 onwards.
87   * </p>
88   * <p>
89   * For example, take the year 2004.  It began on a Thursday.  The first week
90   * of 2004 depends both on where a week begins and how long it must minimally
91   * last.  Let's say that the week begins on a Monday and must have a minimum
92   * of 5 days.  In this case, the first week begins on Monday, the 5th of January.
93   * The first 4 days (Thursday to Sunday) are not eligible, as they are too few
94   * to make up the minimum number of days of the first week which must be in
95   * the new year.  If the minimum was lowered to 4 days, then the first week
96   * would instead begin on Monday, the 29th of December, 2003.  This first week
97   * has 4 of its days in the new year, and is now eligible.
98   * </p>
99   * <p>
100  * The weeks of the month are numbered from 0 to a possible 6.  The first week
101  * of the month (numbered 1) is a set of days, prior to the first day of the week,
102  * which number at least the minimum number of days in a week.  Unlike the first
103  * week of the year, the first week of the month only uses days from that particular
104  * month.  As a consequence, it may have a variable number of days (from the minimum
105  * number required up to a full week of 7) and it need not start on the first day of
106  * the week.  It must, however, be following by the first day of the week, as this
107  * marks the beginning of week 2.  Any days of the month which occur prior to the
108  * first week (because the first day of the week occurs before the minimum number
109  * of days is met) are seen as week 0.
110  * </p>
111  * <p>
112  * Again, we will take the example of the year 2004 to demonstrate this.  September
113  * 2004 begins on a Wednesday.  Taking our first day of the week as Monday, and the
114  * minimum length of the first week as 6, we find that week 1 runs from Monday,
115  * the 6th of September to Sunday the 12th.  Prior to the 6th, there are only
116  * 5 days (Wednesday through to Sunday).  This is too small a number to meet the
117  * minimum, so these are classed as being days in week 0.  Week 2 begins on the
118  * 13th, and so on.  This changes if we reduce the minimum to 5.  In this case,
119  * week 1 is a truncated week from Wednesday the 1st to Sunday the 5th, and week
120  * 0 doesn't exist.  The first seven day week is week 2, starting on the 6th.
121  * </p>
122  * <p>
123  * On using the <code>clear()</code> method, the Gregorian calendar returns
124  * to its default value of the 1st of January, 1970 AD 00:00:00 (the epoch).
125  * The day of the week is set to the correct day for that particular time.
126  * The day is also the first of the month, and the date is in week 0.
127  * </p>
128  *
129  * @see Calendar
130  * @see TimeZone
131  * @see Calendar#getFirstDayOfWeek()
132  * @see Calendar#getMinimalDaysInFirstWeek()
133  */
134 public class GregorianCalendar extends Calendar
135 {
136   /**
137    * Constant representing the era BC (Before Christ).
138    */
139   public static final int BC = 0;
140 
141   /**
142    * Constant representing the era AD (Anno Domini).
143    */
144   public static final int AD = 1;
145 
146   /**
147    * The point at which the Gregorian calendar rules were used.
148    * This may be changed by using setGregorianChange;
149    * The default is midnight (UTC) on October 5, 1582 (Julian),
150    * or October 15, 1582 (Gregorian).
151    *
152    * @serial the changeover point from the Julian calendar
153    *         system to the Gregorian.
154    */
155   private long gregorianCutover = (new Date((24 * 60 * 60 * 1000L) * (((1582 * (365 * 4
156                                             + 1)) / 4
157                                             + (java.util.Calendar.OCTOBER * (31
158                                             + 30 + 31 + 30 + 31) - 9) / 5 + 5)
159                                             - ((1970 * (365 * 4 + 1)) / 4 + 1
160                                             - 13)))).getTime();
161 
162   /**
163    * For compatability with Sun's JDK.
164    */
165   static final long serialVersionUID = -8125100834729963327L;
166 
167   /**
168    * Days in the epoch. Relative Jan 1, year '0' which is not a leap year.
169    * (although there is no year zero, this does not matter.)
170    * This is consistent with the formula:
171    * = (year-1)*365L + ((year-1) >> 2)
172    *
173    * Plus the gregorian correction:
174    *  Math.floor((year-1) / 400.) - Math.floor((year-1) / 100.);
175    * For a correct julian date, the correction is -2 instead.
176    *
177    * The gregorian cutover in 1582 was 10 days, so by calculating the
178    * correction from year zero, we have 15 non-leap days (even centuries)
179    * minus 3 leap days (year 400,800,1200) = 12. Subtracting two corrects
180    * this to the correct number 10.
181    */
182   private static final int EPOCH_DAYS = 719162;
183 
184   /**
185    * Constructs a new GregorianCalender representing the current
186    * time, using the default time zone and the default locale.
187    */
188   public GregorianCalendar()
189   {
190     this(TimeZone.getDefault(), Locale.getDefault());
191   }
192 
193   /**
194    * Constructs a new GregorianCalender representing the current
195    * time, using the specified time zone and the default locale.
196    *
197    * @param zone a time zone.
198    */
199   public GregorianCalendar(TimeZone zone)
200   {
201     this(zone, Locale.getDefault());
202   }
203 
204   /**
205    * Constructs a new GregorianCalender representing the current
206    * time, using the default time zone and the specified locale.
207    *
208    * @param locale a locale.
209    */
210   public GregorianCalendar(Locale locale)
211   {
212     this(TimeZone.getDefault(), locale);
213   }
214 
215   /**
216    * Constructs a new GregorianCalender representing the current
217    * time with the given time zone and the given locale.
218    *
219    * @param zone a time zone.
220    * @param locale a locale.
221    */
222   public GregorianCalendar(TimeZone zone, Locale locale)
223   {
224     this(zone, locale, false);
225     setTimeInMillis(System.currentTimeMillis());
226     complete();
227   }
228 
229   /**
230    * Common constructor that all constructors should call.
231    * @param zone a time zone.
232    * @param locale a locale.
233    * @param unused unused parameter to make the signature differ from
234    * the public constructor (TimeZone, Locale).
235    */
236   private GregorianCalendar(TimeZone zone, Locale locale, boolean unused)
237   {
238     super(zone, locale);
239   }
240 
241   /**
242    * Constructs a new GregorianCalendar representing midnight on the
243    * given date with the default time zone and locale.
244    *
245    * @param year corresponds to the YEAR time field.
246    * @param month corresponds to the MONTH time field.
247    * @param day corresponds to the DAY time field.
248    */
249   public GregorianCalendar(int year, int month, int day)
250   {
251     this(TimeZone.getDefault(), Locale.getDefault(), false);
252     set(year, month, day);
253   }
254 
255   /**
256    * Constructs a new GregorianCalendar representing midnight on the
257    * given date with the default time zone and locale.
258    *
259    * @param year corresponds to the YEAR time field.
260    * @param month corresponds to the MONTH time field.
261    * @param day corresponds to the DAY time field.
262    * @param hour corresponds to the HOUR_OF_DAY time field.
263    * @param minute corresponds to the MINUTE time field.
264    */
265   public GregorianCalendar(int year, int month, int day, int hour, int minute)
266   {
267     this(TimeZone.getDefault(), Locale.getDefault(), false);
268     set(year, month, day, hour, minute);
269   }
270 
271   /**
272    * Constructs a new GregorianCalendar representing midnight on the
273    * given date with the default time zone and locale.
274    *
275    * @param year corresponds to the YEAR time field.
276    * @param month corresponds to the MONTH time field.
277    * @param day corresponds to the DAY time field.
278    * @param hour corresponds to the HOUR_OF_DAY time field.
279    * @param minute corresponds to the MINUTE time field.
280    * @param second corresponds to the SECOND time field.
281    */
282   public GregorianCalendar(int year, int month, int day, int hour, int minute,
283                            int second)
284   {
285     this(TimeZone.getDefault(), Locale.getDefault(), false);
286     set(year, month, day, hour, minute, second);
287   }
288 
289   /**
290    * Sets the date of the switch from Julian dates to Gregorian dates.
291    * You can use <code>new Date(Long.MAX_VALUE)</code> to use a pure
292    * Julian calendar, or <code>Long.MIN_VALUE</code> for a pure Gregorian
293    * calendar.
294    *
295    * @param date the date of the change.
296    */
297   public void setGregorianChange(Date date)
298   {
299     gregorianCutover = date.getTime();
300   }
301 
302   /**
303    * Gets the date of the switch from Julian dates to Gregorian dates.
304    *
305    * @return the date of the change.
306    */
307   public final Date getGregorianChange()
308   {
309     return new Date(gregorianCutover);
310   }
311 
312   /**
313    * <p>
314    * Determines if the given year is a leap year.  The result is
315    * undefined if the Gregorian change took place in 1800, so that
316    * the end of February is skipped, and that year is specified.
317    * (well...).
318    * </p>
319    * <p>
320    * To specify a year in the BC era, use a negative value calculated
321    * as 1 - y, where y is the required year in BC.  So, 1 BC is 0,
322    * 2 BC is -1, 3 BC is -2, etc.
323    * </p>
324    *
325    * @param year a year (use a negative value for BC).
326    * @return true, if the given year is a leap year, false otherwise.
327    */
328   public boolean isLeapYear(int year)
329   {
330     // Only years divisible by 4 can be leap years
331     if ((year & 3) != 0)
332       return false;
333 
334     // Is the leap-day a Julian date? Then it's a leap year
335     if (! isGregorian(year, 31 + 29 - 1))
336       return true;
337 
338     // Apply gregorian rules otherwise
339     return ((year % 100) != 0 || (year % 400) == 0);
340   }
341 
342   /**
343    * Retrieves the day of the week corresponding to the specified
344    * day of the specified year.
345    *
346    * @param year the year in which the dayOfYear occurs.
347    * @param dayOfYear the day of the year (an integer between 0 and
348    *        and 366)
349    */
350   private int getWeekDay(int year, int dayOfYear)
351   {
352     boolean greg = isGregorian(year, dayOfYear);
353     int day = (int) getLinearDay(year, dayOfYear, greg);
354 
355     // The epoch was a thursday.
356     int weekday = (day + THURSDAY) % 7;
357     if (weekday <= 0)
358       weekday += 7;
359     return weekday;
360   }
361 
362   /**
363    * Returns the day of the week for the first day of a given month (0..11)
364    */
365   private int getFirstDayOfMonth(int year, int month)
366   {
367     int[] dayCount = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
368 
369     if (month > 11)
370       {
371   year += (month / 12);
372   month = month % 12;
373       }
374 
375     if (month < 0)
376       {
377   year += (int) month / 12;
378   month = month % 12;
379   if (month < 0)
380     {
381       month += 12;
382       year--;
383     }
384       }
385 
386     int dayOfYear = dayCount[month] + 1;
387     if (month > 1)
388       if (isLeapYear(year))
389   dayOfYear++;
390 
391     boolean greg = isGregorian(year, dayOfYear);
392     int day = (int) getLinearDay(year, dayOfYear, greg);
393 
394     // The epoch was a thursday.
395     int weekday = (day + THURSDAY) % 7;
396     if (weekday <= 0)
397       weekday += 7;
398     return weekday;
399   }
400 
401   /**
402    * Takes a year, and a (zero based) day of year and determines
403    * if it is gregorian or not.
404    */
405   private boolean isGregorian(int year, int dayOfYear)
406   {
407     int relativeDay = (year - 1) * 365 + ((year - 1) >> 2) + dayOfYear
408                       - EPOCH_DAYS; // gregorian days from 1 to epoch.
409     int gregFactor = (int) Math.floor((double) (year - 1) / 400.)
410                      - (int) Math.floor((double) (year - 1) / 100.);
411 
412     return ((relativeDay + gregFactor) * 60L * 60L * 24L * 1000L >= gregorianCutover);
413   }
414 
415   /**
416    * Check set fields for validity, without leniency.
417    *
418    * @throws IllegalArgumentException if a field is invalid
419    */
420   private void nonLeniencyCheck() throws IllegalArgumentException
421   {
422     int[] month_days = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
423     int year = fields[YEAR];
424     int month = fields[MONTH];
425     int leap = isLeapYear(year) ? 1 : 0;
426 
427     if (isSet[ERA] && fields[ERA] != AD && fields[ERA] != BC)
428       throw new IllegalArgumentException("Illegal ERA.");
429     if (isSet[YEAR] && fields[YEAR] < 1)
430       throw new IllegalArgumentException("Illegal YEAR.");
431     if (isSet[MONTH] && (month < 0 || month > 11))
432       throw new IllegalArgumentException("Illegal MONTH.");
433     if (isSet[WEEK_OF_YEAR])
434       {
435   int daysInYear = 365 + leap;
436   daysInYear += (getFirstDayOfMonth(year, 0) - 1); // pad first week
437   int last = getFirstDayOfMonth(year, 11) + 4;
438   if (last > 7)
439     last -= 7;
440   daysInYear += 7 - last;
441   int weeks = daysInYear / 7;
442   if (fields[WEEK_OF_YEAR] < 1 || fields[WEEK_OF_YEAR] > weeks)
443     throw new IllegalArgumentException("Illegal WEEK_OF_YEAR.");
444       }
445 
446     if (isSet[WEEK_OF_MONTH])
447       {
448   int weeks = (month == 1 && leap == 0) ? 4 : 5;
449   if (fields[WEEK_OF_MONTH] < 1 || fields[WEEK_OF_MONTH] > weeks)
450     throw new IllegalArgumentException("Illegal WEEK_OF_MONTH.");
451       }
452 
453     if (isSet[DAY_OF_MONTH])
454       if (fields[DAY_OF_MONTH] < 1
455           || fields[DAY_OF_MONTH] > month_days[month]
456           + ((month == 1) ? leap : 0))
457   throw new IllegalArgumentException("Illegal DAY_OF_MONTH.");
458 
459     if (isSet[DAY_OF_YEAR]
460         && (fields[DAY_OF_YEAR] < 1 || fields[DAY_OF_YEAR] > 365 + leap))
461       throw new IllegalArgumentException("Illegal DAY_OF_YEAR.");
462 
463     if (isSet[DAY_OF_WEEK]
464         && (fields[DAY_OF_WEEK] < 1 || fields[DAY_OF_WEEK] > 7))
465       throw new IllegalArgumentException("Illegal DAY_OF_WEEK.");
466 
467     if (isSet[DAY_OF_WEEK_IN_MONTH])
468       {
469   int weeks = (month == 1 && leap == 0) ? 4 : 5;
470   if (fields[DAY_OF_WEEK_IN_MONTH] < -weeks
471       || fields[DAY_OF_WEEK_IN_MONTH] > weeks)
472     throw new IllegalArgumentException("Illegal DAY_OF_WEEK_IN_MONTH.");
473       }
474 
475     if (isSet[AM_PM] && fields[AM_PM] != AM && fields[AM_PM] != PM)
476       throw new IllegalArgumentException("Illegal AM_PM.");
477     if (isSet[HOUR] && (fields[HOUR] < 0 || fields[HOUR] > 11))
478       throw new IllegalArgumentException("Illegal HOUR.");
479     if (isSet[HOUR_OF_DAY]
480         && (fields[HOUR_OF_DAY] < 0 || fields[HOUR_OF_DAY] > 23))
481       throw new IllegalArgumentException("Illegal HOUR_OF_DAY.");
482     if (isSet[MINUTE] && (fields[MINUTE] < 0 || fields[MINUTE] > 59))
483       throw new IllegalArgumentException("Illegal MINUTE.");
484     if (isSet[SECOND] && (fields[SECOND] < 0 || fields[SECOND] > 59))
485       throw new IllegalArgumentException("Illegal SECOND.");
486     if (isSet[MILLISECOND]
487         && (fields[MILLISECOND] < 0 || fields[MILLISECOND] > 999))
488       throw new IllegalArgumentException("Illegal MILLISECOND.");
489     if (isSet[ZONE_OFFSET]
490         && (fields[ZONE_OFFSET] < -12 * 60 * 60 * 1000L
491         || fields[ZONE_OFFSET] > 12 * 60 * 60 * 1000L))
492       throw new IllegalArgumentException("Illegal ZONE_OFFSET.");
493     if (isSet[DST_OFFSET]
494         && (fields[DST_OFFSET] < -12 * 60 * 60 * 1000L
495         || fields[DST_OFFSET] > 12 * 60 * 60 * 1000L))
496       throw new IllegalArgumentException("Illegal DST_OFFSET.");
497   }
498 
499   /**
500    * Converts the time field values (<code>fields</code>) to
501    * milliseconds since the epoch UTC (<code>time</code>).
502    *
503    * @throws IllegalArgumentException if any calendar fields
504    *         are invalid.
505    */
506   protected synchronized void computeTime()
507   {
508     int millisInDay = 0;
509     int era = fields[ERA];
510     int year = fields[YEAR];
511     int month = fields[MONTH];
512     int day = fields[DAY_OF_MONTH];
513 
514     int minute = fields[MINUTE];
515     int second = fields[SECOND];
516     int millis = fields[MILLISECOND];
517     int[] month_days = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
518     int[] dayCount = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
519     int hour = 0;
520 
521     if (! isLenient())
522       nonLeniencyCheck();
523 
524     if (! isSet[MONTH] && (! isSet[DAY_OF_WEEK] || isSet[WEEK_OF_YEAR]))
525       {
526   // 5: YEAR + DAY_OF_WEEK + WEEK_OF_YEAR
527   if (isSet[WEEK_OF_YEAR])
528     {
529       int first = getFirstDayOfMonth(year, 0);
530       int offs = 1;
531       int daysInFirstWeek = getFirstDayOfWeek() - first;
532       if (daysInFirstWeek <= 0)
533         daysInFirstWeek += 7;
534 
535       if (daysInFirstWeek < getMinimalDaysInFirstWeek())
536         offs += daysInFirstWeek;
537       else
538         offs -= 7 - daysInFirstWeek;
539       month = 0;
540       day = offs + 7 * (fields[WEEK_OF_YEAR] - 1);
541       offs = fields[DAY_OF_WEEK] - getFirstDayOfWeek();
542 
543       if (offs < 0)
544         offs += 7;
545       day += offs;
546     }
547   else
548     {
549       // 4:  YEAR + DAY_OF_YEAR
550       month = 0;
551       day = fields[DAY_OF_YEAR];
552     }
553       }
554     else
555       {
556   if (isSet[DAY_OF_WEEK])
557     {
558       int first = getFirstDayOfMonth(year, month);
559 
560       // 3: YEAR + MONTH + DAY_OF_WEEK_IN_MONTH + DAY_OF_WEEK
561       if (isSet[DAY_OF_WEEK_IN_MONTH])
562         {
563     if (fields[DAY_OF_WEEK_IN_MONTH] < 0)
564       {
565         month++;
566         first = getFirstDayOfMonth(year, month);
567         day = 1 + 7 * (fields[DAY_OF_WEEK_IN_MONTH]);
568       }
569     else
570       day = 1 + 7 * (fields[DAY_OF_WEEK_IN_MONTH] - 1);
571 
572     int offs = fields[DAY_OF_WEEK] - first;
573     if (offs < 0)
574       offs += 7;
575     day += offs;
576         }
577       else
578         { // 2: YEAR + MONTH + WEEK_OF_MONTH + DAY_OF_WEEK
579     int offs = 1;
580     int daysInFirstWeek = getFirstDayOfWeek() - first;
581     if (daysInFirstWeek <= 0)
582       daysInFirstWeek += 7;
583 
584     if (daysInFirstWeek < getMinimalDaysInFirstWeek())
585       offs += daysInFirstWeek;
586     else
587       offs -= 7 - daysInFirstWeek;
588 
589     day = offs + 7 * (fields[WEEK_OF_MONTH] - 1);
590     offs = fields[DAY_OF_WEEK] - getFirstDayOfWeek();
591     if (offs <= 0)
592       offs += 7;
593     day += offs;
594         }
595     }
596 
597   // 1:  YEAR + MONTH + DAY_OF_MONTH
598       }
599     if (era == BC && year > 0)
600       year = 1 - year;
601 
602     // rest of code assumes day/month/year set
603     // should negative BC years be AD?
604     // get the hour (but no check for validity)
605     if (isSet[HOUR])
606       {
607   hour = fields[HOUR];
608   if (fields[AM_PM] == PM)
609     hour += 12;
610       }
611     else
612       hour = fields[HOUR_OF_DAY];
613 
614     // Read the era,year,month,day fields and convert as appropriate.
615     // Calculate number of milliseconds into the day
616     // This takes care of both h, m, s, ms over/underflows.
617     long allMillis = (((hour * 60L) + minute) * 60L + second) * 1000L + millis;
618     day += allMillis / (24 * 60 * 60 * 1000L);
619     millisInDay = (int) (allMillis % (24 * 60 * 60 * 1000L));
620 
621     if (month < 0)
622       {
623   year += (int) month / 12;
624   month = month % 12;
625   if (month < 0)
626     {
627       month += 12;
628       year--;
629     }
630       }
631     if (month > 11)
632       {
633   year += (month / 12);
634   month = month % 12;
635       }
636 
637     month_days[1] = isLeapYear(year) ? 29 : 28;
638 
639     while (day <= 0)
640       {
641   if (month == 0)
642     {
643       year--;
644       month_days[1] = isLeapYear(year) ? 29 : 28;
645     }
646   month = (month + 11) % 12;
647   day += month_days[month];
648       }
649     while (day > month_days[month])
650       {
651   day -= (month_days[month]);
652   month = (month + 1) % 12;
653   if (month == 0)
654     {
655       year++;
656       month_days[1] = isLeapYear(year) ? 29 : 28;
657     }
658       }
659 
660     // ok, by here we have valid day,month,year,era and millisinday
661     int dayOfYear = dayCount[month] + day - 1; // (day starts on 1)
662     if (isLeapYear(year) && month > 1)
663       dayOfYear++;
664 
665     int relativeDay = (year - 1) * 365 + ((year - 1) >> 2) + dayOfYear
666                       - EPOCH_DAYS; // gregorian days from 1 to epoch.
667     int gregFactor = (int) Math.floor((double) (year - 1) / 400.)
668                      - (int) Math.floor((double) (year - 1) / 100.);
669 
670     if ((relativeDay + gregFactor) * 60L * 60L * 24L * 1000L >= gregorianCutover)
671       relativeDay += gregFactor;
672     else
673       relativeDay -= 2;
674 
675     time = relativeDay * (24 * 60 * 60 * 1000L) + millisInDay;
676 
677     // the epoch was a Thursday.
678     int weekday = (int) (relativeDay + THURSDAY) % 7;
679     if (weekday <= 0)
680       weekday += 7;
681     fields[DAY_OF_WEEK] = weekday;
682 
683     // Time zone corrections.
684     TimeZone zone = getTimeZone();
685     int rawOffset = isSet[ZONE_OFFSET] ? fields[ZONE_OFFSET]
686                                        : zone.getRawOffset();
687 
688     int dstOffset = isSet[DST_OFFSET] ? fields[DST_OFFSET]
689                                       : (zone.getOffset((year < 0) ? BC : AD,
690                                                         (year < 0) ? 1 - year
691                                                                    : year,
692                                                         month, day, weekday,
693                                                         millisInDay)
694                                       - zone.getRawOffset());
695 
696     time -= rawOffset + dstOffset;
697 
698     isTimeSet = true;
699   }
700 
701   /**
702    * Get the linear day in days since the epoch, using the
703    * Julian or Gregorian calendar as specified.  If you specify a
704    * nonpositive year it is interpreted as BC as following: 0 is 1
705    * BC, -1 is 2 BC and so on.
706    *
707    * @param year the year of the date.
708    * @param dayOfYear the day of year of the date; 1 based.
709    * @param gregorian <code>true</code>, if we should use the Gregorian rules.
710    * @return the days since the epoch, may be negative.
711    */
712   private long getLinearDay(int year, int dayOfYear, boolean gregorian)
713   {
714     // The 13 is the number of days, that were omitted in the Gregorian
715     // Calender until the epoch.
716     // We shift right by 2 instead of dividing by 4, to get correct
717     // results for negative years (and this is even more efficient).
718     long julianDay = (year - 1) * 365L + ((year - 1) >> 2) + (dayOfYear - 1)
719                      - EPOCH_DAYS; // gregorian days from 1 to epoch.
720 
721     if (gregorian)
722       {
723   // subtract the days that are missing in gregorian calendar
724   // with respect to julian calendar.
725   //
726   // Okay, here we rely on the fact that the gregorian
727   // calendar was introduced in the AD era.  This doesn't work
728   // with negative years.
729   //
730   // The additional leap year factor accounts for the fact that
731   // a leap day is not seen on Jan 1 of the leap year.
732   int gregOffset = (int) Math.floor((double) (year - 1) / 400.)
733                    - (int) Math.floor((double) (year - 1) / 100.);
734 
735   return julianDay + gregOffset;
736       }
737     else
738       julianDay -= 2;
739     return julianDay;
740   }
741 
742   /**
743    * Converts the given linear day into era, year, month,
744    * day_of_year, day_of_month, day_of_week, and writes the result
745    * into the fields array.
746    *
747    * @param day the linear day.
748    * @param gregorian true, if we should use Gregorian rules.
749    */
750   private void calculateDay(int[] fields, long day, boolean gregorian)
751   {
752     // the epoch was a Thursday.
753     int weekday = (int) (day + THURSDAY) % 7;
754     if (weekday <= 0)
755       weekday += 7;
756     fields[DAY_OF_WEEK] = weekday;
757 
758     // get a first approximation of the year.  This may be one 
759     // year too big.
760     int year = 1970
761                + (int) (gregorian
762                         ? ((day - 100L) * 400L) / (365L * 400L + 100L - 4L
763                         + 1L) : ((day - 100L) * 4L) / (365L * 4L + 1L));
764     if (day >= 0)
765       year++;
766 
767     long firstDayOfYear = getLinearDay(year, 1, gregorian);
768 
769     // Now look in which year day really lies.
770     if (day < firstDayOfYear)
771       {
772   year--;
773   firstDayOfYear = getLinearDay(year, 1, gregorian);
774       }
775 
776     day -= firstDayOfYear - 1; // day of year,  one based.
777 
778     fields[DAY_OF_YEAR] = (int) day;
779     if (year <= 0)
780       {
781   fields[ERA] = BC;
782   fields[YEAR] = 1 - year;
783       }
784     else
785       {
786   fields[ERA] = AD;
787   fields[YEAR] = year;
788       }
789 
790     int leapday = isLeapYear(year) ? 1 : 0;
791     if (day <= 31 + 28 + leapday)
792       {
793   fields[MONTH] = (int) day / 32; // 31->JANUARY, 32->FEBRUARY
794   fields[DAY_OF_MONTH] = (int) day - 31 * fields[MONTH];
795       }
796     else
797       {
798   // A few more magic formulas
799   int scaledDay = ((int) day - leapday) * 5 + 8;
800   fields[MONTH] = scaledDay / (31 + 30 + 31 + 30 + 31);
801   fields[DAY_OF_MONTH] = (scaledDay % (31 + 30 + 31 + 30 + 31)) / 5 + 1;
802       }
803   }
804 
805   /**
806    * Converts the milliseconds since the epoch UTC
807    * (<code>time</code>) to time fields
808    * (<code>fields</code>).
809    */
810   protected synchronized void computeFields()
811   {
812     boolean gregorian = (time >= gregorianCutover);
813 
814     TimeZone zone = getTimeZone();
815     fields[ZONE_OFFSET] = zone.getRawOffset();
816     long localTime = time + fields[ZONE_OFFSET];
817 
818     long day = localTime / (24 * 60 * 60 * 1000L);
819     int millisInDay = (int) (localTime % (24 * 60 * 60 * 1000L));
820 
821     if (millisInDay < 0)
822       {
823   millisInDay += (24 * 60 * 60 * 1000);
824   day--;
825       }
826 
827     calculateDay(fields, day, gregorian);
828     fields[DST_OFFSET] = zone.getOffset(fields[ERA], fields[YEAR],
829                                         fields[MONTH], fields[DAY_OF_MONTH],
830                                         fields[DAY_OF_WEEK], millisInDay)
831                          - fields[ZONE_OFFSET];
832 
833     millisInDay += fields[DST_OFFSET];
834     if (millisInDay >= 24 * 60 * 60 * 1000)
835       {
836   millisInDay -= 24 * 60 * 60 * 1000;
837   calculateDay(fields, ++day, gregorian);
838       }
839 
840     fields[DAY_OF_WEEK_IN_MONTH] = (fields[DAY_OF_MONTH] + 6) / 7;
841 
842     // which day of the week are we (0..6), relative to getFirstDayOfWeek
843     int relativeWeekday = (7 + fields[DAY_OF_WEEK] - getFirstDayOfWeek()) % 7;
844 
845     fields[WEEK_OF_MONTH] = (fields[DAY_OF_MONTH] - relativeWeekday + 12) / 7;
846 
847     int weekOfYear = (fields[DAY_OF_YEAR] - relativeWeekday + 6) / 7;
848 
849     // Do the Correction: getMinimalDaysInFirstWeek() is always in the 
850     // first week.
851     int minDays = getMinimalDaysInFirstWeek();
852     int firstWeekday = (7 + getWeekDay(fields[YEAR], minDays)
853                        - getFirstDayOfWeek()) % 7;
854     if (minDays - firstWeekday < 1)
855       weekOfYear++;
856     fields[WEEK_OF_YEAR] = weekOfYear;
857 
858     int hourOfDay = millisInDay / (60 * 60 * 1000);
859     fields[AM_PM] = (hourOfDay < 12) ? AM : PM;
860     int hour = hourOfDay % 12;
861     fields[HOUR] = hour;
862     fields[HOUR_OF_DAY] = hourOfDay;
863     millisInDay %= (60 * 60 * 1000);
864     fields[MINUTE] = millisInDay / (60 * 1000);
865     millisInDay %= (60 * 1000);
866     fields[SECOND] = millisInDay / (1000);
867     fields[MILLISECOND] = millisInDay % 1000;
868 
869     areFieldsSet = isSet[ERA] = isSet[YEAR] = isSet[MONTH] = isSet[WEEK_OF_YEAR] = isSet[WEEK_OF_MONTH] = isSet[DAY_OF_MONTH] = isSet[DAY_OF_YEAR] = isSet[DAY_OF_WEEK] = isSet[DAY_OF_WEEK_IN_MONTH] = isSet[AM_PM] = isSet[HOUR] = isSet[HOUR_OF_DAY] = isSet[MINUTE] = isSet[SECOND] = isSet[MILLISECOND] = isSet[ZONE_OFFSET] = isSet[DST_OFFSET] = true;
870   }
871 
872   /**
873    * Compares the given calendar with this.  An object, o, is
874    * equivalent to this if it is also a <code>GregorianCalendar</code>
875    * with the same time since the epoch under the same conditions
876    * (same change date and same time zone).
877    *
878    * @param o the object to that we should compare.
879    * @return true, if the given object is a calendar, that represents
880    * the same time (but doesn't necessarily have the same fields).
881    * @throws IllegalArgumentException if one of the fields
882    *         <code>ZONE_OFFSET</code> or <code>DST_OFFSET</code> is
883    *         specified, if an unknown field is specified or if one
884    *         of the calendar fields receives an illegal value when
885    *         leniancy is not enabled.
886    */
887   public boolean equals(Object o)
888   {
889     if (! (o instanceof GregorianCalendar))
890       return false;
891 
892     GregorianCalendar cal = (GregorianCalendar) o;
893     return (cal.getTimeInMillis() == getTimeInMillis());
894   }
895 
896   /**
897    * Adds the specified amount of time to the given time field.  The
898    * amount may be negative to subtract the time.  If the field overflows
899    * it does what you expect: Jan, 25 + 10 Days is Feb, 4.
900    * @param field one of the time field constants.
901    * @param amount the amount of time to add.
902    * @exception IllegalArgumentException if <code>field</code> is
903    *   <code>ZONE_OFFSET</code>, <code>DST_OFFSET</code>, or invalid; or
904    *   if <code>amount</code> contains an out-of-range value and the calendar
905    *   is not in lenient mode.
906    */
907   public void add(int field, int amount)
908   {
909     switch (field)
910       {
911       case YEAR:
912   complete();
913   fields[YEAR] += amount;
914   isTimeSet = false;
915   break;
916       case MONTH:
917   complete();
918   int months = fields[MONTH] + amount;
919   fields[YEAR] += months / 12;
920   fields[MONTH] = months % 12;
921   if (fields[MONTH] < 0)
922     {
923       fields[MONTH] += 12;
924       fields[YEAR]--;
925     }
926   int maxDay = getActualMaximum(DAY_OF_MONTH);
927   if (fields[DAY_OF_MONTH] > maxDay)
928     fields[DAY_OF_MONTH] = maxDay;
929   set(YEAR, fields[YEAR]);
930   set(MONTH, fields[MONTH]);
931   break;
932       case DAY_OF_MONTH:
933       case DAY_OF_YEAR:
934       case DAY_OF_WEEK:
935   if (! isTimeSet)
936     computeTime();
937   time += amount * (24 * 60 * 60 * 1000L);
938   areFieldsSet = false;
939   break;
940       case WEEK_OF_YEAR:
941       case WEEK_OF_MONTH:
942       case DAY_OF_WEEK_IN_MONTH:
943   if (! isTimeSet)
944     computeTime();
945   time += amount * (7 * 24 * 60 * 60 * 1000L);
946   areFieldsSet = false;
947   break;
948       case AM_PM:
949   if (! isTimeSet)
950     computeTime();
951   time += amount * (12 * 60 * 60 * 1000L);
952   areFieldsSet = false;
953   break;
954       case HOUR:
955       case HOUR_OF_DAY:
956   if (! isTimeSet)
957     computeTime();
958   time += amount * (60 * 60 * 1000L);
959   areFieldsSet = false;
960   break;
961       case MINUTE:
962   if (! isTimeSet)
963     computeTime();
964   time += amount * (60 * 1000L);
965   areFieldsSet = false;
966   break;
967       case SECOND:
968   if (! isTimeSet)
969     computeTime();
970   time += amount * (1000L);
971   areFieldsSet = false;
972   break;
973       case MILLISECOND:
974   if (! isTimeSet)
975     computeTime();
976   time += amount;
977   areFieldsSet = false;
978   break;
979       case ZONE_OFFSET:
980       case DST_OFFSET:default:
981   throw new IllegalArgumentException("Invalid or unknown field");
982       }
983   }
984 
985   /**
986    * Rolls the specified time field up or down.  This means add one
987    * to the specified field, but don't change the other fields.  If
988    * the maximum for this field is reached, start over with the
989    * minimum value.
990    *
991    * <strong>Note:</strong> There may be situation, where the other
992    * fields must be changed, e.g rolling the month on May, 31.
993    * The date June, 31 is automatically converted to July, 1.
994    * This requires lenient settings.
995    *
996    * @param field the time field. One of the time field constants.
997    * @param up the direction, true for up, false for down.
998    * @throws IllegalArgumentException if one of the fields
999    *         <code>ZONE_OFFSET</code> or <code>DST_OFFSET</code> is
1000   *         specified, if an unknown field is specified or if one
1001   *         of the calendar fields receives an illegal value when
1002   *         leniancy is not enabled.
1003   */
1004  public void roll(int field, boolean up)
1005  {
1006    roll(field, up ? 1 : -1);
1007  }
1008
1009  /**
1010   * Checks that the fields are still within their legal bounds,
1011   * following use of the <code>roll()</code> method.
1012   *
1013   * @param field the field to check.
1014   * @param delta multipler for alterations to the <code>time</code>.
1015   * @see #roll(int, boolean)
1016   * @see #roll(int, int)
1017   */
1018  private void cleanUpAfterRoll(int field, int delta)
1019  {
1020    switch (field)
1021      {
1022      case ERA:
1023      case YEAR:
1024      case MONTH:
1025  // check that day of month is still in correct range
1026  if (fields[DAY_OF_MONTH] > getActualMaximum(DAY_OF_MONTH))
1027    fields[DAY_OF_MONTH] = getActualMaximum(DAY_OF_MONTH);
1028  isTimeSet = false;
1029  isSet[WEEK_OF_MONTH] = false;
1030  isSet[DAY_OF_WEEK] = false;
1031  isSet[DAY_OF_WEEK_IN_MONTH] = false;
1032  isSet[DAY_OF_YEAR] = false;
1033  isSet[WEEK_OF_YEAR] = false;
1034  break;
1035      case DAY_OF_MONTH:
1036  isSet[WEEK_OF_MONTH] = false;
1037  isSet[DAY_OF_WEEK] = false;
1038  isSet[DAY_OF_WEEK_IN_MONTH] = false;
1039  isSet[DAY_OF_YEAR] = false;
1040  isSet[WEEK_OF_YEAR] = false;
1041  time += delta * (24 * 60 * 60 * 1000L);
1042  break;
1043      case WEEK_OF_MONTH:
1044  isSet[DAY_OF_MONTH] = false;
1045  isSet[DAY_OF_WEEK_IN_MONTH] = false;
1046  isSet[DAY_OF_YEAR] = false;
1047  isSet[WEEK_OF_YEAR] = false;
1048  time += delta * (7 * 24 * 60 * 60 * 1000L);
1049  break;
1050      case DAY_OF_WEEK_IN_MONTH:
1051  isSet[DAY_OF_MONTH] = false;
1052  isSet[WEEK_OF_MONTH] = false;
1053  isSet[DAY_OF_YEAR] = false;
1054  isSet[WEEK_OF_YEAR] = false;
1055  time += delta * (7 * 24 * 60 * 60 * 1000L);
1056  break;
1057      case DAY_OF_YEAR:
1058  isSet[MONTH] = false;
1059  isSet[DAY_OF_MONTH] = false;
1060  isSet[WEEK_OF_MONTH] = false;
1061  isSet[DAY_OF_WEEK_IN_MONTH] = false;
1062  isSet[DAY_OF_WEEK] = false;
1063  isSet[WEEK_OF_YEAR] = false;
1064  time += delta * (24 * 60 * 60 * 1000L);
1065  break;
1066      case WEEK_OF_YEAR:
1067  isSet[MONTH] = false;
1068  isSet[DAY_OF_MONTH] = false;
1069  isSet[WEEK_OF_MONTH] = false;
1070  isSet[DAY_OF_WEEK_IN_MONTH] = false;
1071  isSet[DAY_OF_YEAR] = false;
1072  time += delta * (7 * 24 * 60 * 60 * 1000L);
1073  break;
1074      case AM_PM:
1075  isSet[HOUR_OF_DAY] = false;
1076  time += delta * (12 * 60 * 60 * 1000L);
1077  break;
1078      case HOUR:
1079  isSet[HOUR_OF_DAY] = false;
1080  time += delta * (60 * 60 * 1000L);
1081  break;
1082      case HOUR_OF_DAY:
1083  isSet[HOUR] = false;
1084  isSet[AM_PM] = false;
1085  time += delta * (60 * 60 * 1000L);
1086  break;
1087      case MINUTE:
1088  time += delta * (60 * 1000L);
1089  break;
1090      case SECOND:
1091  time += delta * (1000L);
1092  break;
1093      case MILLISECOND:
1094  time += delta;
1095  break;
1096      }
1097  }
1098
1099  /**
1100   * Rolls the specified time field by the given amount.  This means
1101   * add amount to the specified field, but don't change the other
1102   * fields.  If the maximum for this field is reached, start over
1103   * with the minimum value and vice versa for negative amounts.
1104   *
1105   * <strong>Note:</strong> There may be situation, where the other
1106   * fields must be changed, e.g rolling the month on May, 31.
1107   * The date June, 31 is automatically corrected to June, 30.
1108   *
1109   * @param field the time field. One of the time field constants.
1110   * @param amount the amount by which we should roll.
1111   * @throws IllegalArgumentException if one of the fields
1112   *         <code>ZONE_OFFSET</code> or <code>DST_OFFSET</code> is
1113   *         specified, if an unknown field is specified or if one
1114   *         of the calendar fields receives an illegal value when
1115   *         leniancy is not enabled.
1116   */
1117  public void roll(int field, int amount)
1118  {
1119    switch (field)
1120      {
1121      case DAY_OF_WEEK:
1122  // day of week is special: it rolls automatically
1123  add(field, amount);
1124  return;
1125      case ZONE_OFFSET:
1126      case DST_OFFSET:
1127  throw new IllegalArgumentException("Can't roll time zone");
1128      }
1129    complete();
1130    int min = getActualMinimum(field);
1131    int range = getActualMaximum(field) - min + 1;
1132    int oldval = fields[field];
1133    int newval = (oldval - min + range + amount) % range + min;
1134    if (newval < min)
1135      newval += range;
1136    fields[field] = newval;
1137    cleanUpAfterRoll(field, newval - oldval);
1138  }
1139
1140  /**
1141   * The minimum values for the calendar fields.
1142   */
1143  private static final int[] minimums = 
1144                                        {
1145                                          BC, 1, 0, 0, 1, 1, 1, SUNDAY, 1, AM,
1146                                          1, 0, 0, 0, 0, -(12 * 60 * 60 * 1000),
1147                                          0
1148                                        };
1149
1150  /**
1151   * The maximum values for the calendar fields.
1152   */
1153  private static final int[] maximums = 
1154                                        {
1155                                          AD, 5000000, 11, 53, 5, 31, 366,
1156                                          SATURDAY, 5, PM, 12, 23, 59, 59, 999,
1157                                          +(12 * 60 * 60 * 1000),
1158                                          (12 * 60 * 60 * 1000)
1159                                        };
1160
1161  /**
1162   * Gets the smallest value that is allowed for the specified field.
1163   *
1164   * @param field one of the time field constants.
1165   * @return the smallest value for the specified field.
1166   */
1167  public int getMinimum(int field)
1168  {
1169    return minimums[field];
1170  }
1171
1172  /**
1173   * Gets the biggest value that is allowed for the specified field.
1174   *
1175   * @param field one of the time field constants.
1176   * @return the biggest value.
1177   */
1178  public int getMaximum(int field)
1179  {
1180    return maximums[field];
1181  }
1182
1183  /**
1184   * Gets the greatest minimum value that is allowed for the specified field.
1185   * This is the largest value returned by the <code>getActualMinimum(int)</code>
1186   * method.
1187   *
1188   * @param field the time field. One of the time field constants.
1189   * @return the greatest minimum value.
1190   * @see #getActualMinimum(int)
1191   */
1192  public int getGreatestMinimum(int field)
1193  {
1194    if (field == WEEK_OF_YEAR)
1195      return 1;
1196    return minimums[field];
1197  }
1198
1199  /**
1200   * Gets the smallest maximum value that is allowed for the
1201   * specified field.  This is the smallest value returned
1202   * by the <code>getActualMaximum(int)</code>.  For example,
1203   * this is 28 for DAY_OF_MONTH (as all months have at least
1204   * 28 days).
1205   *
1206   * @param field the time field. One of the time field constants.
1207   * @return the least maximum value.
1208   * @see #getActualMaximum(int)
1209   * @since 1.2
1210   */
1211  public int getLeastMaximum(int field)
1212  {
1213    switch (field)
1214      {
1215      case WEEK_OF_YEAR:
1216  return 52;
1217      case DAY_OF_MONTH:
1218  return 28;
1219      case DAY_OF_YEAR:
1220  return 365;
1221      case DAY_OF_WEEK_IN_MONTH:
1222      case WEEK_OF_MONTH:
1223  return 4;
1224      default:
1225  return maximums[field];
1226      }
1227  }
1228
1229  /**
1230   * Gets the actual minimum value that is allowed for the specified field.
1231   * This value is dependent on the values of the other fields.  Note that
1232   * this calls <code>complete()</code> if not enough fields are set.  This
1233   * can have ugly side effects.  The value given depends on the current
1234   * time used by this instance.
1235   *
1236   * @param field the time field. One of the time field constants.
1237   * @return the actual minimum value.
1238   * @since 1.2
1239   */
1240  public int getActualMinimum(int field)
1241  {
1242    if (field == WEEK_OF_YEAR)
1243      {
1244  int min = getMinimalDaysInFirstWeek();
1245  if (min == 0)
1246    return 1;
1247  if (! areFieldsSet || ! isSet[ERA] || ! isSet[YEAR])
1248    complete();
1249
1250  int year = fields[ERA] == AD ? fields[YEAR] : 1 - fields[YEAR];
1251  int weekday = getWeekDay(year, min);
1252  if ((7 + weekday - getFirstDayOfWeek()) % 7 >= min - 1)
1253    return 1;
1254  return 0;
1255      }
1256    return minimums[field];
1257  }
1258
1259  /**
1260   * Gets the actual maximum value that is allowed for the specified field.
1261   * This value is dependent on the values of the other fields.  Note that
1262   * this calls <code>complete()</code> if not enough fields are set.  This
1263   * can have ugly side effects.  The value given depends on the current time
1264   * used by this instance; thus, leap years have a maximum day of month value of
1265   * 29, rather than 28.
1266   *
1267   * @param field the time field. One of the time field constants.
1268   * @return the actual maximum value.
1269   */
1270  public int getActualMaximum(int field)
1271  {
1272    switch (field)
1273      {
1274      case WEEK_OF_YEAR:
1275        {
1276    if (! areFieldsSet || ! isSet[ERA] || ! isSet[YEAR])
1277      complete();
1278
1279    // This is wrong for the year that contains the gregorian change.
1280    // I.e it gives the weeks in the julian year or in the gregorian
1281    // year in that case.
1282    int year = fields[ERA] == AD ? fields[YEAR] : 1 - fields[YEAR];
1283    int lastDay = isLeapYear(year) ? 366 : 365;
1284    int weekday = getWeekDay(year, lastDay);
1285    int week = (lastDay + 6 - (7 + weekday - getFirstDayOfWeek()) % 7) / 7;
1286
1287    int minimalDays = getMinimalDaysInFirstWeek();
1288    int firstWeekday = getWeekDay(year, minimalDays);
1289    /*
1290     * Is there a set of days at the beginning of the year, before the
1291     * first day of the week, equal to or greater than the minimum number
1292     * of days required in the first week?
1293     */
1294    if (minimalDays - (7 + firstWeekday - getFirstDayOfWeek()) % 7 < 1)
1295      return week + 1; /* Add week 1: firstWeekday through to firstDayOfWeek */
1296        }
1297      case DAY_OF_MONTH:
1298        {
1299    if (! areFieldsSet || ! isSet[MONTH])
1300      complete();
1301    int month = fields[MONTH];
1302
1303    // If you change this, you should also change 
1304    // SimpleTimeZone.getDaysInMonth();
1305    if (month == FEBRUARY)
1306      {
1307        if (! isSet[YEAR] || ! isSet[ERA])
1308    complete();
1309        int year = fields[ERA] == AD ? fields[YEAR] : 1 - fields[YEAR];
1310        return isLeapYear(year) ? 29 : 28;
1311      }
1312    else if (month < AUGUST)
1313      return 31 - (month & 1);
1314    else
1315      return 30 + (month & 1);
1316        }
1317      case DAY_OF_YEAR:
1318        {
1319    if (! areFieldsSet || ! isSet[ERA] || ! isSet[YEAR])
1320      complete();
1321    int year = fields[ERA] == AD ? fields[YEAR] : 1 - fields[YEAR];
1322    return isLeapYear(year) ? 366 : 365;
1323        }
1324      case DAY_OF_WEEK_IN_MONTH:
1325        {
1326    // This is wrong for the month that contains the gregorian change.
1327    int daysInMonth = getActualMaximum(DAY_OF_MONTH);
1328
1329    // That's black magic, I know
1330    return (daysInMonth - (fields[DAY_OF_MONTH] - 1) % 7 + 6) / 7;
1331        }
1332      case WEEK_OF_MONTH:
1333        {
1334    int daysInMonth = getActualMaximum(DAY_OF_MONTH);
1335    int weekday = (daysInMonth - fields[DAY_OF_MONTH]
1336                  + fields[DAY_OF_WEEK] - SUNDAY) % 7 + SUNDAY;
1337    return (daysInMonth + 6 - (7 + weekday - getFirstDayOfWeek()) % 7) / 7;
1338        }
1339      default:
1340  return maximums[field];
1341      }
1342  }
1343}