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