home *** CD-ROM | disk | FTP | other *** search
/ Java 1.2 How-To / JavaHowTo.iso / 3rdParty / jbuilder / unsupported / JDK1.2beta3 / SOURCE / SRC.ZIP / java / util / GregorianCalendar.java < prev    next >
Encoding:
Java Source  |  1998-03-20  |  59.3 KB  |  1,484 lines

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