home *** CD-ROM | disk | FTP | other *** search
/ Chip 1998 November / Chip_1998-11_cd.bin / tema / Cafe / main.bin / GregorianCalendar.java < prev    next >
Text File  |  1997-10-01  |  61KB  |  1,481 lines

  1. /*
  2.  * @(#)GregorianCalendar.java    1.21 97/07/15
  3.  *
  4.  * (C) Copyright Taligent, Inc. 1996-1997 - All Rights Reserved
  5.  * (C) Copyright IBM Corp. 1996-1997 - All Rights Reserved
  6.  *
  7.  * Portions copyright (c) 1996 Sun Microsystems, Inc. All Rights Reserved.
  8.  *
  9.  *   The original version of this source code and documentation is copyrighted
  10.  * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
  11.  * materials are provided under terms of a License Agreement between Taligent
  12.  * and Sun. This technology is protected by multiple US and International
  13.  * patents. This notice and attribution to Taligent may not be removed.
  14.  *   Taligent is a registered trademark of Taligent, Inc.
  15.  *
  16.  * Permission to use, copy, modify, and distribute this software
  17.  * and its documentation for NON-COMMERCIAL purposes and without
  18.  * fee is hereby granted provided that this copyright notice
  19.  * appears in all copies. Please refer to the file "copyright.html"
  20.  * for further important copyright and licensing information.
  21.  *
  22.  * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF
  23.  * THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
  24.  * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
  25.  * PARTICULAR PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR
  26.  * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
  27.  * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.
  28.  *
  29.  */
  30.  
  31. package java.util;
  32.  
  33. /**
  34.  * <code>GregorianCalendar</code> is a concrete subclass of
  35.  * <a href="java.util.Calendar.html"><code>Calendar</code></a>
  36.  * and provides the standard calendar used by most of the world.
  37.  *
  38.  * <p>
  39.  * The standard (Gregorian) calendar has 2 eras, BC and AD.
  40.  *
  41.  * <p>
  42.  * This implementation handles a single discontinuity, which corresponds
  43.  * by default to the date the Gregorian calendar was instituted (October 15,
  44.  * 1582 in some countries, later in others). This cutover date may be changed
  45.  * by the caller.
  46.  *
  47.  * <p>
  48.  * Prior to the institution of the Gregorian calendar, New Year's Day was
  49.  * March 25. To avoid confusion, this calendar always uses January 1. A manual
  50.  * adjustment may be made if desired for dates that are prior to the Gregorian
  51.  * changeover and which fall between January 1 and March 24.
  52.  *
  53.  * <p>
  54.  * The current implementation handles dates in a wide range, from
  55.  * 4716 BC up to 5000000 AD. Dates outside of that range
  56.  * will throw an IllegalArgumentException. This range should be broadened
  57.  * in the future.
  58.  *
  59.  * <p> 
  60.  * <strong>Example:</strong>
  61.  * <blockquote>
  62.  * <pre>
  63.  * // get the supported ids for GMT-08:00 (Pacific Standard Time)
  64.  * String[] ids = TimeZone.getAvailableIDs(-8 * 60 * 60 * 1000);
  65.  * // if no ids were returned, something is wrong. get out.
  66.  * if (ids.length == 0)
  67.  *     System.exit(0);
  68.  *
  69.  *  // begin output
  70.  * System.out.println("Current Time");
  71.  *
  72.  * // create a Pacific Standard Time time zone
  73.  * SimpleTimeZone pdt = new SimpleTimeZone(-8 * 60 * 60 * 1000, ids[0]);
  74.  *
  75.  * // set up rules for daylight savings time
  76.  * pdt.setStartRule(Calendar.APRIL, 1, Calendar.SUNDAY, 2 * 60 * 60 * 1000);
  77.  * pdt.setEndRule(Calendar.OCTOBER, -1, Calendar.SUNDAY, 2 * 60 * 60 * 1000);
  78.  *
  79.  * // create a GregorianCalendar with the Pacific Daylight time zone
  80.  * // and the current date and time
  81.  * Calendar calendar = new GregorianCalendar(pdt);
  82.  * Date trialTime = new Date();
  83.  * calendar.setTime(trialTime);
  84.  *
  85.  * // print out a bunch of interesting things
  86.  * System.out.println("ERA: " + calendar.get(Calendar.ERA));
  87.  * System.out.println("YEAR: " + calendar.get(Calendar.YEAR));
  88.  * System.out.println("MONTH: " + calendar.get(Calendar.MONTH));
  89.  * System.out.println("WEEK_OF_YEAR: " + calendar.get(Calendar.WEEK_OF_YEAR));
  90.  * System.out.println("WEEK_OF_MONTH: " + calendar.get(Calendar.WEEK_OF_MONTH));
  91.  * System.out.println("DATE: " + calendar.get(Calendar.DATE));
  92.  * System.out.println("DAY_OF_MONTH: " + calendar.get(Calendar.DAY_OF_MONTH));
  93.  * System.out.println("DAY_OF_YEAR: " + calendar.get(Calendar.DAY_OF_YEAR));
  94.  * System.out.println("DAY_OF_WEEK: " + calendar.get(Calendar.DAY_OF_WEEK));
  95.  * System.out.println("DAY_OF_WEEK_IN_MONTH: "
  96.  *                    + calendar.get(Calendar.DAY_OF_WEEK_IN_MONTH));
  97.  * System.out.println("AM_PM: " + calendar.get(Calendar.AM_PM));
  98.  * System.out.println("HOUR: " + calendar.get(Calendar.HOUR));
  99.  * System.out.println("HOUR_OF_DAY: " + calendar.get(Calendar.HOUR_OF_DAY));
  100.  * System.out.println("MINUTE: " + calendar.get(Calendar.MINUTE));
  101.  * System.out.println("SECOND: " + calendar.get(Calendar.SECOND));
  102.  * System.out.println("MILLISECOND: " + calendar.get(Calendar.MILLISECOND));
  103.  * System.out.println("ZONE_OFFSET: "
  104.  *                    + (calendar.get(Calendar.ZONE_OFFSET)/(60*60*1000)));
  105.  * System.out.println("DST_OFFSET: "
  106.  *                    + (calendar.get(Calendar.DST_OFFSET)/(60*60*1000)));
  107.  
  108.  * System.out.println("Current Time, with hour reset to 3");
  109.  * calendar.clear(Calendar.HOUR_OF_DAY); // so doesn't override
  110.  * calendar.set(Calendar.HOUR, 3);
  111.  * System.out.println("ERA: " + calendar.get(Calendar.ERA));
  112.  * System.out.println("YEAR: " + calendar.get(Calendar.YEAR));
  113.  * System.out.println("MONTH: " + calendar.get(Calendar.MONTH));
  114.  * System.out.println("WEEK_OF_YEAR: " + calendar.get(Calendar.WEEK_OF_YEAR));
  115.  * System.out.println("WEEK_OF_MONTH: " + calendar.get(Calendar.WEEK_OF_MONTH));
  116.  * System.out.println("DATE: " + calendar.get(Calendar.DATE));
  117.  * System.out.println("DAY_OF_MONTH: " + calendar.get(Calendar.DAY_OF_MONTH));
  118.  * System.out.println("DAY_OF_YEAR: " + calendar.get(Calendar.DAY_OF_YEAR));
  119.  * System.out.println("DAY_OF_WEEK: " + calendar.get(Calendar.DAY_OF_WEEK));
  120.  * System.out.println("DAY_OF_WEEK_IN_MONTH: "
  121.  *                    + calendar.get(Calendar.DAY_OF_WEEK_IN_MONTH));
  122.  * System.out.println("AM_PM: " + calendar.get(Calendar.AM_PM));
  123.  * System.out.println("HOUR: " + calendar.get(Calendar.HOUR));
  124.  * System.out.println("HOUR_OF_DAY: " + calendar.get(Calendar.HOUR_OF_DAY));
  125.  * System.out.println("MINUTE: " + calendar.get(Calendar.MINUTE));
  126.  * System.out.println("SECOND: " + calendar.get(Calendar.SECOND));
  127.  * System.out.println("MILLISECOND: " + calendar.get(Calendar.MILLISECOND));
  128.  * System.out.println("ZONE_OFFSET: "
  129.  *        + (calendar.get(Calendar.ZONE_OFFSET)/(60*60*1000))); // in hours
  130.  * System.out.println("DST_OFFSET: "
  131.  *        + (calendar.get(Calendar.DST_OFFSET)/(60*60*1000))); // in hours
  132.  * </pre>
  133.  * </blockquote>
  134.  *
  135.  * @see          Calendar
  136.  * @see          TimeZone
  137.  * @version      1.21 07/15/97
  138.  * @author       David Goldsmith, Mark Davis, Chen-Lieh Huang, Alan Liu
  139.  */
  140. public class GregorianCalendar extends Calendar {
  141.  
  142.     // Internal notes:
  143.     // This algorithm is based on the one presented on pp. 10-12 of
  144.     // "Numerical Recipes in C", William H. Press, et. al., Cambridge
  145.     // University Press 1988, ISBN 0-521-35465-X.
  146.  
  147.     /**
  148.      * Useful constant for GregorianCalendar.
  149.      */
  150.     public static final int BC = 0;
  151.     /**
  152.      * Useful constant for GregorianCalendar.
  153.      */
  154.     public static final int AD = 1;
  155.  
  156.     // Note that the Julian date used here is not a true Julian date, since
  157.     // it is measured from midnight, not noon.
  158.  
  159.     private static final long julianDayOffset = 2440588;
  160.     private static final int millisPerDay = 24 * 60 * 60 * 1000;
  161.     private static final int NUM_DAYS[]
  162.     = {0,31,59,90,120,151,181,212,243,273,304,334}; // 0-based, for day-in-year
  163.     private static final int LEAP_NUM_DAYS[]
  164.     = {0,31,60,91,121,152,182,213,244,274,305,335}; // 0-based, for day-in-year
  165.     private static final int MONTH_LENGTH[]
  166.     = {31,28,31,30,31,30,31,31,30,31,30,31}; // 0-based
  167.     private static final int LEAP_MONTH_LENGTH[]
  168.     = {31,29,31,30,31,30,31,31,30,31,30,31}; // 0-based
  169.  
  170.     // This is measured from the standard epoch, not in Julian Days.
  171.     // Default is 00:00:00 local time, October 15, 1582.
  172.     private long gregorianCutover = -12219292800000L;
  173.  
  174.     // The onset of the Julian calendar is 45 B.C.  The Julian day
  175.     // number for the start of the year 45 B.C. is 1712653.  We compute
  176.     // the Julian onset as epoch-based millis.  Note that this number is
  177.     // useful for rough comparison purposes only; it's not exact. [LIU]
  178.     private static long JULIAN_ONSET = (1712653 - julianDayOffset) * millisPerDay;
  179.  
  180.     // The earliest date we can handle for computing into fields is January 1,
  181.     // 4716 B.C.  This limit is the same regardless of when the Gregorian
  182.     // cutover is, because it is before all cutovers.  If we try to compute the
  183.     // fields for a date before this date, we get nonsense values.  The
  184.     // following constant encodes this date as millis from the epoch. [LIU]
  185.     private static long EARLIEST_USABLE_MILLIS = -210993120000000L;
  186.     private static int  EARLIEST_USABLE_YEAR   = 4716;
  187.  
  188.     /**
  189.      * Converts time as milliseconds to Julian date.
  190.      * @param millis the given milliseconds.
  191.      * @return the Julian date number.
  192.      */
  193.     private static final long millisToJulianDay(long millis)
  194.     {
  195.         if (millis >= 0)
  196.             return julianDayOffset + (millis / millisPerDay);
  197.         else
  198.             return julianDayOffset
  199.                 + ((millis - millisPerDay + 1) / millisPerDay);
  200.     }
  201.  
  202.     /**
  203.      * Converts Julian date to time as milliseconds.
  204.      * @param julian the given Julian date number.
  205.      * @return time as milliseconds.
  206.      */
  207.     private static final long julianDayToMillis(long julian)
  208.     {
  209.         return (julian - julianDayOffset) * millisPerDay;
  210.     }
  211.  
  212.     /**
  213.      * Constructs a default GregorianCalendar using the current time
  214.      * in the default time zone with the default locale.
  215.      */
  216.     public GregorianCalendar()
  217.     {
  218.         this(TimeZone.getDefault(), Locale.getDefault());
  219.     }
  220.  
  221.     /**
  222.      * Constructs a GregorianCalendar based on the current time
  223.      * in the given time zone with the default locale.
  224.      * @param zone the given time zone.
  225.      */
  226.     public GregorianCalendar(TimeZone zone)
  227.     {
  228.         this(zone, Locale.getDefault());
  229.     }
  230.  
  231.     /**
  232.      * Constructs a GregorianCalendar based on the current time
  233.      * in the default time zone with the given locale.
  234.      * @param aLocale the given locale.
  235.      */
  236.     public GregorianCalendar(Locale aLocale)
  237.     {
  238.         this(TimeZone.getDefault(), aLocale);
  239.     }
  240.  
  241.     /**
  242.      * Constructs a GregorianCalendar based on the current time
  243.      * in the given time zone with the given locale.
  244.      * @param zone the given time zone.
  245.      * @param aLocale the given locale.
  246.      */
  247.     public GregorianCalendar(TimeZone zone, Locale aLocale)
  248.     {
  249.         super(zone, aLocale);
  250.         setTimeInMillis(System.currentTimeMillis());
  251.     }
  252.  
  253.     /**
  254.      * Constructs a GregorianCalendar with the given date set
  255.      * in the default time zone with the default locale.
  256.      * @param year the value used to set the YEAR time field in the calendar.
  257.      * @param month the value used to set the MONTH time field in the calendar.
  258.      * Month value is 0-based. e.g., 0 for January.
  259.      * @param date the value used to set the DATE time field in the calendar.
  260.      */
  261.     public GregorianCalendar(int year, int month, int date)
  262.     {
  263.         super(TimeZone.getDefault(), Locale.getDefault());
  264.         this.set(Calendar.ERA, AD);
  265.         this.set(Calendar.YEAR, year);
  266.         this.set(Calendar.MONTH, month);
  267.         this.set(Calendar.DATE, date);
  268.     }
  269.  
  270.     /**
  271.      * Constructs a GregorianCalendar with the given date
  272.      * and time set for the default time zone with the default locale.
  273.      * @param year the value used to set the YEAR time field in the calendar.
  274.      * @param month the value used to set the MONTH time field in the calendar.
  275.      * Month value is 0-based. e.g., 0 for January.
  276.      * @param date the value used to set the DATE time field in the calendar.
  277.      * @param hour the value used to set the HOUR_OF_DAY time field
  278.      * in the calendar.
  279.      * @param minute the value used to set the MINUTE time field
  280.      * in the calendar.
  281.      */
  282.     public GregorianCalendar(int year, int month, int date, int hour,
  283.                              int minute)
  284.     {
  285.         super(TimeZone.getDefault(), Locale.getDefault());
  286.         this.set(Calendar.ERA, AD);
  287.         this.set(Calendar.YEAR, year);
  288.         this.set(Calendar.MONTH, month);
  289.         this.set(Calendar.DATE, date);
  290.         this.set(Calendar.HOUR_OF_DAY, hour);
  291.         this.set(Calendar.MINUTE, minute);
  292.     }
  293.  
  294.     /**
  295.      * Constructs a GregorianCalendar with the given date
  296.      * and time set for the default time zone with the default locale.
  297.      * @param year the value used to set the YEAR time field in the calendar.
  298.      * @param month the value used to set the MONTH time field in the calendar.
  299.      * Month value is 0-based. e.g., 0 for January.
  300.      * @param date the value used to set the DATE time field in the calendar.
  301.      * @param hour the value used to set the HOUR_OF_DAY time field
  302.      * in the calendar.
  303.      * @param minute the value used to set the MINUTE time field
  304.      * in the calendar.
  305.      * @param second the value used to set the SECOND time field
  306.      * in the calendar.
  307.      */
  308.     public GregorianCalendar(int year, int month, int date, int hour,
  309.                              int minute, int second)
  310.     {
  311.         super(TimeZone.getDefault(), Locale.getDefault());
  312.         this.set(Calendar.ERA, AD);
  313.         this.set(Calendar.YEAR, year);
  314.         this.set(Calendar.MONTH, month);
  315.         this.set(Calendar.DATE, date);
  316.         this.set(Calendar.HOUR_OF_DAY, hour);
  317.         this.set(Calendar.MINUTE, minute);
  318.         this.set(Calendar.SECOND, second);
  319.     }
  320.  
  321.     /**
  322.      * Sets the GregorianCalendar change date. This is the point when the
  323.      * switch from Julian dates to Gregorian dates occurred. Default is
  324.      * 00:00:00 local time, October 15, 1582. Previous to this time and date
  325.      * will be Julian dates.
  326.      *
  327.      * @param date the given Gregorian cutover date.
  328.      */
  329.     public void setGregorianChange(Date date)
  330.     {
  331.         gregorianCutover = date.getTime();
  332.     }
  333.  
  334.     /**
  335.      * Gets the Gregorian Calendar change date.  This is the point when the
  336.      * switch from Julian dates to Gregorian dates occurred. Default is
  337.      * 00:00:00 local time, October 15, 1582. Previous to
  338.      * this time and date will be Julian dates.
  339.      * @return the Gregorian cutover time for this calendar.
  340.      */
  341.     public final Date getGregorianChange()
  342.     {
  343.         return new Date(gregorianCutover);
  344.     }
  345.  
  346.     private static final int julianDayToDayOfWeek(long julian)
  347.     {
  348.         // If julian is negative, then julian%7 will be negative, so we adjust
  349.         // accordingly.  We add 1 because Julian day 0 is Monday.
  350.         int dayOfWeek = (int)((julian + 1) % 7);
  351.         return dayOfWeek + ((dayOfWeek < 0) ? (7 + SUNDAY) : SUNDAY);
  352.     }
  353.  
  354.     /**
  355.      * Convert the time as milliseconds to the "big" fields.  Millis must be
  356.      * given as local wall millis to get the correct local day.  For example,
  357.      * if it is 11:30 pm Standard, and DST is in effect, the correct DST millis
  358.      * must be passed in to get the right date.
  359.      *   
  360.      * Fields that are completed by this method: ERA, YEAR, MONTH, DATE,
  361.      * DAY_OF_WEEK, DAY_OF_YEAR, WEEK_OF_YEAR, WEEK_OF_MONTH,
  362.      * DAY_OF_WEEK_IN_MONTH.
  363.      */
  364.     private final void timeToFields(long theTime)
  365.     {
  366.         int year, month, date, dayOfWeek, dayOfYear, weekCount, era = AD;
  367.  
  368.         // The following algorithm only works for dates from January 1, 4716 BC
  369.         // onwards.  We throw an IllegalArgumentException if the date is earlier
  370.         // than this.
  371.         if (theTime < EARLIEST_USABLE_MILLIS)
  372.             throw new IllegalArgumentException("GregorianCalendar does not handle dates before 4716 BC");
  373.                 
  374.         //---------------------------------------------------------------------
  375.         // BEGIN modified caldat()
  376.         //---------------------------------------------------------------------
  377.         // The following variable names are somewhat cryptic. Unfortunately,
  378.         // they are from the original program cited above, and no explanation
  379.         // for their meaning is given. Given that the algorithm is cryptic too,
  380.         // perhaps it doesn't matter...
  381.         long ja, jb, jd;
  382.         long jc, je; // changed from int to fix number overflow problem.
  383.  
  384.         long julian = millisToJulianDay(theTime);
  385.  
  386.         if (theTime >= gregorianCutover)
  387.         {
  388.             long jalpha = (long) (((double) (julian - 1867216) - 0.25)
  389.                                   / 36524.25);
  390.             ja = julian + 1 + jalpha - (long) (0.25 * jalpha);
  391.         }
  392.         else
  393.         {
  394.             ja = julian;
  395.         }
  396.         jb = ja + 1524;
  397.         jc = (long) (6680.0 + ((double) (jb - 2439870) - 122.1) / 365.25);
  398.         jd = (long) (365*jc + (0.25 * jc));
  399.         je = (long) ((jb-jd)/30.6001);
  400.         date = (int) (jb-jd-(long) (30.6001 * je));
  401.         month = (int) je - 1;
  402.         if (month > 12)
  403.             month -= 12;
  404.  
  405.         // Removed; this isn't needed, and in fact should be "if (month < 1)" if
  406.         // it is needed. [LIU]
  407.  
  408.         // else if (month < 0) // added by CLH
  409.         //    month += 12;    // added by CLH, 8-7-96
  410.  
  411.         year = (int) (jc-4715);
  412.         if (month > 2)
  413.             --year;
  414.         if (year <= 0)
  415.         {
  416.             era = BC;
  417.             year = 1-year;
  418.         }
  419.         //---------------------------------------------------------------------
  420.         // END modified caldat()
  421.         //---------------------------------------------------------------------
  422.  
  423.         internalSet(ERA, era);
  424.         internalSet(YEAR, year);
  425.         internalSet(MONTH, month-1); // 0-based
  426.         internalSet(DATE, date);
  427.  
  428.         dayOfWeek = julianDayToDayOfWeek(julian);
  429.         internalSet(DAY_OF_WEEK, dayOfWeek); // CLH, 8-7-96
  430.  
  431.         if (isLeapYear(year))
  432.             dayOfYear = LEAP_NUM_DAYS[month-1] + date; // month: 0-based
  433.         else
  434.             dayOfYear = NUM_DAYS[month-1] + date; // month: 0-based
  435.         internalSet(DAY_OF_YEAR, dayOfYear);
  436.  
  437.         internalSet(WEEK_OF_YEAR, weekNumber(dayOfYear, dayOfWeek));
  438.         internalSet(WEEK_OF_MONTH, weekNumber(date, dayOfWeek));
  439.  
  440.         internalSet(DAY_OF_WEEK_IN_MONTH, (date-1) / 7 + 1);
  441.     }
  442.  
  443.     /**
  444.      * Return the week number of a day, within a period. This may be the week number in
  445.      * a year, or the week number in a month. Usually this will be a value >= 1, but if
  446.      * some initial days of the period are excluded from week 1, because
  447.      * minimalDaysInFirstWeek is > 1, then the week number will be zero for those
  448.      * initial days. Requires the day of week for the given date in order to determine
  449.      * the day of week of the first day of the period.
  450.      *
  451.      * @param dayOfPeriod  Day-of-year or day-of-month. Should be 1 for first day of period.
  452.      * @param day   Day-of-week for given dayOfPeriod. 1-based with 1=Sunday.
  453.      * @return      Week number, one-based, or zero if the day falls in part of the
  454.      *              month before the first week, when there are days before the first
  455.      *              week because the minimum days in the first week is more than one.
  456.      */
  457.     private int weekNumber(int dayOfPeriod, int dayOfWeek)
  458.     {
  459.         // Determine the day of the week of the first day of the period
  460.         // in question (either a year or a month).  Zero represents the
  461.         // first day of the week on this calendar.
  462.         int periodStartDayOfWeek = (dayOfWeek - getFirstDayOfWeek() - dayOfPeriod + 1) % 7;
  463.         if (periodStartDayOfWeek < 0) periodStartDayOfWeek += 7;
  464.  
  465.         // Compute the week number.  Initially, ignore the first week, which
  466.         // may be fractional (or may not be).  We add periodStartDayOfWeek in
  467.         // order to fill out the first week, if it is fractional.
  468.         int weekNo = (dayOfPeriod + periodStartDayOfWeek - 1)/7;
  469.  
  470.         // If the first week is long enough, then count it.  If
  471.         // the minimal days in the first week is one, or if the period start
  472.         // is zero, we always increment weekNo.
  473.         if ((7 - periodStartDayOfWeek) >= getMinimalDaysInFirstWeek()) ++weekNo;
  474.  
  475.         return weekNo;
  476.     }
  477.  
  478.     /**
  479.      * Determines if the given year is a leap year. Returns true if the
  480.      * given year is a leap year.
  481.      * @param year the given year.
  482.      * @return true if the given year is a leap year; false otherwise.
  483.      */
  484.     public boolean isLeapYear(int year)
  485.     {
  486.         // Compute the rough millis for the year.  We only need this number to be
  487.         // good enough to compare it against JULIAN_ONSET.
  488.         long equivalent_millis = (long)((year - 1970) * 365.2422 * millisPerDay);
  489.  
  490.         // No leap years before onset of Julian calendar
  491.         if (equivalent_millis < JULIAN_ONSET)
  492.             return false;
  493.  
  494.         return (equivalent_millis > gregorianCutover) ?
  495.             ((year%4 == 0) && ((year%100 != 0) || (year%400 == 0))) : // Gregorian
  496.             (year%4 == 0); // Julian
  497.     }
  498.  
  499.     /**
  500.      * Overrides Calendar
  501.      * Converts UTC as milliseconds to time field values.
  502.      * The time is <em>not</em>
  503.      * recomputed first; to recompute the time, then the fields, call the
  504.      * <code>complete</code> method.
  505.      * @see Calendar#complete
  506.      */
  507.     protected void computeFields()
  508.     {
  509.         if (areFieldsSet) return;
  510.  
  511.         int gmtOffset = getTimeZone().getRawOffset();
  512.         long localMillis = time + gmtOffset;
  513.  
  514.         // Time to fields takes the wall millis (Standard or DST).
  515.         timeToFields(localMillis);
  516.  
  517.         int era = internalGet(Calendar.ERA);
  518.         int year = internalGet(Calendar.YEAR);
  519.         int month = internalGet(Calendar.MONTH);
  520.         int date = internalGet(Calendar.DATE);
  521.         int dayOfWeek = internalGet(Calendar.DAY_OF_WEEK);
  522.  
  523.         long days = (long) (localMillis / millisPerDay);
  524.         int millisInDay = (int) (localMillis - (days * millisPerDay));
  525.         if (millisInDay < 0) millisInDay += millisPerDay;
  526.  
  527.         // Call getOffset() to get the TimeZone offset.  The millisInDay value must
  528.         // be standard local millis.
  529.         int dstOffset = getTimeZone().getOffset(era,year,month,date,dayOfWeek,millisInDay) -
  530.             gmtOffset;
  531.  
  532.         // Adjust our millisInDay for DST, if necessary.
  533.         millisInDay += dstOffset;
  534.  
  535.         // If DST has pushed us into the next day, we must call timeToFields() again.
  536.         // This happens in DST between 12:00 am and 1:00 am every day.  The call to
  537.         // timeToFields() will give the wrong day, since the Standard time is in the
  538.         // previous day.
  539.         if (millisInDay >= millisPerDay)
  540.         {
  541.             millisInDay -= millisPerDay;
  542.             localMillis += dstOffset;
  543.             timeToFields(localMillis);
  544.         }
  545.  
  546.         // Fill in all time-related fields based on millisInDay.  Call internalSet()
  547.         // so as not to perturb flags.
  548.         internalSet(Calendar.MILLISECOND, millisInDay % 1000);
  549.         millisInDay /= 1000;
  550.         internalSet(Calendar.SECOND, millisInDay % 60);
  551.         millisInDay /= 60;
  552.         internalSet(Calendar.MINUTE, millisInDay % 60);
  553.         millisInDay /= 60;
  554.         internalSet(Calendar.HOUR_OF_DAY, millisInDay);
  555.         internalSet(Calendar.AM_PM, millisInDay / 12);
  556.         internalSet(Calendar.HOUR, millisInDay % 12);
  557.  
  558.         internalSet(Calendar.ZONE_OFFSET, gmtOffset);
  559.         internalSet(Calendar.DST_OFFSET, dstOffset);
  560.         userSetZoneOffset = false;
  561.         userSetDSTOffset = false;
  562.  
  563.         areFieldsSet = true;
  564.         areAllFieldsSet = true;
  565.                 
  566.         // Careful here: We are manually setting the isSet[] flags to true, so we
  567.         // must be sure that the above code actually does set all these fields.
  568.         for (int i=0; i<FIELD_COUNT; ++i) isSet[i] = true;
  569.     }
  570.  
  571.     /**
  572.      * Return true if the current time for this Calendar is in Daylignt
  573.      * Savings Time.
  574.      *
  575.      * Note -- MAKE THIS PUBLIC AT THE NEXT API CHANGE.  POSSIBLY DEPRECATE
  576.      * AND REMOVE TimeZone.inDaylightTime().
  577.      */
  578.     boolean inDaylightTime()
  579.     {
  580.         if (!getTimeZone().useDaylightTime()) return false;
  581.         complete(); // Force update of DST_OFFSET field
  582.         return internalGet(DST_OFFSET) != 0;
  583.     }
  584.  
  585.     private final int monthLength(int month, int year)
  586.     {
  587.         return isLeapYear(year) ? LEAP_MONTH_LENGTH[month] : MONTH_LENGTH[month];
  588.     }
  589.  
  590.     /**
  591.      * Validates the values of the set time fields.
  592.      */
  593.     private boolean validateFields()
  594.     {
  595.         for (int field = 0; field < FIELD_COUNT; field++)
  596.         {
  597.             // Ignore DATE and DAY_OF_YEAR which are handled below
  598.             if (field != DATE &&
  599.                 field != DAY_OF_YEAR &&
  600.                 isSet(field) &&
  601.                 !boundsCheck(internalGet(field), field))
  602.  
  603.                 return false;
  604.         }
  605.  
  606.         // Values differ in Least-Maximum and Maximum should be handled
  607.         // specially.
  608.         if (isSet(DATE))
  609.         {
  610.             int date = internalGet(DATE);
  611.             return (date >= getMinimum(DATE) &&
  612.                     date <= monthLength(internalGet(MONTH), internalGet(YEAR)));
  613.         }
  614.  
  615.         if (isSet(DAY_OF_YEAR))
  616.         {
  617.             int days = internalGet(DAY_OF_YEAR);
  618.  
  619.             if (isLeapYear(internalGet(YEAR))) {
  620.                 if (days < 1 || days > 366)
  621.                     return false;
  622.             }
  623.             else if (days < 1 || days > 365)
  624.                 return false;
  625.         }
  626.  
  627.         // We only handle years back to 4716 BC (EARLIEST_USABLE_YEAR).
  628.         if (isSet(YEAR))
  629.         {
  630.             int year = internalGet(YEAR);
  631.             // Convert AD years to BC equivalents
  632.             if (!isSet(ERA) || internalGet(ERA) == AD) year = 1-year;
  633.             if (year > EARLIEST_USABLE_YEAR) return false;
  634.         }
  635.  
  636.         // Handle DAY_OF_WEEK_IN_MONTH, which must not have the value zero.
  637.         // We've checked against minimum and maximum above already.
  638.         if (isSet(DAY_OF_WEEK_IN_MONTH) &&
  639.             0 == internalGet(DAY_OF_WEEK_IN_MONTH)) return false;
  640.  
  641.         return true;
  642.     }
  643.  
  644.     /**
  645.      * Validates the value of the given time field.
  646.      */
  647.     private boolean boundsCheck(int value, int field)
  648.     {
  649.         return value >= getMinimum(field) && value <= getMaximum(field);
  650.     }
  651.  
  652.     /**
  653.      * Overrides Calendar
  654.      * Converts time field values to UTC as milliseconds.
  655.      * @exception IllegalArgumentException if an unknown field is given.
  656.      */
  657.     protected void computeTime()
  658.     {
  659.         if (isTimeSet) return;
  660.  
  661.         // If we are lenient, we need to recompute the fields to normalize
  662.         // the values.  Also, if we haven't set all the fields yet (i.e.,
  663.         // in a newly-created object), we need to fill in the fields. [LIU]
  664.         areFieldsSet = (!isLenient() && areAllFieldsSet);
  665.  
  666.         if (!isLenient() && !validateFields())
  667.             throw new IllegalArgumentException();
  668.  
  669.         // This function takes advantage of the fact that unset fields in
  670.         // the time field list have a value of zero.
  671.         long millis = 0;
  672.  
  673.         int era;
  674.         if (isSet(ERA))
  675.             era = internalGet(ERA);
  676.         else
  677.             era = AD;
  678.  
  679.         if (era < BC || era > AD)
  680.             throw new IllegalArgumentException();
  681.  
  682.         // The year is required.  We don't have to check if it's unset,
  683.         // because if it is, by definition it will be 0.
  684.  
  685.         int year = internalGet(YEAR);
  686.         int month = 0, date = 0;
  687.         // if (year <= 0)
  688.         //    throw new IllegalArgumentException();
  689.  
  690.         if (era == BC)
  691.             year = 1 - year;
  692.  
  693.         long julian = 0;
  694.  
  695.         // The following code is somewhat convoluted. The various nested
  696.         //  if's handle the different cases of what fields are present.
  697.         if (isSet(MONTH) &&
  698.             (isSet(DATE) ||
  699.              (isSet(DAY_OF_WEEK) &&
  700.               (isSet(WEEK_OF_MONTH) ||
  701.                isSet(DAY_OF_WEEK_IN_MONTH))
  702.                  )
  703.                 ))
  704.         {
  705.             // We have the month specified. Make it 1-based for the algorithm.
  706.             month = internalGet(MONTH) + 1;
  707.             // normalize month
  708.             if (month < 1) {
  709.                 year += month / 12 - 1;
  710.                 month = 12 + month % 12;
  711.             } else if (month > 12) {
  712.                 year += month / 12;
  713.                 month = month % 12;
  714.             }
  715.  
  716.             if (month > 2)
  717.                 ++month;
  718.             else
  719.             {
  720.                 --year;
  721.                 month += 13;
  722.             }
  723.             julian = (long) (Math.floor(365.25*year)
  724.                      + Math.floor(30.6001*month) + 1720995);
  725.  
  726.             if (isSet(DATE))
  727.             {
  728.                 date = internalGet(DATE);
  729.             }
  730.             else
  731.             {
  732.                 // Compute from day of week plus week number or from the day of
  733.                 // week plus the day of week in month.  The computations are
  734.                 // almost identical.
  735.  
  736.                 // The first thing we have to do is do the Gregorian adjustment,
  737.                 // if necessary.  We figure out the adjusted value 'j' and use
  738.                 // that.  We redo this later when we get the real final number.
  739.                 // This double computation provides the best accuracy around the
  740.                 // Gregorian cutover.
  741.                 long j = julian;
  742.                 if (julianDayToMillis(julian) >= gregorianCutover)
  743.                 {
  744.                     long adjust = (long) (0.01 * year);
  745.                     j += 2 - adjust + (long) (0.25*adjust);
  746.                 }
  747.  
  748.                 // Find the day of the week for the first of this month.  This
  749.                 // is zero-based, with 0 being the locale-specific first day of
  750.                 // the week.  Add 1 to get the 1st day of month.  Subtract
  751.                 // getFirstDayOfWeek() to make 0-based.
  752.                 int fdm = julianDayToDayOfWeek(j + 1) - getFirstDayOfWeek();
  753.                 if (fdm < 0) fdm += 7;
  754.  
  755.                 // Find the start of the first week.  This will be a date from
  756.                 // 1..-6.  It represents the locale-specific first day of the
  757.                 // week of the first day of the month, ignoring minimal days in
  758.                 // first week.
  759.                 date = 1 - fdm + internalGet(DAY_OF_WEEK) - getFirstDayOfWeek();
  760.  
  761.                 if (isSet(WEEK_OF_MONTH))
  762.                 {
  763.                     // Adjust for minimal days in first week.
  764.                     if ((7 - fdm) < getMinimalDaysInFirstWeek()) date += 7;
  765.  
  766.                     // Now adjust for the week number.
  767.                     date += 7 * (internalGet(WEEK_OF_MONTH) - 1);
  768.                 }
  769.                 else
  770.                 {
  771.                     // Adjust into the month, if needed.
  772.                     if (date < 1) date += 7;
  773.  
  774.                     // We are basing this on the day-of-week-in-month.  The only
  775.                     // trickiness occurs if the day-of-week-in-month is
  776.                     // negative.
  777.                     int dim = internalGet(DAY_OF_WEEK_IN_MONTH);
  778.                     if (dim >= 0) date += 7*(dim - 1);
  779.                     else
  780.                     {
  781.                         // Move date to the last of this day-of-week in this
  782.                         // month, then back up as needed.  If dim==-1, we don't
  783.                         // back up at all.  If dim==-2, we back up once, etc.
  784.                         // Don't back up past the first of the given day-of-week
  785.                         // in this month.  Note that we handle -2, -3,
  786.                         // etc. correctly, even though values < -1 are
  787.                         // technically disallowed.
  788.                         date += ((monthLength(internalGet(MONTH), year) - date) / 7 + dim + 1) * 7;
  789.                     }
  790.                 }
  791.             }
  792.             julian += date;
  793.         }
  794.         else if (isSet(DAY_OF_YEAR) ||
  795.                  (isSet(DAY_OF_WEEK) && (isSet(WEEK_OF_YEAR))))
  796.         {
  797.             // No month, start with January 0 (day before Jan 1), then adjust.
  798.             --year;
  799.             julian = (long) (Math.floor(365.25*year) + 428 + 1720995);
  800.  
  801.             if (isSet(DAY_OF_YEAR))
  802.                 julian += internalGet(DAY_OF_YEAR);
  803.             else
  804.             {
  805.                 // Compute from day of week plus week of year
  806.  
  807.                 // The first thing we have to do is do the Gregorian adjustment,
  808.                 // if necessary.  We figure out the adjusted value 'j' and use
  809.                 // that.  We redo this later when we get the real final number.
  810.                 // This double computation provides the best accuracy around the
  811.                 // Gregorian cutover.
  812.                 long j = julian;
  813.                 if (julianDayToMillis(julian) >= gregorianCutover)
  814.                 {
  815.                     long adjust = (long) (0.01 * year);
  816.                     j += 2 - adjust + (long) (0.25*adjust);
  817.                 }
  818.  
  819.                 // Find the day of the week for the first of this year.  This
  820.                 // is zero-based, with 0 being the locale-specific first day of
  821.                 // the week.  Add 1 to get the 1st day of month.  Subtract
  822.                 // getFirstDayOfWeek() to make 0-based.
  823.                 int fdy = julianDayToDayOfWeek(j + 1) - getFirstDayOfWeek();
  824.                 if (fdy < 0) fdy += 7;
  825.  
  826.                 // Find the start of the first week.  This may be a valid date
  827.                 // from 1..7, or a date before the first, from 0..-6.  It
  828.                 // represents the locale-specific first day of the week
  829.                 // of the first day of the year.
  830.                                 
  831.                 // First ignore the minimal days in first week.
  832.                 date = 1 - fdy + internalGet(DAY_OF_WEEK) - getFirstDayOfWeek();
  833.                                 
  834.                 // Adjust for minimal days in first week.
  835.                 if ((7 - fdy) < getMinimalDaysInFirstWeek()) date += 7;
  836.  
  837.                 // Now adjust for the week number.
  838.                 date += 7 * (internalGet(WEEK_OF_YEAR) - 1);
  839.  
  840.                 julian += date;
  841.             }
  842.         }
  843.         else {    // Not enough information
  844.             throw new IllegalArgumentException();
  845.         }
  846.  
  847.         // Now adjust for Gregorian if necessary. Note that dates that fall in
  848.         // the "gap" between the Julian and Gregorian calendars will be treated
  849.         // as Gregorian. Strictly speaking, they're illegal.
  850.         millis = julianDayToMillis(julian);
  851.         if (millis >= gregorianCutover)
  852.         {
  853.             long adjust = (long) (0.01 * year);
  854.             julian += 2 - adjust + (long) (0.25*adjust);
  855.             millis = julianDayToMillis(julian);
  856.         }
  857.  
  858.         // Now we can do the time portion of the conversion.
  859.  
  860.         int millisInDay = 0;
  861.  
  862.         // Hours
  863.         if (isSet(HOUR_OF_DAY))
  864.             // Don't normalize here; let overflow bump into the next period.
  865.             // This is consistent with how we handle other fields.
  866.             millisInDay += internalGet(HOUR_OF_DAY);
  867.  
  868.         else if (isSet(HOUR))
  869.         {
  870.             // Don't normalize here; let overflow bump into the next period.
  871.             // This is consistent with how we handle other fields.
  872.             millisInDay += internalGet(HOUR);
  873.  
  874.             millisInDay += 12 * internalGet(AM_PM);
  875.         }
  876.  
  877.         // Minutes. We use the fact that unset == 0
  878.         millisInDay *= 60;
  879.         millisInDay += internalGet(MINUTE);
  880.  
  881.         // Seconds. unset == 0
  882.         millisInDay *= 60;
  883.         millisInDay += internalGet(SECOND);
  884.  
  885.         // Milliseconds. unset == 0
  886.         millisInDay *= 1000;
  887.         millisInDay += internalGet(MILLISECOND);
  888.  
  889.         // Compute the time zone offset and DST offset.  There are two potential
  890.         // ambiguities here.  We'll assume a 2:00 am (wall time) switchover time
  891.         // for discussion purposes here.
  892.         // 1. The transition into DST.  Here, a designated time of 2:00 am - 2:59 am
  893.         //    can be in standard or in DST depending.  However, 2:00 am is an invalid
  894.         //    representation (the representation jumps from 1:59:59 am Std to 3:00:00 am DST).
  895.         //    We assume standard time.
  896.         // 2. The transition out of DST.  Here, a designated time of 1:00 am - 1:59 am
  897.         //    can be in standard or DST.  Both are valid representations (the rep
  898.         //    jumps from 1:59:59 DST to 1:00:00 Std).
  899.         //    Again, we assume standard time.
  900.         // We use the TimeZone object, unless the user has explicitly set the ZONE_OFFSET
  901.         // or DST_OFFSET fields; then we use those fields.
  902.         TimeZone zone = getTimeZone();
  903.         int zoneOffset = (isSet(ZONE_OFFSET) && userSetZoneOffset) ?
  904.             internalGet(ZONE_OFFSET) : zone.getRawOffset();
  905.  
  906.         // Now add date and millisInDay together, to make millis contain local wall
  907.         // millis, with no zone or DST adjustments
  908.         millis += millisInDay;
  909.  
  910.         int dstOffset = 0;
  911.         if (isSet(DST_OFFSET) && userSetDSTOffset) dstOffset = internalGet(DST_OFFSET);
  912.         else
  913.         {
  914.             // We need to have the month, the day, and the day of the week.
  915.             // Calling timeToFields will compute the MONTH and DATE fields.
  916.             if (!isSet(MONTH) || !isSet(DATE))
  917.                 timeToFields(millis); // Right - use wall time here
  918.  
  919.             // It's tempting to try to use DAY_OF_WEEK here, if it
  920.             // is set, but we CAN'T.  Even if it's set, it might have
  921.             // been set wrong by the user.  We should rely only on
  922.             // the Julian day number, which has been computed correctly
  923.             // using the disambiguation algorithm above. [LIU]
  924.             dstOffset = zone.getOffset(era,
  925.                                        internalGet(YEAR),
  926.                                        internalGet(MONTH),
  927.                                        internalGet(DATE),
  928.                                        julianDayToDayOfWeek(julian),
  929.                                        millisInDay) -
  930.                 zoneOffset;
  931.             // Note: Because we pass in wall millisInDay, rather than
  932.             // standard millisInDay, we interpret "1:00 am" on the day
  933.             // of cessation of DST as "1:00 am Std" (assuming the time
  934.             // of cessation is 2:00 am).
  935.         }
  936.  
  937.         // Store our final computed GMT time, with timezone adjustments.
  938.         time = millis - zoneOffset - dstOffset;
  939.         isTimeSet = true;
  940.     }
  941.  
  942.     /**
  943.      * Override hashCode.
  944.      * Generates the hash code for the GregorianCalendar object
  945.      */
  946.     public synchronized int hashCode()
  947.     {
  948.         return getFirstDayOfWeek() ^ getMinimalDaysInFirstWeek();
  949.     }
  950.  
  951.     /**
  952.      * Overrides Calendar
  953.      * Compares the time field records.
  954.      * Equivalent to comparing result of conversion to UTC.
  955.      * Please see Calendar.equals for descriptions on parameters and
  956.      * the return value.
  957.      */
  958.     public boolean equals(Object obj)
  959.     {
  960.         if (this == obj)
  961.             return true;
  962.         if (!(obj instanceof GregorianCalendar))
  963.             return false;
  964.  
  965.         GregorianCalendar that = (GregorianCalendar) obj;
  966.  
  967.         return
  968.             getTimeInMillis() == that.getTimeInMillis() &&
  969.             isLenient() == that.isLenient() &&
  970.             getFirstDayOfWeek() == that.getFirstDayOfWeek() &&
  971.             getMinimalDaysInFirstWeek() == that.getMinimalDaysInFirstWeek() &&
  972.             getTimeZone().equals(that.getTimeZone());
  973.     }
  974.  
  975.     /**
  976.      * Overrides Calendar
  977.      * Compares the time field records.
  978.      * Equivalent to comparing result of conversion to UTC.
  979.      * Please see Calendar.before for descriptions on parameters and
  980.      * the return value.
  981.      */
  982.     public boolean before(Object when)
  983.     {
  984.         if (this == when ||
  985.             when == null ||
  986.             !(when instanceof GregorianCalendar)) return false;
  987.  
  988.         GregorianCalendar other = (GregorianCalendar)when;
  989.  
  990.         return (getTimeInMillis() < other.getTimeInMillis());
  991.     }
  992.  
  993.     /**
  994.      * Overrides Calendar
  995.      * Compares the time field records.
  996.      * Equivalent to comparing result of conversion to UTC.
  997.      * Please see Calendar.after for descriptions on parameters and
  998.      * the return value.
  999.      */
  1000.     public boolean after(Object when)
  1001.     {
  1002.         if (this == when ||
  1003.             when == null ||
  1004.             !(when instanceof GregorianCalendar)) return false;
  1005.  
  1006.         GregorianCalendar other = (GregorianCalendar)when;
  1007.  
  1008.         return (getTimeInMillis() > other.getTimeInMillis());
  1009.     }
  1010.  
  1011.     /**
  1012.      * Overrides Calendar
  1013.      * Date Arithmetic function.
  1014.      * Adds the specified (signed) amount of time to the given time field,
  1015.      * based on the calendar's rules.
  1016.      * @param field the time field.
  1017.      * @param amount the amount of date or time to be added to the field.
  1018.      * @exception IllegalArgumentException if an unknown field is given.
  1019.      */
  1020.     public void add(int field, int amount)
  1021.     {
  1022.         if (amount == 0) return;   // Do nothing!
  1023.         complete();
  1024.  
  1025.         if (field == Calendar.YEAR)
  1026.         {
  1027.             int year = this.internalGet(Calendar.YEAR);
  1028.             if (this.internalGet(Calendar.ERA) == GregorianCalendar.AD)
  1029.             {
  1030.                 year += amount;
  1031.                 if (year > 0)
  1032.                     this.set(Calendar.YEAR, year);
  1033.                 else // year <= 0
  1034.                 {
  1035.                     this.set(Calendar.YEAR, 1 - year);
  1036.                     // if year == 0, you get 1 BC
  1037.                     this.set(Calendar.ERA, GregorianCalendar.BC);
  1038.                 }
  1039.             }
  1040.             else // era == BC
  1041.             {
  1042.                 year -= amount;
  1043.                 if (year > 0)
  1044.                     this.set(Calendar.YEAR, year);
  1045.                 else // year <= 0
  1046.                 {
  1047.                     this.set(Calendar.YEAR, 1 - year);
  1048.                     // if year == 0, you get 1 AD
  1049.                     this.set(Calendar.ERA, GregorianCalendar.AD);
  1050.                 }
  1051.             }
  1052.         }
  1053.         else if (field == Calendar.MONTH)
  1054.         {
  1055.             int month = this.internalGet(Calendar.MONTH) + amount;
  1056.             if (month >= 0)
  1057.             {
  1058.                 add(Calendar.YEAR, (int) (month / 12));
  1059.                 set(Calendar.MONTH, (int) (month % 12));
  1060.             }
  1061.             else // month < 0
  1062.             {
  1063.                 add(Calendar.YEAR, (int) ((month + 1) / 12) - 1);
  1064.                 month %= 12;
  1065.                 if (month < 0) month += 12;
  1066.                 set(MONTH, JANUARY + month);
  1067.             }
  1068.         }
  1069.         else if (field == ERA)
  1070.         {
  1071.             int era = internalGet(ERA) + amount;
  1072.             if (era < 0) era = 0;
  1073.             if (era > 1) era = 1;
  1074.             set(ERA, era);
  1075.         }
  1076.         else
  1077.         {
  1078.             // We handle most fields here.  The algorithm is to add a computed amount
  1079.             // of millis to the current millis.  The only wrinkle is with DST -- if
  1080.             // the result of the add operation is to move from DST to Standard, or vice
  1081.             // versa, we need to adjust by an hour forward or back, respectively.
  1082.             // Otherwise you get weird effects in which the hour seems to shift when
  1083.             // you add to the DAY_OF_MONTH field, for instance.
  1084.  
  1085.             // Save the current DST state.
  1086.             long dst = internalGet(DST_OFFSET);
  1087.  
  1088.             long delta = amount;
  1089.             switch (field)
  1090.             {
  1091.             case Calendar.WEEK_OF_YEAR:
  1092.             case Calendar.WEEK_OF_MONTH:
  1093.             case Calendar.DAY_OF_WEEK_IN_MONTH:
  1094.                 delta *= 7 * 24 * 60 * 60 * 1000; // 7 days
  1095.                 break;
  1096.  
  1097.             case Calendar.AM_PM:
  1098.                 delta *= 12 * 60 * 60 * 1000; // 12 hrs
  1099.                 break;
  1100.  
  1101.             case Calendar.DATE: // synonym of DAY_OF_MONTH
  1102.             case Calendar.DAY_OF_YEAR:
  1103.             case Calendar.DAY_OF_WEEK:
  1104.                 delta *= 24 * 60 * 60 * 1000; // 1 day
  1105.                 break;
  1106.  
  1107.             case Calendar.HOUR_OF_DAY:
  1108.             case Calendar.HOUR:
  1109.                 delta *= 60 * 60 * 1000; // 1 hour
  1110.                 break;
  1111.  
  1112.             case Calendar.MINUTE:
  1113.                 delta *= 60 * 1000; // 1 minute
  1114.                 break;
  1115.  
  1116.             case Calendar.SECOND:
  1117.                 delta *= 1000; // 1 second
  1118.                 break;
  1119.  
  1120.             case MILLISECOND:
  1121.                 // Simply break out on MILLISECOND
  1122.                 break;
  1123.  
  1124.             case ZONE_OFFSET:
  1125.             case DST_OFFSET:
  1126.             default:
  1127.                 throw new IllegalArgumentException();
  1128.             }
  1129.  
  1130.             setTimeInMillis(time + delta); // Automatically computes fields if necessary
  1131.  
  1132.             // Now do the DST adjustment alluded to above.
  1133.             // Only call setTimeInMillis if necessary, because it's an expensive call.
  1134.             dst -= internalGet(DST_OFFSET);
  1135.             if (delta != 0) setTimeInMillis(time + dst);
  1136.         }
  1137.     }
  1138.  
  1139.  
  1140.     /**
  1141.      * Overrides Calendar
  1142.      * Time Field Rolling function.
  1143.      * Rolls (up/down) a single unit of time on the given time field.
  1144.      * @param field the time field.
  1145.      * @param up Indicates if rolling up or rolling down the field value.
  1146.      * @exception IllegalArgumentException if an unknown field value is given.
  1147.      */
  1148.     public void roll(int field, boolean up)
  1149.     {
  1150.         roll(field, up ? +1 : -1);
  1151.     }
  1152.  
  1153.     /**
  1154.      * Roll a field by a signed amount.
  1155.      * Note: This will be made public later. [LIU]
  1156.      */
  1157.     void roll(int field, int amount)
  1158.     {
  1159.         if (amount == 0) return; // Nothing to do
  1160.  
  1161.         complete();
  1162.  
  1163.         int min = getMinimum(field);
  1164.         int max = getMaximum(field);
  1165.         int gap;
  1166.  
  1167.         switch (field) {
  1168.         case ERA:
  1169.         case YEAR:
  1170.         case MONTH:
  1171.         case AM_PM:
  1172.         case HOUR:
  1173.         case HOUR_OF_DAY:
  1174.         case MINUTE:
  1175.         case SECOND:
  1176.         case MILLISECOND:
  1177.             // These fields are handled simply, since they have fixed minima
  1178.             // and maxima.  The field DAY_OF_MONTH is almost as simple.  Other
  1179.             // fields are complicated, since the range within they must roll
  1180.             // varies depending on the date.
  1181.             break;
  1182.  
  1183.         case WEEK_OF_YEAR:
  1184.             {
  1185.                 // This follows the outline of WEEK_OF_MONTH, except it applies
  1186.                 // to the whole year.  Please see the comment for WEEK_OF_MONTH
  1187.                 // for general notes.
  1188.  
  1189.                 // Normalize the DAY_OF_WEEK so that 0 is the first day of the week
  1190.                 // in this locale.  We have dow in 0..6.
  1191.                 int dow = internalGet(DAY_OF_WEEK) - getFirstDayOfWeek();
  1192.                 if (dow < 0) dow += 7;
  1193.  
  1194.                 // Find the day of the week (normalized for locale) for the first
  1195.                 // of the year.
  1196.                 int fdy = (dow - internalGet(DAY_OF_YEAR) + 1) % 7;
  1197.                 if (fdy < 0) fdy += 7;
  1198.  
  1199.                 // Get the first day of the first full week of the year,
  1200.                 // including phantom days, if any.  Figure out if the first week
  1201.                 // counts or not; if it counts, then fill in phantom days.  If
  1202.                 // not, advance to the first real full week (skip the partial week).
  1203.                 int start;
  1204.                 if ((7 - fdy) < getMinimalDaysInFirstWeek())
  1205.                     start = 8 - fdy; // Skip the first partial week
  1206.                 else
  1207.                     start = 1 - fdy; // This may be zero or negative
  1208.  
  1209.                 // Get the day of the week (normalized for locale) for the last
  1210.                 // day of the year.
  1211.                 int yearLen = isLeapYear(internalGet(YEAR)) ? 366 : 365;
  1212.                 int ldy = (yearLen - internalGet(DAY_OF_YEAR) + dow) % 7;
  1213.                 // We know yearLen >= DAY_OF_YEAR so we skip the += 7 step here.
  1214.  
  1215.                 // Get the limit day for the blocked-off rectangular year; that
  1216.                 // is, the day which is one past the last day of the year,
  1217.                 // after the year has already been filled in with phantom days
  1218.                 // to fill out the last week.  This day has a normalized DOW of 0.
  1219.                 int limit = yearLen + 7 - ldy;
  1220.  
  1221.                 // Now roll between start and (limit - 1).
  1222.                 gap = limit - start;
  1223.                 int day_of_year = (internalGet(DAY_OF_YEAR) + amount*7 -
  1224.                                    start) % gap;
  1225.                 if (day_of_year < 0) day_of_year += gap;
  1226.                 day_of_year += start;
  1227.  
  1228.                 // Finally, pin to the real start and end of the month.
  1229.                 if (day_of_year < 1) day_of_year = 1;
  1230.                 if (day_of_year > yearLen) day_of_year = yearLen;
  1231.  
  1232.                 // Make sure that the year and day of year are attended to by
  1233.                 // clearing other fields which would normally take precedence.
  1234.                 // If the disambiguation algorithm is changed, this section will
  1235.                 // have to be updated as well.
  1236.                 set(DAY_OF_YEAR, day_of_year);
  1237.                 clear(MONTH);
  1238.                 return;
  1239.             }
  1240.         case WEEK_OF_MONTH:
  1241.             {
  1242.                 // This is tricky, because during the roll we may have to shift
  1243.                 // to a different day of the week.  For example:
  1244.  
  1245.                 //    s  m  t  w  r  f  s
  1246.                 //          1  2  3  4  5
  1247.                 //    6  7  8  9 10 11 12
  1248.  
  1249.                 // When rolling from the 6th or 7th back one week, we go to the
  1250.                 // 1st (assuming that the first partial week counts).  The same
  1251.                 // thing happens at the end of the month.
  1252.  
  1253.                 // The other tricky thing is that we have to figure out whether
  1254.                 // the first partial week actually counts or not, based on the
  1255.                 // minimal first days in the week.  And we have to use the
  1256.                 // correct first day of the week to delineate the week
  1257.                 // boundaries.
  1258.  
  1259.                 // Here's our algorithm.  First, we find the real boundaries of
  1260.                 // the month.  Then we discard the first partial week if it
  1261.                 // doesn't count in this locale.  Then we fill in the ends with
  1262.                 // phantom days, so that the first partial week and the last
  1263.                 // partial week are full weeks.  We then have a nice square
  1264.                 // block of weeks.  We do the usual rolling within this block,
  1265.                 // as is done elsewhere in this method.  If we wind up on one of
  1266.                 // the phantom days that we added, we recognize this and pin to
  1267.                 // the first or the last day of the month.  Easy, eh?
  1268.  
  1269.                 // Normalize the DAY_OF_WEEK so that 0 is the first day of the week
  1270.                 // in this locale.  We have dow in 0..6.
  1271.                 int dow = internalGet(DAY_OF_WEEK) - getFirstDayOfWeek();
  1272.                 if (dow < 0) dow += 7;
  1273.  
  1274.                 // Find the day of the week (normalized for locale) for the first
  1275.                 // of the month.
  1276.                 int fdm = (dow - internalGet(DAY_OF_MONTH) + 1) % 7;
  1277.                 if (fdm < 0) fdm += 7;
  1278.  
  1279.                 // Get the first day of the first full week of the month,
  1280.                 // including phantom days, if any.  Figure out if the first week
  1281.                 // counts or not; if it counts, then fill in phantom days.  If
  1282.                 // not, advance to the first real full week (skip the partial week).
  1283.                 int start;
  1284.                 if ((7 - fdm) < getMinimalDaysInFirstWeek())
  1285.                     start = 8 - fdm; // Skip the first partial week
  1286.                 else
  1287.                     start = 1 - fdm; // This may be zero or negative
  1288.  
  1289.                 // Get the day of the week (normalized for locale) for the last
  1290.                 // day of the month.
  1291.                 int monthLen = monthLength(internalGet(MONTH), internalGet(YEAR));
  1292.                 int ldm = (monthLen - internalGet(DAY_OF_MONTH) + dow) % 7;
  1293.                 // We know monthLen >= DAY_OF_MONTH so we skip the += 7 step here.
  1294.  
  1295.                 // Get the limit day for the blocked-off rectangular month; that
  1296.                 // is, the day which is one past the last day of the month,
  1297.                 // after the month has already been filled in with phantom days
  1298.                 // to fill out the last week.  This day has a normalized DOW of 0.
  1299.                 int limit = monthLen + 7 - ldm;
  1300.  
  1301.                 // Now roll between start and (limit - 1).
  1302.                 gap = limit - start;
  1303.                 int day_of_month = (internalGet(DAY_OF_MONTH) + amount*7 -
  1304.                                     start) % gap;
  1305.                 if (day_of_month < 0) day_of_month += gap;
  1306.                 day_of_month += start;
  1307.  
  1308.                 // Finally, pin to the real start and end of the month.
  1309.                 if (day_of_month < 1) day_of_month = 1;
  1310.                 if (day_of_month > monthLen) day_of_month = monthLen;
  1311.  
  1312.                 // Set the DAY_OF_MONTH.  We rely on the fact that this field
  1313.                 // takes precedence over everything else (since all other fields
  1314.                 // are also set at this point).  If this fact changes (if the
  1315.                 // disambiguation algorithm changes) then we will have to unset
  1316.                 // the appropriate fields here so that DAY_OF_MONTH is attended
  1317.                 // to.
  1318.                 set(DAY_OF_MONTH, day_of_month);
  1319.                 return;
  1320.             }
  1321.         case DAY_OF_MONTH:
  1322.             max = monthLength(internalGet(MONTH), internalGet(YEAR));
  1323.             break;
  1324.         case DAY_OF_YEAR:
  1325.             {
  1326.                 // Roll the day of year using millis.  Compute the millis for
  1327.                 // the start of the year, and get the length of the year.
  1328.                 long delta = amount * ONE_DAY; // Scale up from days to millis
  1329.                 long min2 = time - (internalGet(DAY_OF_YEAR) - 1) * ONE_DAY;
  1330.                 int yearLength = isLeapYear(internalGet(YEAR)) ? 366 : 365;
  1331.                 time = (time + delta - min2) % (yearLength*ONE_DAY);
  1332.                 if (time < 0) time += yearLength*ONE_DAY;
  1333.                 setTimeInMillis(time + min2);
  1334.                 return;
  1335.             }
  1336.         case DAY_OF_WEEK:
  1337.             {
  1338.                 // Roll the day of week using millis.  Compute the millis for
  1339.                 // the start of the week, using the first day of week setting.
  1340.                 // Restrict the millis to [start, start+7days).
  1341.                 long delta = amount * ONE_DAY; // Scale up from days to millis
  1342.                 // Compute the number of days before the current day in this
  1343.                 // week.  This will be a value 0..6.
  1344.                 int leadDays = internalGet(DAY_OF_WEEK) - getFirstDayOfWeek();
  1345.                 if (leadDays < 0) leadDays += 7;
  1346.                 long min2 = time - leadDays * ONE_DAY;
  1347.                 time = (time + delta - min2) % ONE_WEEK;
  1348.                 if (time < 0) time += ONE_WEEK;
  1349.                 setTimeInMillis(time + min2);
  1350.                 return;
  1351.             }
  1352.         case DAY_OF_WEEK_IN_MONTH:
  1353.             {
  1354.                 // Roll the day of week in the month using millis.  Determine
  1355.                 // the first day of the week in the month, and then the last,
  1356.                 // and then roll within that range.
  1357.                 long delta = amount * ONE_WEEK; // Scale up from weeks to millis
  1358.                 // Find the number of same days of the week before this one
  1359.                 // in this month.
  1360.                 int preWeeks = (internalGet(DAY_OF_MONTH) - 1) / 7;
  1361.                 // Find the number of same days of the week after this one
  1362.                 // in this month.
  1363.                 int postWeeks = (monthLength(internalGet(MONTH), internalGet(YEAR)) -
  1364.                                  internalGet(DAY_OF_MONTH)) / 7;
  1365.                 // From these compute the min and gap millis for rolling.
  1366.                 long min2 = time - preWeeks * ONE_WEEK;
  1367.                 long gap2 = ONE_WEEK * (preWeeks + postWeeks + 1); // Must add 1!
  1368.                 // Roll within this range
  1369.                 time = (time + delta - min2) % gap2;
  1370.                 if (time < 0) time += gap2;
  1371.                 setTimeInMillis(time + min2);
  1372.                 return;
  1373.             }
  1374.         case ZONE_OFFSET:
  1375.         case DST_OFFSET:
  1376.         default:
  1377.             // These fields cannot be rolled
  1378.             throw new IllegalArgumentException();
  1379.         }
  1380.  
  1381.         // These are the standard roll instructions.  These work for all
  1382.         // simple cases, that is, cases in which the limits are fixed, such
  1383.         // as the hour, the month, and the era.
  1384.         gap = max - min + 1;
  1385.         int value = internalGet(field) + amount;
  1386.         value = (value - min) % gap;
  1387.         if (value < 0) value += gap;
  1388.         value += min;
  1389.  
  1390.         set(field, value);
  1391.     }
  1392.  
  1393.     /**
  1394.      * <pre>
  1395.      * Field names Minimum Greatest Minimum Least Maximum Maximum
  1396.      * ----------- ------- ---------------- ------------- -------
  1397.      * ERA 0 0 1 1
  1398.      * YEAR 1 1 5,000,000 5,000,000
  1399.      * MONTH 0 0 11 11
  1400.      * WEEK_OF_YEAR 0 0 53 54
  1401.      * WEEK_OF_MONTH 0 0 4 6
  1402.      * DAY_OF_MONTH 1 1 28 31
  1403.      * DAY_OF_YEAR 1 1 365 366
  1404.      * DAY_OF_WEEK 1 1 7 7
  1405.      * DAY_OF_WEEK_IN_MONTH -1 -1 4 6
  1406.      * AM_PM 0 0 1 1
  1407.      * HOUR 0 0 11 12
  1408.      * HOUR_OF_DAY 0 0 23 23
  1409.      * MINUTE 0 0 59 59
  1410.      * SECOND 0 0 59 59
  1411.      * MILLISECOND 0 0 999 999
  1412.      * ZONE_OFFSET -12*60*60*1000 -12*60*60*1000 12*60*60*1000 12*60*60*1000
  1413.      * DST_OFFSET 0 0 1*60*60*1000 1*60*60*1000
  1414.      * </pre>
  1415.      */
  1416.     private static final int MinValues[]
  1417.     = {0,1,0,0,0,1,1,1,-1,0,0,0,0,0,0,-12*60*60*1000,0};
  1418.     private static final int GreatestMinValues[]
  1419.     = {0,1,0,0,0,1,1,1,-1,0,0,0,0,0,0,-12*60*60*1000,0};// same as MinValues
  1420.     private static final int LeastMaxValues[]
  1421.     = {1,5000000,11,53,4,28,365,7,4,1,11,23,59,59,999,
  1422.        12*60*60*1000,1*60*60*1000};
  1423.     private static final int MaxValues[]
  1424.     = {1,5000000,11,54,6,31,366,7,6,1,12,23,59,59,999,
  1425.        12*60*60*1000,1*60*60*1000};
  1426.  
  1427.     /**
  1428.      * Returns minimum value for the given field.
  1429.      * e.g. for Gregorian DAY_OF_MONTH, 1
  1430.      * Please see Calendar.getMinimum for descriptions on parameters and
  1431.      * the return value.
  1432.      */
  1433.     public int getMinimum(int field)
  1434.     {
  1435.         return MinValues[field];
  1436.     }
  1437.  
  1438.     /**
  1439.      * Returns maximum value for the given field.
  1440.      * e.g. for Gregorian DAY_OF_MONTH, 31
  1441.      * Please see Calendar.getMaximum for descriptions on parameters and
  1442.      * the return value.
  1443.      */
  1444.     public int getMaximum(int field)
  1445.     {
  1446.         return MaxValues[field];
  1447.     }
  1448.  
  1449.     /**
  1450.      * Returns highest minimum value for the given field if varies.
  1451.      * Otherwise same as getMinimum(). For Gregorian, no difference.
  1452.      * Please see Calendar.getGreatestMinimum for descriptions on parameters
  1453.      * and the return value.
  1454.      */
  1455.     public int getGreatestMinimum(int field)
  1456.     {
  1457.         return GreatestMinValues[field];
  1458.     }
  1459.  
  1460.     /**
  1461.      * Returns lowest maximum value for the given field if varies.
  1462.      * Otherwise same as getMaximum(). For Gregorian DAY_OF_MONTH, 28
  1463.      * Please see Calendar.getLeastMaximum for descriptions on parameters and
  1464.      * the return value.
  1465.      */
  1466.     public int getLeastMaximum(int field)
  1467.     {
  1468.         return LeastMaxValues[field];
  1469.     }
  1470.         
  1471.     // Useful millisecond constants
  1472.     private static final long ONE_SECOND = 1000;
  1473.     private static final long ONE_MINUTE = 60*ONE_SECOND;
  1474.     private static final long ONE_HOUR   = 60*ONE_MINUTE;
  1475.     private static final long ONE_DAY    = 24*ONE_HOUR;
  1476.     private static final long ONE_WEEK   = 7*ONE_DAY;
  1477.  
  1478.     // Proclaim serialization compatiblity with JDK 1.1
  1479.     static final long serialVersionUID = -8125100834729963327L;
  1480. }
  1481.