From 554fd8c5195424bdbcabf5de30fdc183aba391bd Mon Sep 17 00:00:00 2001 From: upstream source tree Date: Sun, 15 Mar 2015 20:14:05 -0400 Subject: obtained gcc-4.6.4.tar.bz2 from upstream website; verified gcc-4.6.4.tar.bz2.sig; imported gcc-4.6.4 source tree from verified upstream tarball. downloading a git-generated archive based on the 'upstream' tag should provide you with a source tree that is binary identical to the one extracted from the above tarball. if you have obtained the source via the command 'git clone', however, do note that line-endings of files in your working directory might differ from line-endings of the respective files in the upstream repository. --- libjava/classpath/java/util/Calendar.java | 1620 +++++++++++++++++++++++++++++ 1 file changed, 1620 insertions(+) create mode 100644 libjava/classpath/java/util/Calendar.java (limited to 'libjava/classpath/java/util/Calendar.java') diff --git a/libjava/classpath/java/util/Calendar.java b/libjava/classpath/java/util/Calendar.java new file mode 100644 index 000000000..8123b1706 --- /dev/null +++ b/libjava/classpath/java/util/Calendar.java @@ -0,0 +1,1620 @@ +/* Calendar.java -- + Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004, 2005, 2006, + Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.util; + +import gnu.java.lang.CPStringBuilder; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; + +import java.text.DateFormatSymbols; + +/** + * This class is an abstract base class for Calendars, which can be + * used to convert between Date objects and a set of + * integer fields which represent YEAR, + * MONTH, DAY, etc. The Date + * object represents a time in milliseconds since the Epoch.
+ * + * This class is locale sensitive. To get the Object matching the + * current locale you can use getInstance. You can even provide + * a locale or a timezone. getInstance returns currently + * a GregorianCalendar for the current date.
+ * + * If you want to convert a date from the Year, Month, Day, DayOfWeek, + * etc. Representation to a Date-Object, you can create + * a new Calendar with getInstance(), + * clear() all fields, set(int,int) the + * fields you need and convert it with getTime().
+ * + * If you want to convert a Date-object to the Calendar + * representation, create a new Calendar, assign the + * Date-Object with setTime(), and read the + * fields with get(int).
+ * + * When computing the date from time fields, it may happen, that there + * are either two few fields set, or some fields are inconsistent. This + * cases will handled in a calendar specific way. Missing fields are + * replaced by the fields of the epoch: 1970 January 1 00:00.
+ * + * To understand, how the day of year is computed out of the fields + * look at the following table. It is traversed from top to bottom, + * and for the first line all fields are set, that line is used to + * compute the day.
+ * + * +
month + day_of_month
+month + week_of_month + day_of_week
+month + day_of_week_of_month + day_of_week
+day_of_year
+day_of_week + week_of_year
+ * + * The hour_of_day-field takes precedence over the ampm and + * hour_of_ampm fields.
+ * + * Note: This can differ for non-Gregorian calendar.
+ * + * To convert a calendar to a human readable form and vice versa, use + * the java.text.DateFormat class.
+ * + * Other useful things you can do with an calendar, is + * rolling fields (that means increase/decrease a + * specific field by one, propagating overflows), or + * adding/substracting a fixed amount to a field. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Jochen Hoenicke (Jochen.Hoenicke@Informatik.Uni-Oldenburg.de) + * @author Warren Levy (warrenl@cygnus.com) + * @author Jeff Sturm (jsturm@one-point.com) + * @author Tom Tromey (tromey@redhat.com) + * @author Bryce McKinlay (mckinlay@redhat.com) + * @author Ingo Proetel (proetel@aicas.com) + * @author Jerry Quinn (jlquinn@optonline.net) + * @author Jeroen Frijters (jeroen@frijters.net) + * @author Noa Resare (noa@resare.com) + * @author Sven de Marothy (sven@physto.se) + * @author David Gilbert (david.gilbert@object-refinery.com) + * @author Olivier Jolly (olivier.jolly@pcedev.com) + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + * @see Date + * @see GregorianCalendar + * @see TimeZone + * @see java.text.DateFormat + */ +public abstract class Calendar + implements Serializable, Cloneable, Comparable +{ + /** + * Constant representing the era time field. + */ + public static final int ERA = 0; + + /** + * Constant representing the year time field. + */ + public static final int YEAR = 1; + + /** + * Constant representing the month time field. This field + * should contain one of the JANUARY,...,DECEMBER constants below. + */ + public static final int MONTH = 2; + + /** + * Constant representing the week of the year field. + * @see #setFirstDayOfWeek(int) + */ + public static final int WEEK_OF_YEAR = 3; + + /** + * Constant representing the week of the month time field. + * @see #setFirstDayOfWeek(int) + */ + public static final int WEEK_OF_MONTH = 4; + + /** + * Constant representing the day time field, synonym for DAY_OF_MONTH. + */ + public static final int DATE = 5; + + /** + * Constant representing the day time field. + */ + public static final int DAY_OF_MONTH = 5; + + /** + * Constant representing the day of year time field. This is + * 1 for the first day in month. + */ + public static final int DAY_OF_YEAR = 6; + + /** + * Constant representing the day of week time field. This field + * should contain one of the SUNDAY,...,SATURDAY constants below. + */ + public static final int DAY_OF_WEEK = 7; + + /** + * Constant representing the day-of-week-in-month field. For + * instance this field contains 2 for the second thursday in a + * month. If you give a negative number here, the day will count + * from the end of the month. + */ + public static final int DAY_OF_WEEK_IN_MONTH = 8; + + /** + * Constant representing the part of the day for 12-hour clock. This + * should be one of AM or PM. + */ + public static final int AM_PM = 9; + + /** + * Constant representing the hour time field for 12-hour clock. + */ + public static final int HOUR = 10; + + /** + * Constant representing the hour of day time field for 24-hour clock. + */ + public static final int HOUR_OF_DAY = 11; + + /** + * Constant representing the minute of hour time field. + */ + public static final int MINUTE = 12; + + /** + * Constant representing the second time field. + */ + public static final int SECOND = 13; + + /** + * Constant representing the millisecond time field. + */ + public static final int MILLISECOND = 14; + + /** + * Constant representing the time zone offset time field for the + * time given in the other fields. It is measured in + * milliseconds. The default is the offset of the time zone. + */ + public static final int ZONE_OFFSET = 15; + + /** + * Constant representing the daylight saving time offset in + * milliseconds. The default is the value given by the time zone. + */ + public static final int DST_OFFSET = 16; + + /** + * Number of time fields. + */ + public static final int FIELD_COUNT = 17; + + /** + * Constant representing Sunday. + */ + public static final int SUNDAY = 1; + + /** + * Constant representing Monday. + */ + public static final int MONDAY = 2; + + /** + * Constant representing Tuesday. + */ + public static final int TUESDAY = 3; + + /** + * Constant representing Wednesday. + */ + public static final int WEDNESDAY = 4; + + /** + * Constant representing Thursday. + */ + public static final int THURSDAY = 5; + + /** + * Constant representing Friday. + */ + public static final int FRIDAY = 6; + + /** + * Constant representing Saturday. + */ + public static final int SATURDAY = 7; + + /** + * Constant representing January. + */ + public static final int JANUARY = 0; + + /** + * Constant representing February. + */ + public static final int FEBRUARY = 1; + + /** + * Constant representing March. + */ + public static final int MARCH = 2; + + /** + * Constant representing April. + */ + public static final int APRIL = 3; + + /** + * Constant representing May. + */ + public static final int MAY = 4; + + /** + * Constant representing June. + */ + public static final int JUNE = 5; + + /** + * Constant representing July. + */ + public static final int JULY = 6; + + /** + * Constant representing August. + */ + public static final int AUGUST = 7; + + /** + * Constant representing September. + */ + public static final int SEPTEMBER = 8; + + /** + * Constant representing October. + */ + public static final int OCTOBER = 9; + + /** + * Constant representing November. + */ + public static final int NOVEMBER = 10; + + /** + * Constant representing December. + */ + public static final int DECEMBER = 11; + + /** + * Constant representing Undecimber. This is an artificial name useful + * for lunar calendars. + */ + public static final int UNDECIMBER = 12; + + /** + * Useful constant for 12-hour clock. + */ + public static final int AM = 0; + + /** + * Useful constant for 12-hour clock. + */ + public static final int PM = 1; + + /** + * A style specifier for {@link #getDisplayNames(int,int,Locale)} + * stating that names should be returned in both long and short variants. + * + * @since 1.6 + * @see #SHORT + * @see #LONG + */ + public static final int ALL_STYLES = 0; + + /** + * A style specifier for {@link #getDisplayName(int,int,Locale)} + * and {@link #getDisplayNames(int,int,Locale)} stating that names + * should be returned in their short variant if applicable. + * + * @since 1.6 + */ + public static final int SHORT = 1; + + /** + * A style specifier for {@link #getDisplayName(int,int,Locale)} + * and {@link #getDisplayNames(int,int,Locale)} stating that names + * should be returned in their long variant if applicable. + * + * @since 1.6 + */ + public static final int LONG = 2; + + /** + * The time fields. The array is indexed by the constants YEAR to + * DST_OFFSET. + * @serial + */ + protected int[] fields = new int[FIELD_COUNT]; + + /** + * The flags which tell if the fields above have a value. + * @serial + */ + protected boolean[] isSet = new boolean[FIELD_COUNT]; + + /** + * The time in milliseconds since the epoch. + * @serial + */ + protected long time; + + /** + * Tells if the above field has a valid value. + * @serial + */ + protected boolean isTimeSet; + + /** + * Tells if the fields have a valid value. This superseeds the isSet + * array. + * @serial + */ + protected boolean areFieldsSet; + + /** + * The time zone of this calendar. Used by sub classes to do UTC / local + * time conversion. Sub classes can access this field with getTimeZone(). + * @serial + */ + private TimeZone zone; + + /** + * This is the default calendar class, that is returned on + * java.util.Calendar.getInstance(). + * XXX - this isn't localized anywhere, is it? + * @see java.util.Calendar#getInstance() + */ + private static final String calendarClassName = "java.util.GregorianCalendar"; + + /** + * Specifies if the date/time interpretation should be lenient. + * If the flag is set, a date such as "February 30, 1996" will be + * treated as the 29th day after the February 1. If this flag + * is false, such dates will cause an exception. + * @serial + */ + private boolean lenient; + + /** + * Sets what the first day of week is. This is used for + * WEEK_OF_MONTH and WEEK_OF_YEAR fields. + * @serial + */ + private int firstDayOfWeek; + + /** + * Sets how many days are required in the first week of the year. + * If the first day of the year should be the first week you should + * set this value to 1. If the first week must be a full week, set + * it to 7. + * @serial + */ + private int minimalDaysInFirstWeek; + + /** + * Is set to true if DST_OFFSET is explicitly set. In that case + * it's value overrides the value computed from the current + * time and the timezone. + */ + private boolean explicitDSTOffset = false; + + /** + * The version of the serialized data on the stream. + *
0 or not present
+ *
JDK 1.1.5 or later.
+ *
1
+ *
JDK 1.1.6 or later. This always writes a correct `time' value + * on the stream, as well as the other fields, to be compatible with + * earlier versions
+ * @since JDK1.1.6 + * @serial + */ + private int serialVersionOnStream = 1; + + /** + * XXX - I have not checked the compatibility. The documentation of + * the serialized-form is quite hairy... + */ + static final long serialVersionUID = -1807547505821590642L; + + /** + * The name of the resource bundle. Used only by getBundle() + */ + private static final String bundleName = "gnu.java.locale.LocaleInformation"; + + /** + * get resource bundle: + * The resources should be loaded via this method only. Iff an application + * uses this method, the resourcebundle is required. + */ + private static ResourceBundle getBundle(Locale locale) + { + return ResourceBundle.getBundle(bundleName, locale, + ClassLoader.getSystemClassLoader()); + } + + /** + * The set of properties for obtaining the minimum number of days in + * the first week. + */ + private static transient final Properties properties; + + /** + * Reads in the properties. + */ + static + { + properties = new Properties(); + try + { + properties.load(Calendar.class.getResourceAsStream("weeks.properties")); + } + catch (IOException exception) + { + System.out.println("Failed to load weeks resource: " + exception); + } + } + + /** + * Constructs a new Calendar with the default time zone and the default + * locale. + */ + protected Calendar() + { + this(TimeZone.getDefault(), Locale.getDefault()); + } + + /** + * Constructs a new Calendar with the given time zone and the given + * locale. + * @param zone a time zone. + * @param locale a locale. + */ + protected Calendar(TimeZone zone, Locale locale) + { + this.zone = zone; + lenient = true; + String[] days = { "", "sun", "mon", "tue", "wed", "thu", "fri", "sat" }; + + String country = locale.getCountry(); + String min = properties.getProperty("minDays." + country); + if (min == null) + min = properties.getProperty("minDays.DEFAULT"); + String first = properties.getProperty("firstDay." + country); + if (first == null) + first = properties.getProperty("firstDay.DEFAULT"); + try + { + if (min != null) + minimalDaysInFirstWeek = Integer.parseInt(min); + } + catch (NumberFormatException ex) + { + minimalDaysInFirstWeek = 1; + } + + firstDayOfWeek = 1; + if (first != null) + for (int i = 0; i < 8; i++) + if (days[i].equals(first)) + firstDayOfWeek = i; + + clear(); + } + + /** + * Creates a calendar representing the actual time, using the default + * time zone and locale. + * + * @return The new calendar. + */ + public static synchronized Calendar getInstance() + { + return getInstance(TimeZone.getDefault(), Locale.getDefault()); + } + + /** + * Creates a calendar representing the actual time, using the given + * time zone and the default locale. + * + * @param zone a time zone (null not permitted). + * + * @return The new calendar. + * + * @throws NullPointerException if zone is null. + */ + public static synchronized Calendar getInstance(TimeZone zone) + { + return getInstance(zone, Locale.getDefault()); + } + + /** + * Creates a calendar representing the actual time, using the default + * time zone and the given locale. + * + * @param locale a locale (null not permitted). + * + * @return The new calendar. + * + * @throws NullPointerException if locale is null. + */ + public static synchronized Calendar getInstance(Locale locale) + { + return getInstance(TimeZone.getDefault(), locale); + } + + /** + * Cache of locale->calendar-class mappings. This avoids having to do a ResourceBundle + * lookup for every getInstance call. + */ + private static final HashMap cache = new HashMap(); + + /** Preset argument types for calendar-class constructor lookup. */ + private static Class[] ctorArgTypes = new Class[] + { + TimeZone.class, Locale.class + }; + + /** + * Creates a calendar representing the actual time, using the given + * time zone and locale. + * + * @param zone a time zone (null not permitted). + * @param locale a locale (null not permitted). + * + * @return The new calendar. + * + * @throws NullPointerException if zone or locale + * is null. + */ + public static synchronized Calendar getInstance(TimeZone zone, Locale locale) + { + Class calendarClass = cache.get(locale); + Throwable exception = null; + + try + { + if (calendarClass == null) + { + calendarClass = Class.forName(calendarClassName); + if (Calendar.class.isAssignableFrom(calendarClass)) + cache.put(locale, calendarClass); + } + + // GregorianCalendar is by far the most common case. Optimize by + // avoiding reflection. + if (calendarClass == GregorianCalendar.class) + return new GregorianCalendar(zone, locale); + + if (Calendar.class.isAssignableFrom(calendarClass)) + { + Constructor ctor = calendarClass.getConstructor(ctorArgTypes); + return (Calendar) ctor.newInstance(new Object[] { zone, locale }); + } + } + catch (ClassNotFoundException ex) + { + exception = ex; + } + catch (IllegalAccessException ex) + { + exception = ex; + } + catch (NoSuchMethodException ex) + { + exception = ex; + } + catch (InstantiationException ex) + { + exception = ex; + } + catch (InvocationTargetException ex) + { + exception = ex; + } + + throw new RuntimeException("Error instantiating calendar for locale " + + locale, exception); + } + + /** + * Gets the set of locales for which a Calendar is available. + * @exception MissingResourceException if locale data couldn't be found. + * @return the set of locales. + */ + public static synchronized Locale[] getAvailableLocales() + { + ResourceBundle rb = getBundle(new Locale("", "")); + return (Locale[]) rb.getObject("availableLocales"); + } + + /** + * Converts the time field values (fields) to + * milliseconds since the epoch UTC (time). Override + * this method if you write your own Calendar. */ + protected abstract void computeTime(); + + /** + * Converts the milliseconds since the epoch UTC + * (time) to time fields + * (fields). Override this method if you write your + * own Calendar. + */ + protected abstract void computeFields(); + + /** + * Converts the time represented by this object to a + * Date-Object. + * @return the Date. + */ + public final Date getTime() + { + if (! isTimeSet) + computeTime(); + return new Date(time); + } + + /** + * Sets this Calendar's time to the given Date. All time fields + * are invalidated by this method. + * + * @param date the date (null not permitted). + * + * @throws NullPointerException if date is null. + */ + public final void setTime(Date date) + { + setTimeInMillis(date.getTime()); + } + + /** + * Returns the time represented by this Calendar. + * @return the time in milliseconds since the epoch. + * @specnote This was made public in 1.4. + */ + public long getTimeInMillis() + { + if (! isTimeSet) + computeTime(); + return time; + } + + /** + * Sets this Calendar's time to the given Time. All time fields + * are invalidated by this method. + * @param time the time in milliseconds since the epoch + * @specnote This was made public in 1.4. + */ + public void setTimeInMillis(long time) + { + clear(); + this.time = time; + isTimeSet = true; + computeFields(); + } + + /** + * Gets the value of the specified field. They are recomputed + * if they are invalid. + * @param field the time field. One of the time field constants. + * @return the value of the specified field + * @throws ArrayIndexOutOfBoundsException if the field is outside + * the valid range. The value of field must be >= 0 and + * <= FIELD_COUNT. + * @specnote Not final since JDK 1.4 + */ + public int get(int field) + { + // If the requested field is invalid, force all fields to be recomputed. + if (! isSet[field]) + areFieldsSet = false; + complete(); + return fields[field]; + } + + /** + * Gets the value of the specified field. This method doesn't + * recompute the fields, if they are invalid. + * @param field the time field. One of the time field constants. + * @return the value of the specified field, undefined if + * areFieldsSet or isSet[field] is false. + * @throws ArrayIndexOutOfBoundsException if the field is outside + * the valid range. The value of field must be >= 0 and + * <= FIELD_COUNT. + */ + protected final int internalGet(int field) + { + return fields[field]; + } + + /** + * Sets the time field with the given value. This does invalidate + * the time in milliseconds. + * @param field the time field. One of the time field constants + * @param value the value to be set. + * @throws ArrayIndexOutOfBoundsException if field is outside + * the valid range. The value of field must be >= 0 and + * <= FIELD_COUNT. + * @specnote Not final since JDK 1.4 + */ + public void set(int field, int value) + { + if (isTimeSet) + for (int i = 0; i < FIELD_COUNT; i++) + isSet[i] = false; + isTimeSet = false; + fields[field] = value; + isSet[field] = true; + + // The five valid date patterns, in order of priority + // 1 YEAR + MONTH + DAY_OF_MONTH + // 2 YEAR + MONTH + WEEK_OF_MONTH + DAY_OF_WEEK + // 3 YEAR + MONTH + DAY_OF_WEEK_IN_MONTH + DAY_OF_WEEK + // 4 YEAR + DAY_OF_YEAR + // 5 YEAR + DAY_OF_WEEK + WEEK_OF_YEAR + switch (field) + { + case MONTH: // pattern 1,2 or 3 + isSet[DAY_OF_YEAR] = false; + isSet[WEEK_OF_YEAR] = false; + break; + case DAY_OF_MONTH: // pattern 1 + isSet[YEAR] = true; + isSet[MONTH] = true; + isSet[WEEK_OF_MONTH] = true; + isSet[DAY_OF_WEEK] = false; + isSet[DAY_OF_WEEK_IN_MONTH] = false; + isSet[DAY_OF_YEAR] = false; + isSet[WEEK_OF_YEAR] = false; + break; + case WEEK_OF_MONTH: // pattern 2 + if (! isSet[DAY_OF_WEEK]) + fields[DAY_OF_WEEK] = getFirstDayOfWeek(); + isSet[YEAR] = true; + isSet[MONTH] = true; + isSet[DAY_OF_WEEK] = true; + isSet[DAY_OF_MONTH] = false; + isSet[DAY_OF_WEEK_IN_MONTH] = false; + isSet[DAY_OF_YEAR] = false; + isSet[WEEK_OF_YEAR] = false; + break; + case DAY_OF_WEEK_IN_MONTH: // pattern 3 + if (! isSet[DAY_OF_WEEK]) + fields[DAY_OF_WEEK] = getFirstDayOfWeek(); + isSet[YEAR] = true; + isSet[MONTH] = true; + isSet[DAY_OF_WEEK] = true; + isSet[DAY_OF_YEAR] = false; + isSet[DAY_OF_MONTH] = false; + isSet[WEEK_OF_MONTH] = false; + isSet[WEEK_OF_YEAR] = false; + break; + case DAY_OF_YEAR: // pattern 4 + isSet[YEAR] = true; + isSet[MONTH] = false; + isSet[WEEK_OF_MONTH] = false; + isSet[DAY_OF_MONTH] = false; + isSet[DAY_OF_WEEK] = false; + isSet[WEEK_OF_YEAR] = false; + isSet[DAY_OF_WEEK_IN_MONTH] = false; + break; + case WEEK_OF_YEAR: // pattern 5 + if (! isSet[DAY_OF_WEEK]) + fields[DAY_OF_WEEK] = getFirstDayOfWeek(); + isSet[YEAR] = true; + isSet[DAY_OF_WEEK] = true; + isSet[MONTH] = false; + isSet[DAY_OF_MONTH] = false; + isSet[WEEK_OF_MONTH] = false; + isSet[DAY_OF_YEAR] = false; + isSet[DAY_OF_WEEK_IN_MONTH] = false; + break; + case AM_PM: + isSet[HOUR] = true; + isSet[HOUR_OF_DAY] = false; + break; + case HOUR_OF_DAY: + isSet[AM_PM] = false; + isSet[HOUR] = false; + break; + case HOUR: + isSet[AM_PM] = true; + isSet[HOUR_OF_DAY] = false; + break; + case DST_OFFSET: + explicitDSTOffset = true; + } + + // May have crossed over a DST boundary. + if (! explicitDSTOffset && (field != DST_OFFSET && field != ZONE_OFFSET)) + isSet[DST_OFFSET] = false; + } + + /** + * Sets the fields for year, month, and date + * @param year the year. + * @param month the month, one of the constants JANUARY..UNDICEMBER. + * @param date the day of the month + */ + public final void set(int year, int month, int date) + { + isTimeSet = false; + fields[YEAR] = year; + fields[MONTH] = month; + fields[DATE] = date; + isSet[YEAR] = isSet[MONTH] = isSet[DATE] = true; + isSet[WEEK_OF_YEAR] = false; + isSet[DAY_OF_YEAR] = false; + isSet[WEEK_OF_MONTH] = false; + isSet[DAY_OF_WEEK] = false; + isSet[DAY_OF_WEEK_IN_MONTH] = false; + isSet[ERA] = false; + + if (! explicitDSTOffset) + isSet[DST_OFFSET] = false; // May have crossed a DST boundary. + } + + /** + * Sets the fields for year, month, date, hour, and minute + * @param year the year. + * @param month the month, one of the constants JANUARY..UNDICEMBER. + * @param date the day of the month + * @param hour the hour of day. + * @param minute the minute. + */ + public final void set(int year, int month, int date, int hour, int minute) + { + set(year, month, date); + fields[HOUR_OF_DAY] = hour; + fields[MINUTE] = minute; + isSet[HOUR_OF_DAY] = isSet[MINUTE] = true; + isSet[AM_PM] = false; + isSet[HOUR] = false; + } + + /** + * Sets the fields for year, month, date, hour, and minute + * @param year the year. + * @param month the month, one of the constants JANUARY..UNDICEMBER. + * @param date the day of the month + * @param hour the hour of day. + * @param minute the minute. + * @param second the second. + */ + public final void set(int year, int month, int date, int hour, int minute, + int second) + { + set(year, month, date, hour, minute); + fields[SECOND] = second; + isSet[SECOND] = true; + } + + /** + * Clears the values of all the time fields. + */ + public final void clear() + { + isTimeSet = false; + areFieldsSet = false; + int zoneOffs = zone.getRawOffset(); + int[] tempFields = + { + 1, 1970, JANUARY, 1, 1, 1, 1, THURSDAY, 1, AM, 0, 0, 0, + 0, 0, zoneOffs, 0 + }; + fields = tempFields; + for (int i = 0; i < FIELD_COUNT; i++) + isSet[i] = false; + } + + /** + * Clears the values of the specified time field. + * @param field the time field. One of the time field constants. + * @throws ArrayIndexOutOfBoundsException if field is outside + * the valid range. The value of field must be >= 0 and + * <= FIELD_COUNT. + */ + public final void clear(int field) + { + int[] tempFields = + { + 1, 1970, JANUARY, 1, 1, 1, 1, THURSDAY, 1, AM, 0, 0, 0, + 0, 0, zone.getRawOffset(), 0 + }; + complete(); + isTimeSet = false; + areFieldsSet = false; + isSet[field] = false; + fields[field] = tempFields[field]; + } + + /** + * Determines if the specified field has a valid value. + * @return true if the specified field has a value. + * @throws ArrayIndexOutOfBoundsException if the field is outside + * the valid range. The value of field must be >= 0 and + * <= FIELD_COUNT. + */ + public final boolean isSet(int field) + { + return isSet[field]; + } + + /** + * Fills any unset fields in the time field list + */ + protected void complete() + { + if (! isTimeSet) + computeTime(); + if (! areFieldsSet) + computeFields(); + } + + /** + * Compares the given calendar with this. + * @param o the object to that we should compare. + * @return true, if the given object is a calendar, that represents + * the same time (but doesn't necessary have the same fields). + */ + public boolean equals(Object o) + { + if (! (o instanceof Calendar)) + return false; + Calendar cal = (Calendar) o; + if (getTimeInMillis() == ((Calendar) o).getTimeInMillis() + && cal.getFirstDayOfWeek() == getFirstDayOfWeek() + && cal.isLenient() == isLenient() + && cal.getMinimalDaysInFirstWeek() == getMinimalDaysInFirstWeek()) + { + TimeZone self = getTimeZone(); + TimeZone oth = cal.getTimeZone(); + return self == null ? oth == null : self.equals(oth); + } + return false; + } + + /** + * Returns a hash code for this calendar. + * @return a hash code, which fullfits the general contract of + * hashCode() + */ + public int hashCode() + { + long time = getTimeInMillis(); + int val = (int) ((time & 0xffffffffL) ^ (time >> 32)); + val += (getFirstDayOfWeek() + (isLenient() ? 1230 : 1237) + + getMinimalDaysInFirstWeek()); + TimeZone self = getTimeZone(); + if (self != null) + val ^= self.hashCode(); + return val; + } + + /** + * Compares the given calendar with this. + * @param o the object to that we should compare. + * @return true, if the given object is a calendar, and this calendar + * represents a smaller time than the calendar o. + * @exception ClassCastException if o is not an calendar. + * @since JDK1.2 you don't need to override this method + */ + public boolean before(Object o) + { + return getTimeInMillis() < ((Calendar) o).getTimeInMillis(); + } + + /** + * Compares the given calendar with this. + * @param o the object to that we should compare. + * @return true, if the given object is a calendar, and this calendar + * represents a bigger time than the calendar o. + * @exception ClassCastException if o is not an calendar. + * @since JDK1.2 you don't need to override this method + */ + public boolean after(Object o) + { + return getTimeInMillis() > ((Calendar) o).getTimeInMillis(); + } + + /** + * Adds the specified amount of time to the given time field. The + * amount may be negative to subtract the time. If the field overflows + * it does what you expect: Jan, 25 + 10 Days is Feb, 4. + * @param field the time field. One of the time field constants. + * @param amount the amount of time. + * @throws ArrayIndexOutOfBoundsException if the field is outside + * the valid range. The value of field must be >= 0 and + * <= FIELD_COUNT. + */ + public abstract void add(int field, int amount); + + /** + * Rolls the specified time field up or down. This means add one + * to the specified field, but don't change the other fields. If + * the maximum for this field is reached, start over with the + * minimum value.
+ * + * Note: There may be situation, where the other + * fields must be changed, e.g rolling the month on May, 31. + * The date June, 31 is automatically converted to July, 1. + * @param field the time field. One of the time field constants. + * @param up the direction, true for up, false for down. + * @throws ArrayIndexOutOfBoundsException if the field is outside + * the valid range. The value of field must be >= 0 and + * <= FIELD_COUNT. + */ + public abstract void roll(int field, boolean up); + + /** + * Rolls up or down the specified time field by the given amount. + * A negative amount rolls down. The default implementation is + * call roll(int, boolean) for the specified amount. + * + * Subclasses should override this method to do more intuitiv things. + * + * @param field the time field. One of the time field constants. + * @param amount the amount to roll by, positive for rolling up, + * negative for rolling down. + * @throws ArrayIndexOutOfBoundsException if the field is outside + * the valid range. The value of field must be >= 0 and + * <= FIELD_COUNT. + * @since JDK1.2 + */ + public void roll(int field, int amount) + { + while (amount > 0) + { + roll(field, true); + amount--; + } + while (amount < 0) + { + roll(field, false); + amount++; + } + } + + /** + * Sets the time zone to the specified value. + * @param zone the new time zone + */ + public void setTimeZone(TimeZone zone) + { + this.zone = zone; + computeTime(); + computeFields(); + } + + /** + * Gets the time zone of this calendar + * @return the current time zone. + */ + public TimeZone getTimeZone() + { + return zone; + } + + /** + * Specifies if the date/time interpretation should be lenient. + * If the flag is set, a date such as "February 30, 1996" will be + * treated as the 29th day after the February 1. If this flag + * is false, such dates will cause an exception. + * @param lenient true, if the date should be interpreted linient, + * false if it should be interpreted strict. + */ + public void setLenient(boolean lenient) + { + this.lenient = lenient; + } + + /** + * Tells if the date/time interpretation is lenient. + * @return true, if the date should be interpreted linient, + * false if it should be interpreted strict. + */ + public boolean isLenient() + { + return lenient; + } + + /** + * Sets what the first day of week is. This is used for + * WEEK_OF_MONTH and WEEK_OF_YEAR fields. + * @param value the first day of week. One of SUNDAY to SATURDAY. + */ + public void setFirstDayOfWeek(int value) + { + firstDayOfWeek = value; + } + + /** + * Gets what the first day of week is. This is used for + * WEEK_OF_MONTH and WEEK_OF_YEAR fields. + * @return the first day of week. One of SUNDAY to SATURDAY. + */ + public int getFirstDayOfWeek() + { + return firstDayOfWeek; + } + + /** + * Sets how many days are required in the first week of the year. + * If the first day of the year should be the first week you should + * set this value to 1. If the first week must be a full week, set + * it to 7. + * @param value the minimal days required in the first week. + */ + public void setMinimalDaysInFirstWeek(int value) + { + minimalDaysInFirstWeek = value; + } + + /** + * Gets how many days are required in the first week of the year. + * @return the minimal days required in the first week. + * @see #setMinimalDaysInFirstWeek + */ + public int getMinimalDaysInFirstWeek() + { + return minimalDaysInFirstWeek; + } + + /** + * Gets the smallest value that is allowed for the specified field. + * @param field the time field. One of the time field constants. + * @return the smallest value. + */ + public abstract int getMinimum(int field); + + /** + * Gets the biggest value that is allowed for the specified field. + * @param field the time field. One of the time field constants. + * @return the biggest value. + */ + public abstract int getMaximum(int field); + + /** + * Gets the greatest minimum value that is allowed for the specified field. + * @param field the time field. One of the time field constants. + * @return the greatest minimum value. + */ + public abstract int getGreatestMinimum(int field); + + /** + * Gets the smallest maximum value that is allowed for the + * specified field. For example this is 28 for DAY_OF_MONTH. + * @param field the time field. One of the time field constants. + * @return the least maximum value. + */ + public abstract int getLeastMaximum(int field); + + /** + * Gets the actual minimum value that is allowed for the specified field. + * This value is dependent on the values of the other fields. + * @param field the time field. One of the time field constants. + * @return the actual minimum value. + * @throws ArrayIndexOutOfBoundsException if the field is outside + * the valid range. The value of field must be >= 0 and + * <= FIELD_COUNT. + * @since jdk1.2 + */ + public int getActualMinimum(int field) + { + Calendar tmp = (Calendar) clone(); // To avoid restoring state + int min = tmp.getGreatestMinimum(field); + int end = tmp.getMinimum(field); + tmp.set(field, min); + for (; min > end; min--) + { + tmp.add(field, -1); // Try to get smaller + if (tmp.get(field) != min - 1) + break; // Done if not successful + } + return min; + } + + /** + * Gets the actual maximum value that is allowed for the specified field. + * This value is dependent on the values of the other fields. + * @param field the time field. One of the time field constants. + * @return the actual maximum value. + * @throws ArrayIndexOutOfBoundsException if the field is outside + * the valid range. The value of field must be >= 0 and + * <= FIELD_COUNT. + * @since jdk1.2 + */ + public int getActualMaximum(int field) + { + Calendar tmp = (Calendar) clone(); // To avoid restoring state + int max = tmp.getLeastMaximum(field); + int end = tmp.getMaximum(field); + tmp.set(field, max); + for (; max < end; max++) + { + tmp.add(field, 1); + if (tmp.get(field) != max + 1) + break; + } + return max; + } + + /** + * Compares the time of two calendar instances. + * @param cal the calendar to which the time should be compared. + * @return 0 if the two calendars are set to the same time, + * less than 0 if the time of this calendar is before that of + * cal, or more than 0 if the time of this calendar is after + * that of cal. + * + * @param cal the calendar to compare this instance with. + * @throws NullPointerException if cal is null. + * @throws IllegalArgumentException if either calendar has fields set to + * invalid values. + * @since 1.5 + */ + public int compareTo(Calendar cal) + { + long t1 = getTimeInMillis(); + long t2 = cal.getTimeInMillis(); + if(t1 == t2) + return 0; + if(t1 > t2) + return 1; + return -1; + } + + /** + * Return a clone of this object. + */ + public Object clone() + { + try + { + Calendar cal = (Calendar) super.clone(); + cal.fields = (int[]) fields.clone(); + cal.isSet = (boolean[]) isSet.clone(); + return cal; + } + catch (CloneNotSupportedException ex) + { + return null; + } + } + + private static final String[] fieldNames = + { + ",ERA=", ",YEAR=", ",MONTH=", + ",WEEK_OF_YEAR=", + ",WEEK_OF_MONTH=", + ",DAY_OF_MONTH=", + ",DAY_OF_YEAR=", ",DAY_OF_WEEK=", + ",DAY_OF_WEEK_IN_MONTH=", + ",AM_PM=", ",HOUR=", + ",HOUR_OF_DAY=", ",MINUTE=", + ",SECOND=", ",MILLISECOND=", + ",ZONE_OFFSET=", ",DST_OFFSET=" + }; + + /** + * Returns a string representation of this object. It is mainly + * for debugging purposes and its content is implementation + * specific. + */ + public String toString() + { + CPStringBuilder sb = new CPStringBuilder(getClass().getName()); + sb.append('['); + sb.append("time="); + if (isTimeSet) + sb.append(time); + else + sb.append("?"); + sb.append(",zone=" + zone); + sb.append(",areFieldsSet=" + areFieldsSet); + for (int i = 0; i < FIELD_COUNT; i++) + { + sb.append(fieldNames[i]); + if (isSet[i]) + sb.append(fields[i]); + else + sb.append("?"); + } + sb.append(",lenient=").append(lenient); + sb.append(",firstDayOfWeek=").append(firstDayOfWeek); + sb.append(",minimalDaysInFirstWeek=").append(minimalDaysInFirstWeek); + sb.append("]"); + return sb.toString(); + } + + /** + * Saves the state of the object to the stream. Ideally we would + * only write the time field, but we need to be compatible with + * earlier versions.
+ * + * This doesn't write the JDK1.1 field nextStamp to the stream, as + * I don't know what it is good for, and because the documentation + * says, that it could be omitted. */ + private void writeObject(ObjectOutputStream stream) throws IOException + { + if (! isTimeSet) + computeTime(); + stream.defaultWriteObject(); + } + + /** + * Reads the object back from stream (deserialization). + */ + private void readObject(ObjectInputStream stream) + throws IOException, ClassNotFoundException + { + stream.defaultReadObject(); + if (! isTimeSet) + computeTime(); + + if (serialVersionOnStream > 1) + { + // This is my interpretation of the serial number: + // Sun wants to remove all fields from the stream someday + // and will then increase the serialVersion number again. + // We prepare to be compatible. + fields = new int[FIELD_COUNT]; + isSet = new boolean[FIELD_COUNT]; + areFieldsSet = false; + } + } + + /** + * Returns a localised textual representation of the current value + * of the given field using the specified style. If there is no + * applicable textual representation (e.g. the field has a numeric + * value), then null is returned. If one does exist, + * then the value is obtained from {@link #get(int)} and converted + * appropriately. For example, if the MONTH field is + * requested, then get(MONTH) is called. This is then + * converted to a textual representation based on its value and + * the style requested; if the LONG style is requested + * and the returned value is 11 from a + * {@link GregorianCalendar} implementation, then "December" + * is returned. By default, a textual representation is available + * for all fields which have an applicable value obtainable from + * {@link java.text.DateFormatSymbols}. + * + * @param field the calendar field whose textual representation should + * be obtained. + * @param style the style to use; either {@link #LONG} or {@link #SHORT}. + * @param locale the locale to use for translation. + * @return the textual representation of the given field in the specified + * style, or null if none is applicable. + * @throws IllegalArgumentException if field or style + * or invalid, or the calendar is non-lenient + * and has invalid values. + * @throws NullPointerException if locale is null. + * @since 1.6 + */ + public String getDisplayName(int field, int style, Locale locale) + { + if (field < 0 || field >= FIELD_COUNT) + throw new IllegalArgumentException("The field value, " + field + + ", is invalid."); + if (style != SHORT && style != LONG) + throw new IllegalArgumentException("The style must be either " + + "short or long."); + if (field == YEAR || field == WEEK_OF_YEAR || + field == WEEK_OF_MONTH || field == DAY_OF_MONTH || + field == DAY_OF_YEAR || field == DAY_OF_WEEK_IN_MONTH || + field == HOUR || field == HOUR_OF_DAY || field == MINUTE || + field == SECOND || field == MILLISECOND) + return null; + + int value = get(field); + DateFormatSymbols syms = DateFormatSymbols.getInstance(locale); + if (field == ERA) + return syms.getEras()[value]; + if (field == MONTH) + if (style == LONG) + return syms.getMonths()[value]; + else + return syms.getShortMonths()[value]; + if (field == DAY_OF_WEEK) + if (style == LONG) + return syms.getWeekdays()[value]; + else + return syms.getShortWeekdays()[value]; + if (field == AM_PM) + return syms.getAmPmStrings()[value]; + if (field == ZONE_OFFSET) + if (style == LONG) + return syms.getZoneStrings()[value][1]; + else + return syms.getZoneStrings()[value][2]; + if (field == DST_OFFSET) + if (style == LONG) + return syms.getZoneStrings()[value][3]; + else + return syms.getZoneStrings()[value][4]; + + throw new InternalError("Failed to resolve field " + field + + " with style " + style + " for locale " + + locale); + } + + /** + * Returns a map linking all specified textual representations + * of the given field to their numerical values. The textual + * representations included are determined by the specified + * style and locale. For example, if the style LONG + * is specified and the German locale, then the map will + * contain "Montag" to {@link #MONDAY}, "Dienstag" to + * {@link #TUESDAY}, "Mittwoch" to {@link #WEDNESDAY} and + * so on. The default implementation uses the values returned + * by {@link DateFormatSymbols} so, for example, the style + * {@link #ALL_STYLES} and the field {@link #MONTH} will return + * a map filled with the values returned from + * {@link DateFormatSymbols#getMonths()} and + * {@link DateFormatSymbols#getShortMonths()}. If there are + * no textual representations for a given field (usually because + * it is purely numeric, such as the year in the + * {@link GregorianCalendar}), null is returned. + * + * @param field the calendar field whose textual representation should + * be obtained. + * @param style the style to use; either {@link #LONG}, {@link #SHORT} + * or {@link ALL_STYLES}. + * @param locale the locale to use for translation. + * @return a map of the textual representations of the given field in the + * specified style to their numeric values, or null + * if none is applicable. + * @throws IllegalArgumentException if field or style + * or invalid, or the calendar is non-lenient + * and has invalid values. + * @throws NullPointerException if locale is null. + * @since 1.6 + */ + public Map getDisplayNames(int field, int style, Locale locale) + { + if (field < 0 || field >= FIELD_COUNT) + throw new IllegalArgumentException("The field value, " + field + + ", is invalid."); + if (style != SHORT && style != LONG && style != ALL_STYLES) + throw new IllegalArgumentException("The style must be either " + + "short, long or all styles."); + if (field == YEAR || field == WEEK_OF_YEAR || + field == WEEK_OF_MONTH || field == DAY_OF_MONTH || + field == DAY_OF_YEAR || field == DAY_OF_WEEK_IN_MONTH || + field == HOUR || field == HOUR_OF_DAY || field == MINUTE || + field == SECOND || field == MILLISECOND) + return null; + + DateFormatSymbols syms = DateFormatSymbols.getInstance(locale); + Map map = new HashMap(); + if (field == ERA) + { + String[] eras = syms.getEras(); + for (int a = 0; a < eras.length; ++a) + map.put(eras[a], a); + return map; + } + if (field == MONTH) + { + if (style == LONG || style == ALL_STYLES) + { + String[] months = syms.getMonths(); + for (int a = 0; a < months.length; ++a) + map.put(months[a], a); + } + if (style == SHORT || style == ALL_STYLES) + { + String[] months = syms.getShortMonths(); + for (int a = 0; a < months.length; ++a) + map.put(months[a], a); + } + return map; + } + if (field == DAY_OF_WEEK) + { + if (style == LONG || style == ALL_STYLES) + { + String[] weekdays = syms.getWeekdays(); + for (int a = SUNDAY; a < weekdays.length; ++a) + map.put(weekdays[a], a); + } + if (style == SHORT || style == ALL_STYLES) + { + String[] weekdays = syms.getShortWeekdays(); + for (int a = SUNDAY; a < weekdays.length; ++a) + map.put(weekdays[a], a); + } + return map; + } + if (field == AM_PM) + { + String[] ampms = syms.getAmPmStrings(); + for (int a = 0; a < ampms.length; ++a) + map.put(ampms[a], a); + return map; + } + if (field == ZONE_OFFSET) + { + String[][] zones = syms.getZoneStrings(); + for (int a = 0; a < zones.length; ++a) + { + if (style == LONG || style == ALL_STYLES) + map.put(zones[a][1], a); + if (style == SHORT || style == ALL_STYLES) + map.put(zones[a][2], a); + } + return map; + } + if (field == DST_OFFSET) + { + String[][] zones = syms.getZoneStrings(); + for (int a = 0; a < zones.length; ++a) + { + if (style == LONG || style == ALL_STYLES) + map.put(zones[a][3], a); + if (style == SHORT || style == ALL_STYLES) + map.put(zones[a][4], a); + } + return map; + } + + throw new InternalError("Failed to resolve field " + field + + " with style " + style + " for locale " + + locale); + } + +} -- cgit v1.2.3