aboutsummaryrefslogtreecommitdiff
path: root/libjava
diff options
context:
space:
mode:
authorMark Wielaard <mark@gcc.gnu.org>2005-02-22 00:58:36 +0000
committerMark Wielaard <mark@gcc.gnu.org>2005-02-22 00:58:36 +0000
commit933e5b284a41cc6e1d21805c350d9aea5ef84006 (patch)
tree1ef9e4a70e8658f5a1afafb0f811039fb753f321 /libjava
parent665794a6c42fc7a9eb31cd12522db01ff4c652e1 (diff)
downloadgcc-933e5b284a41cc6e1d21805c350d9aea5ef84006.zip
gcc-933e5b284a41cc6e1d21805c350d9aea5ef84006.tar.gz
gcc-933e5b284a41cc6e1d21805c350d9aea5ef84006.tar.bz2
[multiple changes]
2005-02-21 Mark Wielaard <mark@klomp.org> * gnu/java/locale/LocaleInformation_en.java: Extend localPatternChars to "GyMdkHmsSEDFwWahKzYeugAZ". 2005-02-21 Mark Wielaard <mark@klomp.org> * java/text/SimpleDateFormat.java (SimpleDateFormat(String, DateFormatSymbols)): Throw NullPointerException when formatData is null. 2005-02-21 Mark Wielaard <mark@klomp.org> * java/util/SimpleTimeZone.java (getOffset): Calculate beforeEnd by taking dstSavings into account. 2005-02-21 Sven de Marothy <sven@physto.se> * java/text/SimpleDateFormat.java, (parse): Set correct DST_OFFSET to the correct value. 2005-02-21 Mark Wielaard <mark@klomp.org> * java/util/SimpleTimeZone.java (checkRule): Throw IllegalArgumentException when month out of range. 2005-02-21 Sven de Marothy <sven@physto.se> * java/util/GregorianCalendar.java, (add): Don't set fields directly anymore. Use set() 2005-02-21 Mark Wielaard <mark@klomp.org> * java/text/SimpleDateFormat.java (CompiledField.toString): Use StringBuffer, not StringBuilder. (toString): Likewise. 2005-02-21 Sven de Marothy <sven@physto.se> * java/util/Calendar.java (clear): Dates should clear to local time. * java/util/GregorianCalendar.java (computeTime): Fix priority problem with DAY_OF_WEEK, Handle non-sunday-startig weeks and minimumDaysInFirstWeek. 2005-02-21 Sven de Marothy <sven@physto.se> * java/util/Calendar.java (Calendar): Constructor should clear fields. 2005-02-21 Sven de Marothy <sven@physto.se> * java/text/SimpleDateFormat.java (parse): Tweak handling of 2-year dates * java/util/Calendar.java (clear): Clear fields to correct value. * java/util/GregorianCalendar.java (computeTime): Correct handling of time zones. Correct field minimum values. 2005-02-21 Sven de Marothy <sven@physto.se> * java/util/Calendar.java (set) Invalidate all fields on first call to set(). 2005-02-21 Sven de Marothy <sven@physto.se> * java/util/GregorianCalendar.java (computeTime): Fixed handling of time zones. 2005-02-21 Sven de Marothy <sven@physto.se> * java/util/Calendar.java (clear): Set values to Epoch instead of zero. (set): Set isSet to the relevant field pattern instead of just the field. * java/util/GregorianCalendar.java (getBundle): Removed. (getDayOfYear): Removed. (getFirstDayOfMonth): New private method. (nonLeniencyCheck): New private method. (computeTime): Correct handling of insufficient data. 2005-02-21 Sven de Marothy <sven@physto.se> * java/util/Calendar.java: Invalidate ERA field on setting the YEAR. * java/util/SimpleTimeZone.java: (getDaysInMonth): Reimplemented. * java/util/GregorianCalendar.java: (getLinearTime): Removed. (isLeapYear(int,boolean)): Removed. (before(), after()): Removed. (computeTime): Reimplemented. 2005-02-21 Sven de Marothy <sven@physto.se> * java/util/Calendar.java: Reformatted. * java/util/GregorianCalendar.java: Reformatted. * java/util/SimpleTimeZone.java: Reformatted. 2005-02-21 Sven de Marothy <sven@physto.se> * java/util/GregorianCalendar.java (GregorianCalendar): Update fields in the constructor 2005-02-21 Noa Resare <noa@resare.com> * java/util/Calendar.java (explicitDSTOffset): New instance field. (set(int,int)): Set and use new field. (set(int,int,int)): Check new field. 2005-02-21 Noa Resare <address@hidden> * java/util/Calendar.java(set): Fix for DST related regression. 2005-02-21 Jeroen Frijters <jeroen@frijters.net> * java/util/Calendar.java (setTimeInMillis): Added call to clear, removed computeFields call. * java/util/Date.java (Date(int,int,int,int,int,int)): Removed workaround for GregorianCalendar bug. * java/util/GregorianCalendar.java (GregorianCalendar): Chained all constructors to a (new) common constructor. (computeTime): Fixed support for lenient month treatment. (getLinearDay): Return long instead of int. (calculateDay): Added fields argument and changed day argument to long. 2005-02-21 Andrew John Hughes <gnu_andrew@member.fsf.org> * java/text/SimpleDateFormat.java Lots of documentation updates. (readObject(java.io.ObjectInputStream)): Wraps IllegalArgumentException as specified. (compileFormat(String)): Uses standardChars rather than the local pattern characters. Throws IllegalArgumentException rather than storing a -1 field. (toString()): Extended to include all variables in a better format. (translateLocalizedPattern(String, String, String)): Renamed to better define the use of this method. 2005-02-21 Andrew John Hughes <gnu_andrew@member.fsf.org> * java/text/DateFormat.java: Documented pattern character offset constants and added new ones. (Field): Added new static fields for new pattern chars. * java/text/SimpleDateFormat.java: (CompiledField): Changed name of FieldSizePair class to CompiledField after adding the character as an attribute. Changed fields to private and added accessors to give encapsulation. (CompiledField.CompiledField(int,int,char)): Extended with character field. (CompiledField.getField()): New accessor method. (CompiledField.getSize()): New acceessor method. (CompiledField.getCharacter()): New accessor method. (CompiledField.toString()): Added primarily for debugging. (standardChars): Now uses extended 24 character sequence. (compileFormat(String)): Changed to use CompiledField. (formatWithAttribute(java.util.Date, gnu.java.text.FormatBuffer, java.text.FieldPosition)): Changed to use CompiledField. New handler for RFC 822 timezones added. 2005-02-21 Andrew John Hughes <gnu_andrew@member.fsf.org> * java/text/SimpleDateFormat.java: (parse(String, java.text.ParsePosition)): Changed 'E' and 'M' cases to use both short and long names. Extended 'z' case to also handle 'Z', and deal with simple GMT offsets such as +0100. (computeOffset(String)): New private method, which converts a GMT offset specification, such as GMT-0500 to a numeric offset in milliseconds. * java/util/TimeZone.java: (timezones()): Added "CEST", the daylight savings time version of "CET", or Central European Time. 2005-02-21 Ito Kazumitsu <kaz@maczuka.gcd.org> * java/text/SimpleDateFormat.java: (parse): Set the DST offset to 0 when parsing GMT offset timezones. 2005-02-21 Ito Kazumitsu <kaz@maczuka.gcd.org> * java/text/SimpleDateFormat.java: (parse): Use offset to set ZONE_OFFSET rather than the DST_OFFSET, so that GMT offset timezones change the right one. 2005-02-21 Andrew John Hughes <gnu_andrew@member.fsf.org> * java/text/SimpleDateFormat.java: (getDateFormatSymbols()): return a copy (setDateFormatSymbols(java.text.DateFormatSymbols)): throw exception on null input (clone()): implemented to clone internal fields 2005-02-21 Sven de Marothy <sven@physto.se> * java/text/SimpleDateFormat.java (parse): comparison should be case-insensitive, ignore null strings. From-SVN: r95368
Diffstat (limited to 'libjava')
-rw-r--r--libjava/ChangeLog216
-rw-r--r--libjava/gnu/java/locale/LocaleInformation_en.java2
-rw-r--r--libjava/java/text/DateFormat.java218
-rw-r--r--libjava/java/text/SimpleDateFormat.java890
-rw-r--r--libjava/java/util/Calendar.java271
-rw-r--r--libjava/java/util/GregorianCalendar.java811
-rw-r--r--libjava/java/util/SimpleTimeZone.java333
-rw-r--r--libjava/java/util/TimeZone.java1
8 files changed, 1839 insertions, 903 deletions
diff --git a/libjava/ChangeLog b/libjava/ChangeLog
index f689581..99183ff 100644
--- a/libjava/ChangeLog
+++ b/libjava/ChangeLog
@@ -1,3 +1,219 @@
+2005-02-21 Mark Wielaard <mark@klomp.org>
+
+ * gnu/java/locale/LocaleInformation_en.java: Extend
+ localPatternChars to "GyMdkHmsSEDFwWahKzYeugAZ".
+
+2005-02-21 Mark Wielaard <mark@klomp.org>
+
+ * java/text/SimpleDateFormat.java
+ (SimpleDateFormat(String, DateFormatSymbols)): Throw
+ NullPointerException when formatData is null.
+
+2005-02-21 Mark Wielaard <mark@klomp.org>
+
+ * java/util/SimpleTimeZone.java (getOffset): Calculate beforeEnd by
+ taking dstSavings into account.
+
+2005-02-21 Sven de Marothy <sven@physto.se>
+
+ * java/text/SimpleDateFormat.java,
+ (parse): Set correct DST_OFFSET to the correct value.
+
+2005-02-21 Mark Wielaard <mark@klomp.org>
+
+ * java/util/SimpleTimeZone.java (checkRule): Throw
+ IllegalArgumentException when month out of range.
+
+2005-02-21 Sven de Marothy <sven@physto.se>
+
+ * java/util/GregorianCalendar.java,
+ (add): Don't set fields directly anymore. Use set()
+
+2005-02-21 Mark Wielaard <mark@klomp.org>
+
+ * java/text/SimpleDateFormat.java (CompiledField.toString):
+ Use StringBuffer, not StringBuilder.
+ (toString): Likewise.
+
+2005-02-21 Sven de Marothy <sven@physto.se>
+
+ * java/util/Calendar.java
+ (clear): Dates should clear to local time.
+ * java/util/GregorianCalendar.java
+ (computeTime): Fix priority problem with DAY_OF_WEEK,
+ Handle non-sunday-startig weeks and minimumDaysInFirstWeek.
+
+2005-02-21 Sven de Marothy <sven@physto.se>
+
+ * java/util/Calendar.java
+ (Calendar): Constructor should clear fields.
+
+2005-02-21 Sven de Marothy <sven@physto.se>
+
+ * java/text/SimpleDateFormat.java
+ (parse): Tweak handling of 2-year dates
+ * java/util/Calendar.java
+ (clear): Clear fields to correct value.
+ * java/util/GregorianCalendar.java
+ (computeTime): Correct handling of time zones.
+ Correct field minimum values.
+
+2005-02-21 Sven de Marothy <sven@physto.se>
+
+ * java/util/Calendar.java
+ (set) Invalidate all fields on first call to set().
+
+2005-02-21 Sven de Marothy <sven@physto.se>
+
+ * java/util/GregorianCalendar.java
+ (computeTime): Fixed handling of time zones.
+
+2005-02-21 Sven de Marothy <sven@physto.se>
+
+ * java/util/Calendar.java
+ (clear): Set values to Epoch instead of zero.
+ (set): Set isSet to the relevant field pattern instead of just
+ the field.
+ * java/util/GregorianCalendar.java
+ (getBundle): Removed.
+ (getDayOfYear): Removed.
+ (getFirstDayOfMonth): New private method.
+ (nonLeniencyCheck): New private method.
+ (computeTime): Correct handling of insufficient data.
+
+2005-02-21 Sven de Marothy <sven@physto.se>
+
+ * java/util/Calendar.java: Invalidate ERA field on setting
+ the YEAR.
+ * java/util/SimpleTimeZone.java:
+ (getDaysInMonth): Reimplemented.
+ * java/util/GregorianCalendar.java:
+ (getLinearTime): Removed.
+ (isLeapYear(int,boolean)): Removed.
+ (before(), after()): Removed.
+ (computeTime): Reimplemented.
+
+2005-02-21 Sven de Marothy <sven@physto.se>
+
+ * java/util/Calendar.java: Reformatted.
+ * java/util/GregorianCalendar.java: Reformatted.
+ * java/util/SimpleTimeZone.java: Reformatted.
+
+2005-02-21 Sven de Marothy <sven@physto.se>
+
+ * java/util/GregorianCalendar.java
+ (GregorianCalendar): Update fields in the constructor
+
+2005-02-21 Noa Resare <noa@resare.com>
+
+ * java/util/Calendar.java (explicitDSTOffset): New instance field.
+ (set(int,int)): Set and use new field.
+ (set(int,int,int)): Check new field.
+
+2005-02-21 Noa Resare <address@hidden>
+
+ * java/util/Calendar.java(set):
+ Fix for DST related regression.
+
+2005-02-21 Jeroen Frijters <jeroen@frijters.net>
+
+ * java/util/Calendar.java
+ (setTimeInMillis): Added call to clear, removed computeFields call.
+ * java/util/Date.java
+ (Date(int,int,int,int,int,int)): Removed workaround for
+ GregorianCalendar bug.
+ * java/util/GregorianCalendar.java
+ (GregorianCalendar): Chained all constructors to a (new)
+ common constructor.
+ (computeTime): Fixed support for lenient month treatment.
+ (getLinearDay): Return long instead of int.
+ (calculateDay): Added fields argument and changed day argument
+ to long.
+
+2005-02-21 Andrew John Hughes <gnu_andrew@member.fsf.org>
+
+ * java/text/SimpleDateFormat.java
+ Lots of documentation updates.
+ (readObject(java.io.ObjectInputStream)): Wraps
+ IllegalArgumentException as specified.
+ (compileFormat(String)): Uses standardChars
+ rather than the local pattern characters.
+ Throws IllegalArgumentException rather than
+ storing a -1 field.
+ (toString()): Extended to include all variables
+ in a better format.
+ (translateLocalizedPattern(String, String, String)):
+ Renamed to better define the use of this method.
+
+2005-02-21 Andrew John Hughes <gnu_andrew@member.fsf.org>
+
+ * java/text/DateFormat.java:
+ Documented pattern character offset constants and
+ added new ones.
+ (Field): Added new static fields for new pattern chars.
+ * java/text/SimpleDateFormat.java:
+ (CompiledField): Changed name of FieldSizePair class
+ to CompiledField after adding the character as an
+ attribute. Changed fields to private and added
+ accessors to give encapsulation.
+ (CompiledField.CompiledField(int,int,char)): Extended
+ with character field.
+ (CompiledField.getField()): New accessor method.
+ (CompiledField.getSize()): New acceessor method.
+ (CompiledField.getCharacter()): New accessor method.
+ (CompiledField.toString()): Added primarily for debugging.
+ (standardChars): Now uses extended 24 character sequence.
+ (compileFormat(String)): Changed to use CompiledField.
+ (formatWithAttribute(java.util.Date, gnu.java.text.FormatBuffer,
+ java.text.FieldPosition)): Changed to use CompiledField.
+ New handler for RFC 822 timezones added.
+
+2005-02-21 Andrew John Hughes <gnu_andrew@member.fsf.org>
+
+ * java/text/SimpleDateFormat.java:
+ (parse(String, java.text.ParsePosition)):
+ Changed 'E' and 'M' cases to use both
+ short and long names. Extended 'z'
+ case to also handle 'Z', and deal
+ with simple GMT offsets such as +0100.
+ (computeOffset(String)): New private method,
+ which converts a GMT offset specification,
+ such as GMT-0500 to a numeric offset in
+ milliseconds.
+ * java/util/TimeZone.java:
+ (timezones()): Added "CEST", the daylight
+ savings time version of "CET", or Central
+ European Time.
+
+2005-02-21 Ito Kazumitsu <kaz@maczuka.gcd.org>
+
+ * java/text/SimpleDateFormat.java:
+ (parse): Set the DST offset to 0 when parsing
+ GMT offset timezones.
+
+2005-02-21 Ito Kazumitsu <kaz@maczuka.gcd.org>
+
+ * java/text/SimpleDateFormat.java:
+ (parse): Use offset to set ZONE_OFFSET
+ rather than the DST_OFFSET, so that
+ GMT offset timezones change the right
+ one.
+
+2005-02-21 Andrew John Hughes <gnu_andrew@member.fsf.org>
+
+ * java/text/SimpleDateFormat.java:
+ (getDateFormatSymbols()): return a copy
+ (setDateFormatSymbols(java.text.DateFormatSymbols)):
+ throw exception on null input
+ (clone()): implemented to clone
+ internal fields
+
+2005-02-21 Sven de Marothy <sven@physto.se>
+
+ * java/text/SimpleDateFormat.java
+ (parse): comparison should be case-insensitive, ignore null
+ strings.
+
2005-02-21 Robert Schuster <theBohemian@gmx.net>
* gnu/java/beans/IntrospectionIncubator.java
diff --git a/libjava/gnu/java/locale/LocaleInformation_en.java b/libjava/gnu/java/locale/LocaleInformation_en.java
index aa35091..df25809 100644
--- a/libjava/gnu/java/locale/LocaleInformation_en.java
+++ b/libjava/gnu/java/locale/LocaleInformation_en.java
@@ -159,7 +159,7 @@ public class LocaleInformation_en extends ListResourceBundle
{ "shortWeekdays", shortWeekdays },
{ "ampms", ampms },
{ "eras", eras },
- { "localPatternChars", "GyMdkHmsSEDFwWahKz" },
+ { "localPatternChars", "GyMdkHmsSEDFwWahKzYeugAZ" },
{ "zoneStrings", zoneStrings },
{ "shortDateFormat", "M/d/yy" }, // Java's Y2K bug.
diff --git a/libjava/java/text/DateFormat.java b/libjava/java/text/DateFormat.java
index da07fdd..f19817e 100644
--- a/libjava/java/text/DateFormat.java
+++ b/libjava/java/text/DateFormat.java
@@ -70,29 +70,221 @@ public abstract class DateFormat extends Format implements Cloneable
/* These constants need to have these exact values. They
* correspond to index positions within the localPatternChars
- * string for a given locale. For example, the US locale uses
- * the string "GyMdkHmsSEDFwWahKz", where 'G' is the character
- * for era, 'y' for year, and so on down to 'z' for time zone.
+ * string for a given locale. Each locale may specify its
+ * own character for a particular field, but the position
+ * of these characters must correspond to an appropriate field
+ * number (as listed below), in order for their meaning to
+ * be determined. For example, the US locale uses
+ * the string "GyMdkHmsSEDFwWahKzYeugAZ", where 'G' is the character
+ * for era, 'y' for year, and so on down to 'Z' for time zone.
*/
+ /**
+ * Represents the position of the era
+ * pattern character in the array of
+ * localized pattern characters.
+ * For example, 'AD' is an era used
+ * in the Gregorian calendar system.
+ * In the U.S. locale, this is 'G'.
+ */
public static final int ERA_FIELD = 0;
+ /**
+ * Represents the position of the year
+ * pattern character in the array of
+ * localized pattern characters.
+ * In the U.S. locale, this is 'y'.
+ */
public static final int YEAR_FIELD = 1;
+ /**
+ * Represents the position of the month
+ * pattern character in the array of
+ * localized pattern characters.
+ * In the U.S. locale, this is 'M'.
+ */
public static final int MONTH_FIELD = 2;
+ /**
+ * Represents the position of the date
+ * or day of the month pattern character
+ * in the array of localized pattern
+ * characters. In the U.S. locale,
+ * this is 'd'.
+ */
public static final int DATE_FIELD = 3;
+ /**
+ * Represents the position of the 24
+ * hour pattern character in the array of
+ * localized pattern characters.
+ * In the U.S. locale, this is 'k'.
+ * This field numbers hours from 1 to 24.
+ */
public static final int HOUR_OF_DAY1_FIELD = 4;
+ /**
+ * Represents the position of the 24
+ * hour pattern character in the array of
+ * localized pattern characters.
+ * In the U.S. locale, this is 'H'.
+ * This field numbers hours from 0 to 23.
+ */
public static final int HOUR_OF_DAY0_FIELD = 5;
+ /**
+ * Represents the position of the minute
+ * pattern character in the array of
+ * localized pattern characters.
+ * In the U.S. locale, this is 'm'.
+ */
public static final int MINUTE_FIELD = 6;
+ /**
+ * Represents the position of the second
+ * pattern character in the array of
+ * localized pattern characters.
+ * In the U.S. locale, this is 's'.
+ */
public static final int SECOND_FIELD = 7;
+ /**
+ * Represents the position of the millisecond
+ * pattern character in the array of
+ * localized pattern characters.
+ * In the U.S. locale, this is 'S'.
+ */
public static final int MILLISECOND_FIELD = 8;
+ /**
+ * Represents the position of the day of the
+ * week pattern character in the array of
+ * localized pattern characters.
+ * In the U.S. locale, this is 'E'.
+ */
public static final int DAY_OF_WEEK_FIELD = 9;
+ /**
+ * Represents the position of the day of the
+ * year pattern character in the array of
+ * localized pattern characters.
+ * In the U.S. locale, this is 'D'.
+ */
public static final int DAY_OF_YEAR_FIELD = 10;
+ /**
+ * Represents the position of the day of the
+ * week in the month pattern character in the
+ * array of localized pattern characters.
+ * In the U.S. locale, this is 'F'.
+ */
public static final int DAY_OF_WEEK_IN_MONTH_FIELD = 11;
+ /**
+ * Represents the position of the week of the
+ * year pattern character in the array of
+ * localized pattern characters.
+ * In the U.S. locale, this is 'w'.
+ */
public static final int WEEK_OF_YEAR_FIELD = 12;
+ /**
+ * Represents the position of the week of the
+ * month pattern character in the array of
+ * localized pattern characters.
+ * In the U.S. locale, this is 'W'.
+ */
public static final int WEEK_OF_MONTH_FIELD = 13;
+ /**
+ * Represents the position of the am/pm
+ * pattern character in the array of
+ * localized pattern characters.
+ * In the U.S. locale, this is 'a'.
+ */
public static final int AM_PM_FIELD = 14;
+ /**
+ * Represents the position of the 12
+ * hour pattern character in the array of
+ * localized pattern characters.
+ * In the U.S. locale, this is 'h'.
+ * This field numbers hours from 1 to 12.
+ */
public static final int HOUR1_FIELD = 15;
+ /**
+ * Represents the position of the 12
+ * hour pattern character in the array of
+ * localized pattern characters.
+ * In the U.S. locale, this is 'K'.
+ * This field numbers hours from 0 to 11.
+ */
public static final int HOUR0_FIELD = 16;
+ /**
+ * Represents the position of the generic
+ * timezone pattern character in the array of
+ * localized pattern characters.
+ * In the U.S. locale, this is 'z'.
+ */
public static final int TIMEZONE_FIELD = 17;
-
+ /**
+ * Represents the position of the ISO year
+ * pattern character in the array of
+ * localized pattern characters.
+ * In the U.S. locale, this is 'Y'.
+ * This is a GNU extension in accordance with
+ * the CLDR data used. This value may
+ * differ from the normal year value.
+ */
+ public static final int ISO_YEAR_FIELD = 18;
+ /**
+ * Represents the position of the localized
+ * day of the week pattern character in the
+ * array of localized pattern characters.
+ * In the U.S. locale, this is 'e'.
+ * This is a GNU extension in accordance with
+ * the CLDR data used. This value only
+ * differs from the day of the week with
+ * numeric formatting, in which case the
+ * locale's first day of the week is used.
+ */
+ public static final int LOCALIZED_DAY_OF_WEEK_FIELD = 19;
+ /**
+ * Represents the position of the extended year
+ * pattern character in the array of
+ * localized pattern characters.
+ * In the U.S. locale, this is 'u'.
+ * This is a GNU extension in accordance with
+ * the CLDR data used. This value modifies
+ * the year value, so as to incorporate the era.
+ * For example, in the Gregorian calendar system,
+ * the extended year is negative instead of being
+ * marked as BC.
+ */
+ public static final int EXTENDED_YEAR_FIELD = 20;
+ /**
+ * Represents the position of the modified Julian
+ * day pattern character in the array of
+ * localized pattern characters.
+ * In the U.S. locale, this is 'g'.
+ * This is a GNU extension in accordance with
+ * the CLDR data used. This value differs
+ * from the standard Julian day in that days
+ * are marked from midnight onwards rather than
+ * noon, and the local time zone affects the value.
+ * In simple terms, it can be thought of as all
+ * the date fields represented as a single number.
+ */
+ public static final int MODIFIED_JULIAN_DAY_FIELD = 21;
+ /**
+ * Represents the position of the millisecond
+ * in the day pattern character in the array of
+ * localized pattern characters.
+ * In the U.S. locale, this is 'A'.
+ * This is a GNU extension in accordance with
+ * the CLDR data used. This value represents
+ * all the time fields (excluding the time zone)
+ * numerically, giving the number of milliseconds
+ * into the day (e.g. 10 in the morning would
+ * be 10 * 60 * 60 * 1000). Any daylight savings
+ * offset also affects this value.
+ */
+ public static final int MILLISECOND_IN_DAY_FIELD = 22;
+ /**
+ * Represents the position of the RFC822
+ * timezone pattern character in the array of
+ * localized pattern characters.
+ * In the U.S. locale, this is 'Z'.
+ * This is a GNU extension in accordance with
+ * the CLDR data used. The value is the offset
+ * of the current time from GMT e.g. -0500 would
+ * be five hours prior to GMT.
+ */
+ public static final int RFC822_TIMEZONE_FIELD = 23;
public static class Field extends Format.Field
{
@@ -136,14 +328,28 @@ public abstract class DateFormat extends Format implements Cloneable
= new Field("hour0", Calendar.HOUR);
public static final DateFormat.Field TIME_ZONE
= new Field("timezone", Calendar.ZONE_OFFSET);
-
+ public static final DateFormat.Field ISO_YEAR
+ = new Field("iso year", Calendar.YEAR);
+ public static final DateFormat.Field LOCALIZED_DAY_OF_WEEK
+ = new Field("localized day of week", Calendar.DAY_OF_WEEK);
+ public static final DateFormat.Field EXTENDED_YEAR
+ = new Field("extended year", Calendar.YEAR);
+ public static final DateFormat.Field MODIFIED_JULIAN_DAY
+ = new Field("julian day", -1);
+ public static final DateFormat.Field MILLISECOND_IN_DAY
+ = new Field("millisecond in day", -1);
+ public static final DateFormat.Field RFC822_TIME_ZONE
+ = new Field("rfc822 timezone", Calendar.ZONE_OFFSET);
+
static final DateFormat.Field[] allFields =
{
ERA, YEAR, MONTH, DAY_OF_MONTH, HOUR_OF_DAY1,
HOUR_OF_DAY0, MINUTE, SECOND, MILLISECOND,
DAY_OF_WEEK, DAY_OF_YEAR, DAY_OF_WEEK_IN_MONTH,
WEEK_OF_YEAR, WEEK_OF_MONTH, AM_PM, HOUR1, HOUR0,
- TIME_ZONE
+ TIME_ZONE, ISO_YEAR, LOCALIZED_DAY_OF_WEEK,
+ EXTENDED_YEAR, MODIFIED_JULIAN_DAY, MILLISECOND_IN_DAY,
+ RFC822_TIME_ZONE
};
// For deserialization
diff --git a/libjava/java/text/SimpleDateFormat.java b/libjava/java/text/SimpleDateFormat.java
index 35083eb..d8e15f2 100644
--- a/libjava/java/text/SimpleDateFormat.java
+++ b/libjava/java/text/SimpleDateFormat.java
@@ -1,6 +1,6 @@
/* SimpleDateFormat.java -- A class for parsing/formating simple
date constructs
- Copyright (C) 1998, 1999, 2000, 2001, 2003, 2004
+ Copyright (C) 1998, 1999, 2000, 2001, 2003, 2004, 2005
Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -45,6 +45,7 @@ import gnu.java.text.FormatBuffer;
import gnu.java.text.FormatCharacterIterator;
import gnu.java.text.StringFormatBuffer;
+import java.io.InvalidObjectException;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.util.ArrayList;
@@ -55,6 +56,8 @@ import java.util.Iterator;
import java.util.Locale;
import java.util.SimpleTimeZone;
import java.util.TimeZone;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
/**
* SimpleDateFormat provides convenient methods for parsing and formatting
@@ -62,34 +65,189 @@ import java.util.TimeZone;
*/
public class SimpleDateFormat extends DateFormat
{
- /** A pair class used by SimpleDateFormat as a compiled representation
- * of a format string.
+ /**
+ * This class is used by <code>SimpleDateFormat</code> as a
+ * compiled representation of a format string. The field
+ * ID, size, and character used are stored for each sequence
+ * of pattern characters.
*/
- private class FieldSizePair
+ private class CompiledField
{
- public int field;
- public int size;
+ /**
+ * The ID of the field within the local pattern characters,
+ */
+ private int field;
+
+ /**
+ * The size of the character sequence.
+ */
+ private int size;
+
+ /**
+ * The character used.
+ */
+ private char character;
- /** Constructs a pair with the given field and size values */
- public FieldSizePair(int f, int s) {
+ /**
+ * Constructs a compiled field using the
+ * the given field ID, size and character
+ * values.
+ *
+ * @param f the field ID.
+ * @param s the size of the field.
+ * @param c the character used.
+ */
+ public CompiledField(int f, int s, char c) {
field = f;
size = s;
+ character = c;
+ }
+
+ /**
+ * Retrieves the ID of the field relative to
+ * the local pattern characters.
+ */
+ public int getField()
+ {
+ return field;
+ }
+
+ /**
+ * Retrieves the size of the character sequence.
+ */
+ public int getSize()
+ {
+ return size;
+ }
+
+ /**
+ * Retrieves the character used in the sequence.
+ */
+ public char getCharacter()
+ {
+ return character;
+ }
+
+ /**
+ * Returns a <code>String</code> representation
+ * of the compiled field, primarily for debugging
+ * purposes.
+ *
+ * @return a <code>String</code> representation.
+ */
+ public String toString()
+ {
+ StringBuffer builder;
+
+ builder = new StringBuffer(getClass().getName());
+ builder.append("[field=");
+ builder.append(field);
+ builder.append(", size=");
+ builder.append(size);
+ builder.append(", character=");
+ builder.append(character);
+ builder.append("]");
+
+ return builder.toString();
}
}
+ /**
+ * A list of <code>CompiledField</code>s,
+ * representing the compiled version of the pattern.
+ *
+ * @see CompiledField
+ * @serial Ignored.
+ */
private transient ArrayList tokens;
+
+ /**
+ * The localised data used in formatting,
+ * such as the day and month names in the local
+ * language, and the localized pattern characters.
+ *
+ * @see DateFormatSymbols
+ * @serial The localisation data. May not be null.
+ */
private DateFormatSymbols formatData; // formatData
+
+ /**
+ * The date representing the start of the century
+ * used for interpreting two digit years. For
+ * example, 24/10/2004 would cause two digit
+ * years to be interpreted as representing
+ * the years between 2004 and 2104.
+ *
+ * @see get2DigitYearStart()
+ * @see set2DigitYearStart(java.util.Date)
+ * @see Date
+ * @serial The start date of the century for parsing two digit years.
+ * May not be null.
+ */
private Date defaultCenturyStart;
+
+ /**
+ * The year at which interpretation of two
+ * digit years starts.
+ *
+ * @see get2DigitYearStart()
+ * @see set2DigitYearStart(java.util.Date)
+ * @serial Ignored.
+ */
private transient int defaultCentury;
+
+ /**
+ * The non-localized pattern string. This
+ * only ever contains the pattern characters
+ * stored in standardChars. Localized patterns
+ * are translated to this form.
+ *
+ * @see applyPattern(String)
+ * @see applyLocalizedPattern(String)
+ * @see toPattern()
+ * @see toLocalizedPattern()
+ * @serial The non-localized pattern string. May not be null.
+ */
private String pattern;
+
+ /**
+ * The version of serialized data used by this class.
+ * Version 0 only includes the pattern and formatting
+ * data. Version 1 adds the start date for interpreting
+ * two digit years.
+ *
+ * @serial This specifies the version of the data being serialized.
+ * Version 0 (or no version) specifies just <code>pattern</code>
+ * and <code>formatData</code>. Version 1 adds
+ * the <code>defaultCenturyStart</code>. This implementation
+ * always writes out version 1 data.
+ */
private int serialVersionOnStream = 1; // 0 indicates JDK1.1.3 or earlier
+
+ /**
+ * For compatability.
+ */
private static final long serialVersionUID = 4774881970558875024L;
- // This string is specified in the JCL. We set it here rather than
- // do a DateFormatSymbols(Locale.US).getLocalPatternChars() since
- // someone could theoretically change those values (though unlikely).
- private static final String standardChars = "GyMdkHmsSEDFwWahKzZ";
+ // This string is specified in the root of the CLDR. We set it here
+ // rather than doing a DateFormatSymbols(Locale.US).getLocalPatternChars()
+ // since someone could theoretically change those values (though unlikely).
+ private static final String standardChars = "GyMdkHmsSEDFwWahKzYeugAZ";
+ /**
+ * Reads the serialized version of this object.
+ * If the serialized data is only version 0,
+ * then the date for the start of the century
+ * for interpreting two digit years is computed.
+ * The pattern is parsed and compiled following the process
+ * of reading in the serialized data.
+ *
+ * @param stream the object stream to read the data from.
+ * @throws IOException if an I/O error occurs.
+ * @throws ClassNotFoundException if the class of the serialized data
+ * could not be found.
+ * @throws InvalidObjectException if the pattern is invalid.
+ */
private void readObject(ObjectInputStream stream)
throws IOException, ClassNotFoundException
{
@@ -105,9 +263,25 @@ public class SimpleDateFormat extends DateFormat
// Set up items normally taken care of by the constructor.
tokens = new ArrayList();
- compileFormat(pattern);
+ try
+ {
+ compileFormat(pattern);
+ }
+ catch (IllegalArgumentException e)
+ {
+ throw new InvalidObjectException("The stream pattern was invalid.");
+ }
}
+ /**
+ * Compiles the supplied non-localized pattern into a form
+ * from which formatting and parsing can be performed.
+ * This also detects errors in the pattern, which will
+ * be raised on later use of the compiled data.
+ *
+ * @param pattern the non-localized pattern to compile.
+ * @throws IllegalArgumentException if the pattern is invalid.
+ */
private void compileFormat(String pattern)
{
// Any alphabetical characters are treated as pattern characters
@@ -116,24 +290,25 @@ public class SimpleDateFormat extends DateFormat
char thisChar;
int pos;
int field;
- FieldSizePair current = null;
+ CompiledField current = null;
for (int i=0; i<pattern.length(); i++) {
thisChar = pattern.charAt(i);
- field = formatData.getLocalPatternChars().indexOf(thisChar);
+ field = standardChars.indexOf(thisChar);
if (field == -1) {
current = null;
if ((thisChar >= 'A' && thisChar <= 'Z')
|| (thisChar >= 'a' && thisChar <= 'z')) {
- // Not a valid letter
- tokens.add(new FieldSizePair(-1,0));
+ // Not a valid letter
+ throw new IllegalArgumentException("Invalid letter " + thisChar +
+ "encountered at character " + i
+ + ".");
} else if (thisChar == '\'') {
// Quoted text section; skip to next single quote
pos = pattern.indexOf('\'',i+1);
if (pos == -1) {
- // This ought to be an exception, but spec does not
- // let us throw one.
- tokens.add(new FieldSizePair(-1,0));
+ throw new IllegalArgumentException("Quotes starting at character "
+ + i + " not closed.");
}
if ((pos+1 < pattern.length()) && (pattern.charAt(pos+1) == '\'')) {
tokens.add(pattern.substring(i+1,pos+1));
@@ -150,20 +325,38 @@ public class SimpleDateFormat extends DateFormat
if ((current != null) && (field == current.field)) {
current.size++;
} else {
- current = new FieldSizePair(field,1);
+ current = new CompiledField(field,1,thisChar);
tokens.add(current);
}
}
}
}
+ /**
+ * Returns a string representation of this
+ * class.
+ *
+ * @return a string representation of the <code>SimpleDateFormat</code>
+ * instance.
+ */
public String toString()
{
- StringBuffer output = new StringBuffer();
- Iterator i = tokens.iterator();
- while (i.hasNext()) {
- output.append(i.next().toString());
- }
+ StringBuffer output = new StringBuffer(getClass().getName());
+ output.append("[tokens=");
+ output.append(tokens);
+ output.append(", formatData=");
+ output.append(formatData);
+ output.append(", defaultCenturyStart=");
+ output.append(defaultCenturyStart);
+ output.append(", defaultCentury=");
+ output.append(defaultCentury);
+ output.append(", pattern=");
+ output.append(pattern);
+ output.append(", serialVersionOnStream=");
+ output.append(serialVersionOnStream);
+ output.append(", standardChars=");
+ output.append(standardChars);
+ output.append("]");
return output.toString();
}
@@ -194,8 +387,12 @@ public class SimpleDateFormat extends DateFormat
}
/**
- * Creates a date formatter using the specified pattern, with the default
- * DateFormatSymbols for the default locale.
+ * Creates a date formatter using the specified non-localized pattern,
+ * with the default DateFormatSymbols for the default locale.
+ *
+ * @param pattern the pattern to use.
+ * @throws NullPointerException if the pattern is null.
+ * @throws IllegalArgumentException if the pattern is invalid.
*/
public SimpleDateFormat(String pattern)
{
@@ -203,8 +400,13 @@ public class SimpleDateFormat extends DateFormat
}
/**
- * Creates a date formatter using the specified pattern, with the default
- * DateFormatSymbols for the given locale.
+ * Creates a date formatter using the specified non-localized pattern,
+ * with the default DateFormatSymbols for the given locale.
+ *
+ * @param pattern the non-localized pattern to use.
+ * @param locale the locale to use for the formatting symbols.
+ * @throws NullPointerException if the pattern is null.
+ * @throws IllegalArgumentException if the pattern is invalid.
*/
public SimpleDateFormat(String pattern, Locale locale)
{
@@ -222,8 +424,14 @@ public class SimpleDateFormat extends DateFormat
}
/**
- * Creates a date formatter using the specified pattern. The
- * specified DateFormatSymbols will be used when formatting.
+ * Creates a date formatter using the specified non-localized
+ * pattern. The specified DateFormatSymbols will be used when
+ * formatting.
+ *
+ * @param pattern the non-localized pattern to use.
+ * @param formatData the formatting symbols to use.
+ * @throws NullPointerException if the pattern or formatData is null.
+ * @throws IllegalArgumentException if the pattern is invalid.
*/
public SimpleDateFormat(String pattern, DateFormatSymbols formatData)
{
@@ -231,6 +439,8 @@ public class SimpleDateFormat extends DateFormat
calendar = new GregorianCalendar();
computeCenturyStart ();
tokens = new ArrayList();
+ if (formatData == null)
+ throw new NullPointerException("formatData");
this.formatData = formatData;
compileFormat(pattern);
this.pattern = pattern;
@@ -240,9 +450,6 @@ public class SimpleDateFormat extends DateFormat
numberFormat.setMaximumFractionDigits (0);
}
- // What is the difference between localized and unlocalized? The
- // docs don't say.
-
/**
* This method returns a string with the formatting pattern being used
* by this object. This string is unlocalized.
@@ -263,7 +470,7 @@ public class SimpleDateFormat extends DateFormat
public String toLocalizedPattern()
{
String localChars = formatData.getLocalPatternChars();
- return applyLocalizedPattern (pattern, standardChars, localChars);
+ return translateLocalizedPattern(pattern, standardChars, localChars);
}
/**
@@ -271,6 +478,8 @@ public class SimpleDateFormat extends DateFormat
* object. This string is not localized.
*
* @param pattern The new format pattern.
+ * @throws NullPointerException if the pattern is null.
+ * @throws IllegalArgumentException if the pattern is invalid.
*/
public void applyPattern(String pattern)
{
@@ -284,16 +493,34 @@ public class SimpleDateFormat extends DateFormat
* object. This string is localized.
*
* @param pattern The new format pattern.
+ * @throws NullPointerException if the pattern is null.
+ * @throws IllegalArgumentException if the pattern is invalid.
*/
public void applyLocalizedPattern(String pattern)
{
String localChars = formatData.getLocalPatternChars();
- pattern = applyLocalizedPattern (pattern, localChars, standardChars);
+ pattern = translateLocalizedPattern(pattern, localChars, standardChars);
applyPattern(pattern);
}
- private String applyLocalizedPattern(String pattern,
- String oldChars, String newChars)
+ /**
+ * Translates either from or to a localized variant of the pattern
+ * string. For example, in the German locale, 't' (for 'tag') is
+ * used instead of 'd' (for 'date'). This method translates
+ * a localized pattern (such as 'ttt') to a non-localized pattern
+ * (such as 'ddd'), or vice versa. Non-localized patterns use
+ * a standard set of characters, which match those of the U.S. English
+ * locale.
+ *
+ * @param pattern the pattern to translate.
+ * @param oldChars the old set of characters (used in the pattern).
+ * @param newChars the new set of characters (which will be used in the
+ * pattern).
+ * @return a version of the pattern using the characters in
+ * <code>newChars</code>.
+ */
+ private String translateLocalizedPattern(String pattern,
+ String oldChars, String newChars)
{
int len = pattern.length();
StringBuffer buf = new StringBuffer(len);
@@ -341,14 +568,14 @@ public class SimpleDateFormat extends DateFormat
}
/**
- * This method returns the format symbol information used for parsing
- * and formatting dates.
+ * This method returns a copy of the format symbol information used
+ * for parsing and formatting dates.
*
- * @return The date format symbols.
+ * @return a copy of the date format symbols.
*/
public DateFormatSymbols getDateFormatSymbols()
{
- return formatData;
+ return (DateFormatSymbols) formatData.clone();
}
/**
@@ -356,9 +583,15 @@ public class SimpleDateFormat extends DateFormat
* and formatting dates.
*
* @param formatData The date format symbols.
+ * @throws NullPointerException if <code>formatData</code> is null.
*/
public void setDateFormatSymbols(DateFormatSymbols formatData)
{
+ if (formatData == null)
+ {
+ throw new
+ NullPointerException("The supplied format data was null.");
+ }
this.formatData = formatData;
}
@@ -431,12 +664,12 @@ public class SimpleDateFormat extends DateFormat
while (iter.hasNext())
{
Object o = iter.next();
- if (o instanceof FieldSizePair)
+ if (o instanceof CompiledField)
{
- FieldSizePair p = (FieldSizePair) o;
+ CompiledField cf = (CompiledField) o;
int beginIndex = buffer.length();
- switch (p.field)
+ switch (cf.getField())
{
case ERA_FIELD:
buffer.append (formatData.eras[calendar.get (Calendar.ERA)], DateFormat.Field.ERA);
@@ -445,75 +678,75 @@ public class SimpleDateFormat extends DateFormat
// If we have two digits, then we truncate. Otherwise, we
// use the size of the pattern, and zero pad.
buffer.setDefaultAttribute (DateFormat.Field.YEAR);
- if (p.size == 2)
+ if (cf.getSize() == 2)
{
temp = String.valueOf (calendar.get (Calendar.YEAR));
buffer.append (temp.substring (temp.length() - 2));
}
else
- withLeadingZeros (calendar.get (Calendar.YEAR), p.size, buffer);
+ withLeadingZeros (calendar.get (Calendar.YEAR), cf.getSize(), buffer);
break;
case MONTH_FIELD:
buffer.setDefaultAttribute (DateFormat.Field.MONTH);
- if (p.size < 3)
- withLeadingZeros (calendar.get (Calendar.MONTH) + 1, p.size, buffer);
- else if (p.size < 4)
+ if (cf.getSize() < 3)
+ withLeadingZeros (calendar.get (Calendar.MONTH) + 1, cf.getSize(), buffer);
+ else if (cf.getSize() < 4)
buffer.append (formatData.shortMonths[calendar.get (Calendar.MONTH)]);
else
buffer.append (formatData.months[calendar.get (Calendar.MONTH)]);
break;
case DATE_FIELD:
buffer.setDefaultAttribute (DateFormat.Field.DAY_OF_MONTH);
- withLeadingZeros (calendar.get (Calendar.DATE), p.size, buffer);
+ withLeadingZeros (calendar.get (Calendar.DATE), cf.getSize(), buffer);
break;
case HOUR_OF_DAY1_FIELD: // 1-24
buffer.setDefaultAttribute(DateFormat.Field.HOUR_OF_DAY1);
withLeadingZeros ( ((calendar.get (Calendar.HOUR_OF_DAY) + 23) % 24) + 1,
- p.size, buffer);
+ cf.getSize(), buffer);
break;
case HOUR_OF_DAY0_FIELD: // 0-23
buffer.setDefaultAttribute (DateFormat.Field.HOUR_OF_DAY0);
- withLeadingZeros (calendar.get (Calendar.HOUR_OF_DAY), p.size, buffer);
+ withLeadingZeros (calendar.get (Calendar.HOUR_OF_DAY), cf.getSize(), buffer);
break;
case MINUTE_FIELD:
buffer.setDefaultAttribute (DateFormat.Field.MINUTE);
withLeadingZeros (calendar.get (Calendar.MINUTE),
- p.size, buffer);
+ cf.getSize(), buffer);
break;
case SECOND_FIELD:
buffer.setDefaultAttribute (DateFormat.Field.SECOND);
withLeadingZeros(calendar.get (Calendar.SECOND),
- p.size, buffer);
+ cf.getSize(), buffer);
break;
case MILLISECOND_FIELD:
buffer.setDefaultAttribute (DateFormat.Field.MILLISECOND);
- withLeadingZeros (calendar.get (Calendar.MILLISECOND), p.size, buffer);
+ withLeadingZeros (calendar.get (Calendar.MILLISECOND), cf.getSize(), buffer);
break;
case DAY_OF_WEEK_FIELD:
buffer.setDefaultAttribute (DateFormat.Field.DAY_OF_WEEK);
- if (p.size < 4)
+ if (cf.getSize() < 4)
buffer.append (formatData.shortWeekdays[calendar.get (Calendar.DAY_OF_WEEK)]);
else
buffer.append (formatData.weekdays[calendar.get (Calendar.DAY_OF_WEEK)]);
break;
case DAY_OF_YEAR_FIELD:
buffer.setDefaultAttribute (DateFormat.Field.DAY_OF_YEAR);
- withLeadingZeros (calendar.get (Calendar.DAY_OF_YEAR), p.size, buffer);
+ withLeadingZeros (calendar.get (Calendar.DAY_OF_YEAR), cf.getSize(), buffer);
break;
case DAY_OF_WEEK_IN_MONTH_FIELD:
buffer.setDefaultAttribute (DateFormat.Field.DAY_OF_WEEK_IN_MONTH);
withLeadingZeros (calendar.get (Calendar.DAY_OF_WEEK_IN_MONTH),
- p.size, buffer);
+ cf.getSize(), buffer);
break;
case WEEK_OF_YEAR_FIELD:
buffer.setDefaultAttribute (DateFormat.Field.WEEK_OF_YEAR);
withLeadingZeros (calendar.get (Calendar.WEEK_OF_YEAR),
- p.size, buffer);
+ cf.getSize(), buffer);
break;
case WEEK_OF_MONTH_FIELD:
buffer.setDefaultAttribute (DateFormat.Field.WEEK_OF_MONTH);
withLeadingZeros (calendar.get (Calendar.WEEK_OF_MONTH),
- p.size, buffer);
+ cf.getSize(), buffer);
break;
case AM_PM_FIELD:
buffer.setDefaultAttribute (DateFormat.Field.AM_PM);
@@ -521,25 +754,39 @@ public class SimpleDateFormat extends DateFormat
break;
case HOUR1_FIELD: // 1-12
buffer.setDefaultAttribute (DateFormat.Field.HOUR1);
- withLeadingZeros (((calendar.get (Calendar.HOUR) + 11) % 12) + 1, p.size, buffer);
+ withLeadingZeros (((calendar.get (Calendar.HOUR) + 11) % 12) + 1,
+ cf.getSize(), buffer);
break;
case HOUR0_FIELD: // 0-11
buffer.setDefaultAttribute (DateFormat.Field.HOUR0);
- withLeadingZeros (calendar.get (Calendar.HOUR), p.size, buffer);
+ withLeadingZeros (calendar.get (Calendar.HOUR), cf.getSize(), buffer);
break;
case TIMEZONE_FIELD:
buffer.setDefaultAttribute (DateFormat.Field.TIME_ZONE);
TimeZone zone = calendar.getTimeZone();
boolean isDST = calendar.get (Calendar.DST_OFFSET) != 0;
// FIXME: XXX: This should be a localized time zone.
- String zoneID = zone.getDisplayName (isDST, p.size > 3 ? TimeZone.LONG : TimeZone.SHORT);
+ String zoneID = zone.getDisplayName
+ (isDST, cf.getSize() > 3 ? TimeZone.LONG : TimeZone.SHORT);
buffer.append (zoneID);
break;
+ case RFC822_TIMEZONE_FIELD:
+ buffer.setDefaultAttribute(DateFormat.Field.RFC822_TIME_ZONE);
+ int pureMinutes = (calendar.get(Calendar.ZONE_OFFSET) +
+ calendar.get(Calendar.DST_OFFSET)) / (1000 * 60);
+ String sign = (pureMinutes < 0) ? "-" : "+";
+ int hours = pureMinutes / 60;
+ int minutes = pureMinutes % 60;
+ buffer.append(sign);
+ withLeadingZeros(hours, 2, buffer);
+ withLeadingZeros(minutes, 2, buffer);
+ break;
default:
- throw new IllegalArgumentException ("Illegal pattern character " + p.field);
+ throw new IllegalArgumentException ("Illegal pattern character " +
+ cf.getCharacter());
}
if (pos != null && (buffer.getDefaultAttribute() == pos.getFieldAttribute()
- || p.field == pos.getField()))
+ || cf.getField() == pos.getField()))
{
pos.setBeginIndex(beginIndex);
pos.setEndIndex(buffer.length());
@@ -614,232 +861,265 @@ public class SimpleDateFormat extends DateFormat
boolean saw_timezone = false;
int quote_start = -1;
boolean is2DigitYear = false;
- for (; fmt_index < fmt_max; ++fmt_index)
+ try
{
- char ch = pattern.charAt(fmt_index);
- if (ch == '\'')
+ for (; fmt_index < fmt_max; ++fmt_index)
{
- int index = pos.getIndex();
- if (fmt_index < fmt_max - 1
- && pattern.charAt(fmt_index + 1) == '\'')
+ char ch = pattern.charAt(fmt_index);
+ if (ch == '\'')
+ {
+ int index = pos.getIndex();
+ if (fmt_index < fmt_max - 1
+ && pattern.charAt(fmt_index + 1) == '\'')
+ {
+ if (! expect (dateStr, pos, ch))
+ return null;
+ ++fmt_index;
+ }
+ else
+ quote_start = quote_start < 0 ? fmt_index : -1;
+ continue;
+ }
+
+ if (quote_start != -1
+ || ((ch < 'a' || ch > 'z')
+ && (ch < 'A' || ch > 'Z')))
{
if (! expect (dateStr, pos, ch))
return null;
- ++fmt_index;
+ continue;
}
- else
- quote_start = quote_start < 0 ? fmt_index : -1;
- continue;
- }
-
- if (quote_start != -1
- || ((ch < 'a' || ch > 'z')
- && (ch < 'A' || ch > 'Z')))
- {
- if (! expect (dateStr, pos, ch))
- return null;
- continue;
- }
-
- // We've arrived at a potential pattern character in the
- // pattern.
- int first = fmt_index;
- while (++fmt_index < fmt_max && pattern.charAt(fmt_index) == ch)
- ;
- int fmt_count = fmt_index - first;
-
- // We might need to limit the number of digits to parse in
- // some cases. We look to the next pattern character to
- // decide.
- boolean limit_digits = false;
- if (fmt_index < fmt_max
- && standardChars.indexOf(pattern.charAt(fmt_index)) >= 0)
- limit_digits = true;
- --fmt_index;
-
- // We can handle most fields automatically: most either are
- // numeric or are looked up in a string vector. In some cases
- // we need an offset. When numeric, `offset' is added to the
- // resulting value. When doing a string lookup, offset is the
- // initial index into the string array.
- int calendar_field;
- boolean is_numeric = true;
- String[] match = null;
- int offset = 0;
- boolean maybe2DigitYear = false;
- switch (ch)
- {
- case 'd':
- calendar_field = Calendar.DATE;
- break;
- case 'D':
- calendar_field = Calendar.DAY_OF_YEAR;
- break;
- case 'F':
- calendar_field = Calendar.DAY_OF_WEEK_IN_MONTH;
- break;
- case 'E':
- is_numeric = false;
- offset = 1;
- calendar_field = Calendar.DAY_OF_WEEK;
- match = (fmt_count <= 3
- ? formatData.getShortWeekdays()
- : formatData.getWeekdays());
- break;
- case 'w':
- calendar_field = Calendar.WEEK_OF_YEAR;
- break;
- case 'W':
- calendar_field = Calendar.WEEK_OF_MONTH;
- break;
- case 'M':
- calendar_field = Calendar.MONTH;
- if (fmt_count <= 2)
- offset = -1;
- else
+
+ // We've arrived at a potential pattern character in the
+ // pattern.
+ int fmt_count = 1;
+ while (++fmt_index < fmt_max && pattern.charAt(fmt_index) == ch)
{
- is_numeric = false;
- match = (fmt_count <= 3
- ? formatData.getShortMonths()
- : formatData.getMonths());
+ ++fmt_count;
}
- break;
- case 'y':
- calendar_field = Calendar.YEAR;
- if (fmt_count <= 2)
- maybe2DigitYear = true;
- break;
- case 'K':
- calendar_field = Calendar.HOUR;
- break;
- case 'h':
- calendar_field = Calendar.HOUR;
- break;
- case 'H':
- calendar_field = Calendar.HOUR_OF_DAY;
- break;
- case 'k':
- calendar_field = Calendar.HOUR_OF_DAY;
- break;
- case 'm':
- calendar_field = Calendar.MINUTE;
- break;
- case 's':
- calendar_field = Calendar.SECOND;
- break;
- case 'S':
- calendar_field = Calendar.MILLISECOND;
- break;
- case 'a':
- is_numeric = false;
- calendar_field = Calendar.AM_PM;
- match = formatData.getAmPmStrings();
- break;
- case 'z':
- // We need a special case for the timezone, because it
- // uses a different data structure than the other cases.
- is_numeric = false;
- calendar_field = Calendar.DST_OFFSET;
- String[][] zoneStrings = formatData.getZoneStrings();
- int zoneCount = zoneStrings.length;
- int index = pos.getIndex();
- boolean found_zone = false;
- for (int j = 0; j < zoneCount; j++)
+
+ // We might need to limit the number of digits to parse in
+ // some cases. We look to the next pattern character to
+ // decide.
+ boolean limit_digits = false;
+ if (fmt_index < fmt_max
+ && standardChars.indexOf(pattern.charAt(fmt_index)) >= 0)
+ limit_digits = true;
+ --fmt_index;
+
+ // We can handle most fields automatically: most either are
+ // numeric or are looked up in a string vector. In some cases
+ // we need an offset. When numeric, `offset' is added to the
+ // resulting value. When doing a string lookup, offset is the
+ // initial index into the string array.
+ int calendar_field;
+ boolean is_numeric = true;
+ int offset = 0;
+ boolean maybe2DigitYear = false;
+ Integer simpleOffset;
+ String[] set1 = null;
+ String[] set2 = null;
+ switch (ch)
{
- String[] strings = zoneStrings[j];
- int k;
- for (k = 1; k < strings.length; ++k)
+ case 'd':
+ calendar_field = Calendar.DATE;
+ break;
+ case 'D':
+ calendar_field = Calendar.DAY_OF_YEAR;
+ break;
+ case 'F':
+ calendar_field = Calendar.DAY_OF_WEEK_IN_MONTH;
+ break;
+ case 'E':
+ is_numeric = false;
+ offset = 1;
+ calendar_field = Calendar.DAY_OF_WEEK;
+ set1 = formatData.getWeekdays();
+ set2 = formatData.getShortWeekdays();
+ break;
+ case 'w':
+ calendar_field = Calendar.WEEK_OF_YEAR;
+ break;
+ case 'W':
+ calendar_field = Calendar.WEEK_OF_MONTH;
+ break;
+ case 'M':
+ calendar_field = Calendar.MONTH;
+ if (fmt_count <= 2)
+ offset = -1;
+ else
{
- if (dateStr.startsWith(strings[k], index))
- break;
+ is_numeric = false;
+ set1 = formatData.getMonths();
+ set2 = formatData.getShortMonths();
}
- if (k != strings.length)
+ break;
+ case 'y':
+ calendar_field = Calendar.YEAR;
+ if (fmt_count <= 2)
+ maybe2DigitYear = true;
+ break;
+ case 'K':
+ calendar_field = Calendar.HOUR;
+ break;
+ case 'h':
+ calendar_field = Calendar.HOUR;
+ break;
+ case 'H':
+ calendar_field = Calendar.HOUR_OF_DAY;
+ break;
+ case 'k':
+ calendar_field = Calendar.HOUR_OF_DAY;
+ break;
+ case 'm':
+ calendar_field = Calendar.MINUTE;
+ break;
+ case 's':
+ calendar_field = Calendar.SECOND;
+ break;
+ case 'S':
+ calendar_field = Calendar.MILLISECOND;
+ break;
+ case 'a':
+ is_numeric = false;
+ calendar_field = Calendar.AM_PM;
+ set1 = formatData.getAmPmStrings();
+ break;
+ case 'z':
+ case 'Z':
+ // We need a special case for the timezone, because it
+ // uses a different data structure than the other cases.
+ is_numeric = false;
+ calendar_field = Calendar.ZONE_OFFSET;
+ String[][] zoneStrings = formatData.getZoneStrings();
+ int zoneCount = zoneStrings.length;
+ int index = pos.getIndex();
+ boolean found_zone = false;
+ simpleOffset = computeOffset(dateStr.substring(index));
+ if (simpleOffset != null)
{
found_zone = true;
saw_timezone = true;
- TimeZone tz = TimeZone.getTimeZone (strings[0]);
- calendar.set (Calendar.ZONE_OFFSET, tz.getRawOffset ());
- offset = 0;
- if (k > 2 && tz instanceof SimpleTimeZone)
+ calendar.set(Calendar.DST_OFFSET, 0);
+ offset = simpleOffset.intValue();
+ }
+ else
+ {
+ for (int j = 0; j < zoneCount; j++)
{
- SimpleTimeZone stz = (SimpleTimeZone) tz;
- offset = stz.getDSTSavings ();
+ String[] strings = zoneStrings[j];
+ int k;
+ for (k = 0; k < strings.length; ++k)
+ {
+ if (dateStr.startsWith(strings[k], index))
+ break;
+ }
+ if (k != strings.length)
+ {
+ found_zone = true;
+ saw_timezone = true;
+ TimeZone tz = TimeZone.getTimeZone (strings[0]);
+ // Check if it's a DST zone or ordinary
+ if(k == 3 || k == 4)
+ calendar.set (Calendar.DST_OFFSET, tz.getDSTSavings());
+ else
+ calendar.set (Calendar.DST_OFFSET, 0);
+ offset = tz.getRawOffset ();
+ pos.setIndex(index + strings[k].length());
+ break;
+ }
}
- pos.setIndex(index + strings[k].length());
- break;
}
- }
- if (! found_zone)
- {
+ if (! found_zone)
+ {
+ pos.setErrorIndex(pos.getIndex());
+ return null;
+ }
+ break;
+ default:
pos.setErrorIndex(pos.getIndex());
return null;
}
- break;
- default:
- pos.setErrorIndex(pos.getIndex());
- return null;
- }
-
- // Compute the value we should assign to the field.
- int value;
- int index = -1;
- if (is_numeric)
- {
- numberFormat.setMinimumIntegerDigits(fmt_count);
- if (limit_digits)
- numberFormat.setMaximumIntegerDigits(fmt_count);
- if (maybe2DigitYear)
- index = pos.getIndex();
- Number n = numberFormat.parse(dateStr, pos);
- if (pos == null || ! (n instanceof Long))
- return null;
- value = n.intValue() + offset;
- }
- else if (match != null)
- {
- index = pos.getIndex();
- int i;
- for (i = offset; i < match.length; ++i)
+
+ // Compute the value we should assign to the field.
+ int value;
+ int index = -1;
+ if (is_numeric)
{
- if (dateStr.startsWith(match[i], index))
- break;
+ numberFormat.setMinimumIntegerDigits(fmt_count);
+ if (limit_digits)
+ numberFormat.setMaximumIntegerDigits(fmt_count);
+ if (maybe2DigitYear)
+ index = pos.getIndex();
+ Number n = numberFormat.parse(dateStr, pos);
+ if (pos == null || ! (n instanceof Long))
+ return null;
+ value = n.intValue() + offset;
}
- if (i == match.length)
+ else if (set1 != null)
{
- pos.setErrorIndex(index);
- return null;
+ index = pos.getIndex();
+ int i;
+ boolean found = false;
+ for (i = offset; i < set1.length; ++i)
+ {
+ if (set1[i] != null)
+ if (dateStr.toUpperCase().startsWith(set1[i].toUpperCase(),
+ index))
+ {
+ found = true;
+ pos.setIndex(index + set1[i].length());
+ break;
+ }
+ }
+ if (!found && set2 != null)
+ {
+ for (i = offset; i < set2.length; ++i)
+ {
+ if (set2[i] != null)
+ if (dateStr.toUpperCase().startsWith(set2[i].toUpperCase(),
+ index))
+ {
+ found = true;
+ pos.setIndex(index + set2[i].length());
+ break;
+ }
+ }
+ }
+ if (!found)
+ {
+ pos.setErrorIndex(index);
+ return null;
+ }
+ value = i;
}
- pos.setIndex(index + match[i].length());
- value = i;
- }
- else
- value = offset;
+ else
+ value = offset;
- if (maybe2DigitYear)
- {
- // Parse into default century if the numeric year string has
- // exactly 2 digits.
- int digit_count = pos.getIndex() - index;
- if (digit_count == 2)
- is2DigitYear = true;
+ if (maybe2DigitYear)
+ {
+ // Parse into default century if the numeric year string has
+ // exactly 2 digits.
+ int digit_count = pos.getIndex() - index;
+ if (digit_count == 2)
+ {
+ is2DigitYear = true;
+ value += defaultCentury;
+ }
+ }
+
+ // Assign the value and move on.
+ calendar.set(calendar_field, value);
}
-
- // Assign the value and move on.
- calendar.set(calendar_field, value);
- }
- if (is2DigitYear)
- {
- // Apply the 80-20 heuristic to dermine the full year based on
- // defaultCenturyStart.
- int year = defaultCentury + calendar.get(Calendar.YEAR);
- calendar.set(Calendar.YEAR, year);
- if (calendar.getTime().compareTo(defaultCenturyStart) < 0)
- calendar.set(Calendar.YEAR, year + 100);
- }
-
- try
- {
+ if (is2DigitYear)
+ {
+ // Apply the 80-20 heuristic to dermine the full year based on
+ // defaultCenturyStart.
+ int year = calendar.get(Calendar.YEAR);
+ if (calendar.getTime().compareTo(defaultCenturyStart) < 0)
+ calendar.set(Calendar.YEAR, year + 100);
+ }
if (! saw_timezone)
{
// Use the real rules to determine whether or not this
@@ -854,6 +1134,69 @@ public class SimpleDateFormat extends DateFormat
pos.setErrorIndex(pos.getIndex());
return null;
}
+ }
+
+ /**
+ * <p>
+ * Computes the time zone offset in milliseconds
+ * relative to GMT, based on the supplied
+ * <code>String</code> representation.
+ * </p>
+ * <p>
+ * The supplied <code>String</code> must be a three
+ * or four digit signed number, with an optional 'GMT'
+ * prefix. The first one or two digits represents the hours,
+ * while the last two represent the minutes. The
+ * two sets of digits can optionally be separated by
+ * ':'. The mandatory sign prefix (either '+' or '-')
+ * indicates the direction of the offset from GMT.
+ * </p>
+ * <p>
+ * For example, 'GMT+0200' specifies 2 hours after
+ * GMT, while '-05:00' specifies 5 hours prior to
+ * GMT. The special case of 'GMT' alone can be used
+ * to represent the offset, 0.
+ * </p>
+ * <p>
+ * If the <code>String</code> can not be parsed,
+ * the result will be null. The resulting offset
+ * is wrapped in an <code>Integer</code> object, in
+ * order to allow such failure to be represented.
+ * </p>
+ *
+ * @param zoneString a string in the form
+ * (GMT)? sign hours : minutes
+ * where sign = '+' or '-', hours
+ * is a one or two digits representing
+ * a number between 0 and 23, and
+ * minutes is two digits representing
+ * a number between 0 and 59.
+ * @return the parsed offset, or null if parsing
+ * failed.
+ */
+ private Integer computeOffset(String zoneString)
+ {
+ Pattern pattern =
+ Pattern.compile("(GMT)?([+-])([012])?([0-9]):?([0-9]{2})");
+ Matcher matcher = pattern.matcher(zoneString);
+ if (matcher.matches())
+ {
+ int sign = matcher.group(2).equals("+") ? 1 : -1;
+ int hour = (Integer.parseInt(matcher.group(3)) * 10)
+ + Integer.parseInt(matcher.group(4));
+ int minutes = Integer.parseInt(matcher.group(5));
+
+ if (hour > 23)
+ return null;
+
+ int offset = sign * ((hour * 60) + minutes) * 60000;
+ return new Integer(offset);
+ }
+ else if (zoneString.startsWith("GMT"))
+ {
+ return new Integer(0);
+ }
+ return null;
}
// Compute the start of the current century as defined by
@@ -864,4 +1207,19 @@ public class SimpleDateFormat extends DateFormat
calendar.set(Calendar.YEAR, year - 80);
set2DigitYearStart(calendar.getTime());
}
+
+ /**
+ * Returns a copy of this instance of
+ * <code>SimpleDateFormat</code>. The copy contains
+ * clones of the formatting symbols and the 2-digit
+ * year century start date.
+ */
+ public Object clone()
+ {
+ SimpleDateFormat clone = (SimpleDateFormat) super.clone();
+ clone.setDateFormatSymbols((DateFormatSymbols) formatData.clone());
+ clone.set2DigitYearStart((Date) defaultCenturyStart.clone());
+ return clone;
+ }
+
}
diff --git a/libjava/java/util/Calendar.java b/libjava/java/util/Calendar.java
index 1f0b27a..8a37c5e 100644
--- a/libjava/java/util/Calendar.java
+++ b/libjava/java/util/Calendar.java
@@ -51,7 +51,7 @@ import java.lang.reflect.InvocationTargetException;
* integer fields which represent <code>YEAR</code>,
* <code>MONTH</code>, <code>DAY</code>, etc. The <code>Date</code>
* object represents a time in milliseconds since the Epoch. <br>
- *
+ *
* This class is locale sensitive. To get the Object matching the
* current locale you can use <code>getInstance</code>. You can even provide
* a locale or a timezone. <code>getInstance</code> returns currently
@@ -78,13 +78,13 @@ import java.lang.reflect.InvocationTargetException;
* and for the first line all fields are set, that line is used to
* compute the day. <br>
*
- *
+ *
<pre>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</pre>
- *
+ *
* The hour_of_day-field takes precedence over the ampm and
* hour_of_ampm fields. <br>
*
@@ -92,7 +92,7 @@ day_of_week + week_of_year</pre>
*
* To convert a calendar to a human readable form and vice versa, use
* the <code>java.text.DateFormat</code> class. <br>
- *
+ *
* Other useful things you can do with an calendar, is
* <code>roll</code>ing fields (that means increase/decrease a
* specific field by one, propagating overflows), or
@@ -101,7 +101,7 @@ day_of_week + week_of_year</pre>
* @see Date
* @see GregorianCalendar
* @see TimeZone
- * @see java.text.DateFormat
+ * @see java.text.DateFormat
*/
public abstract class Calendar implements Serializable, Cloneable
{
@@ -109,43 +109,52 @@ public abstract class Calendar implements Serializable, Cloneable
* 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
@@ -153,42 +162,51 @@ public abstract class Calendar implements Serializable, Cloneable
* 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.
+ * 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.
+ * milliseconds. The default is the value given by the time zone.
*/
public static final int DST_OFFSET = 16;
+
/**
* Number of time fields.
*/
@@ -198,26 +216,32 @@ public abstract class Calendar implements Serializable, Cloneable
* 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.
*/
@@ -227,50 +251,62 @@ public abstract class Calendar implements Serializable, Cloneable
* 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.
@@ -281,6 +317,7 @@ public abstract class Calendar implements Serializable, Cloneable
* Useful constant for 12-hour clock.
*/
public static final int AM = 0;
+
/**
* Useful constant for 12-hour clock.
*/
@@ -292,21 +329,25 @@ public abstract class Calendar implements Serializable, Cloneable
* @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.
@@ -332,7 +373,7 @@ public abstract class Calendar implements Serializable, Cloneable
/**
* Sets what the first day of week is. This is used for
- * WEEK_OF_MONTH and WEEK_OF_YEAR fields.
+ * WEEK_OF_MONTH and WEEK_OF_YEAR fields.
* @serial
*/
private int firstDayOfWeek;
@@ -347,7 +388,14 @@ public abstract class Calendar implements Serializable, Cloneable
private int minimalDaysInFirstWeek;
/**
- * The version of the serialized data on the stream.
+ * 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.
* <dl><dt>0 or not present</dt>
* <dd> JDK 1.1.5 or later.</dd>
* <dl><dt>1</dt>
@@ -371,14 +419,14 @@ public abstract class Calendar implements Serializable, Cloneable
private static final String bundleName = "gnu.java.locale.Calendar";
/**
- * get resource bundle:
+ * get resource bundle:
* The resources should be loaded via this method only. Iff an application
- * uses this method, the resourcebundle is required.
+ * uses this method, the resourcebundle is required.
*/
- private static ResourceBundle getBundle(Locale locale)
+ private static ResourceBundle getBundle(Locale locale)
{
return ResourceBundle.getBundle(bundleName, locale,
- ClassLoader.getSystemClassLoader());
+ ClassLoader.getSystemClassLoader());
}
/**
@@ -404,8 +452,9 @@ public abstract class Calendar implements Serializable, Cloneable
ResourceBundle rb = getBundle(locale);
firstDayOfWeek = ((Integer) rb.getObject("firstDayOfWeek")).intValue();
- minimalDaysInFirstWeek =
- ((Integer) rb.getObject("minimalDaysInFirstWeek")).intValue();
+ minimalDaysInFirstWeek = ((Integer) rb.getObject("minimalDaysInFirstWeek"))
+ .intValue();
+ clear();
}
/**
@@ -437,15 +486,17 @@ public abstract class Calendar implements Serializable, Cloneable
return getInstance(TimeZone.getDefault(), locale);
}
- /**
+ /**
* Cache of locale->calendar-class mappings. This avoids having to do a ResourceBundle
- * lookup for every getInstance call.
+ * lookup for every getInstance call.
*/
private static HashMap cache = new HashMap();
/** Preset argument types for calendar-class constructor lookup. */
- private static Class[] ctorArgTypes
- = new Class[] {TimeZone.class, Locale.class};
+ private static Class[] ctorArgTypes = new Class[]
+ {
+ TimeZone.class, Locale.class
+ };
/**
* Creates a calendar representing the actual time, using the given
@@ -473,7 +524,7 @@ public abstract class Calendar implements Serializable, Cloneable
}
}
- // GregorianCalendar is by far the most common case. Optimize by
+ // GregorianCalendar is by far the most common case. Optimize by
// avoiding reflection.
if (calendarClass == GregorianCalendar.class)
return new GregorianCalendar(zone, locale);
@@ -481,7 +532,7 @@ public abstract class Calendar implements Serializable, Cloneable
if (Calendar.class.isAssignableFrom(calendarClass))
{
Constructor ctor = calendarClass.getConstructor(ctorArgTypes);
- return (Calendar) ctor.newInstance(new Object[] {zone, locale});
+ return (Calendar) ctor.newInstance(new Object[] { zone, locale });
}
}
catch (ClassNotFoundException ex)
@@ -504,9 +555,9 @@ public abstract class Calendar implements Serializable, Cloneable
{
exception = ex;
}
-
- throw new RuntimeException("Error instantiating calendar for locale " +
- locale, exception);
+
+ throw new RuntimeException("Error instantiating calendar for locale "
+ + locale, exception);
}
/**
@@ -530,7 +581,7 @@ public abstract class Calendar implements Serializable, Cloneable
* Converts the milliseconds since the epoch UTC
* (<code>time</code>) to time fields
* (<code>fields</code>). Override this method if you write your
- * own Calendar.
+ * own Calendar.
*/
protected abstract void computeFields();
@@ -541,7 +592,7 @@ public abstract class Calendar implements Serializable, Cloneable
*/
public final Date getTime()
{
- if (!isTimeSet)
+ if (! isTimeSet)
computeTime();
return new Date(time);
}
@@ -562,7 +613,7 @@ public abstract class Calendar implements Serializable, Cloneable
*/
public long getTimeInMillis()
{
- if (!isTimeSet)
+ if (! isTimeSet)
computeTime();
return time;
}
@@ -575,9 +626,9 @@ public abstract class Calendar implements Serializable, Cloneable
*/
public void setTimeInMillis(long time)
{
+ clear();
this.time = time;
isTimeSet = true;
- computeFields();
}
/**
@@ -593,14 +644,14 @@ public abstract class Calendar implements Serializable, Cloneable
public int get(int field)
{
// If the requested field is invalid, force all fields to be recomputed.
- if (!isSet[field])
+ if (! isSet[field])
areFieldsSet = false;
complete();
return fields[field];
}
/**
- * Gets the value of the specified field. This method doesn't
+ * 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
@@ -626,21 +677,72 @@ public abstract class Calendar implements Serializable, Cloneable
*/
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 YEAR:
- case MONTH:
- case DATE:
+ 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
+ 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
+ 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
+ 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:
@@ -648,12 +750,15 @@ public abstract class Calendar implements Serializable, Cloneable
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 (field != DST_OFFSET && field != ZONE_OFFSET)
+ if (! explicitDSTOffset && (field != DST_OFFSET && field != ZONE_OFFSET))
isSet[DST_OFFSET] = false;
}
@@ -675,8 +780,10 @@ public abstract class Calendar implements Serializable, Cloneable
isSet[WEEK_OF_MONTH] = false;
isSet[DAY_OF_WEEK] = false;
isSet[DAY_OF_WEEK_IN_MONTH] = false;
+ isSet[ERA] = false;
- isSet[DST_OFFSET] = false; // May have crossed a DST boundary.
+ if (! explicitDSTOffset)
+ isSet[DST_OFFSET] = false; // May have crossed a DST boundary.
}
/**
@@ -706,8 +813,8 @@ public abstract class Calendar implements Serializable, Cloneable
* @param minute the minute.
* @param second the second.
*/
- public final void set(int year, int month, int date,
- int hour, int minute, int 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;
@@ -721,11 +828,15 @@ public abstract class Calendar implements Serializable, Cloneable
{
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;
- fields[i] = 0;
- }
+ isSet[i] = false;
}
/**
@@ -737,10 +848,15 @@ public abstract class Calendar implements Serializable, Cloneable
*/
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
+ };
isTimeSet = false;
areFieldsSet = false;
isSet[field] = false;
- fields[field] = 0;
+ fields[field] = tempFields[field];
}
/**
@@ -757,18 +873,18 @@ public abstract class Calendar implements Serializable, Cloneable
/**
* Fills any unset fields in the time field list
- * @return true if the specified field has a value.
+ * @return true if the specified field has a value.
*/
protected void complete()
{
- if (!isTimeSet)
+ if (! isTimeSet)
computeTime();
- if (!areFieldsSet)
+ if (! areFieldsSet)
computeFields();
}
/**
- * Compares the given calendar with this.
+ * 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).
@@ -776,12 +892,12 @@ public abstract class Calendar implements Serializable, Cloneable
public boolean equals(Object o)
{
return (o instanceof Calendar)
- && getTimeInMillis() == ((Calendar) o).getTimeInMillis();
+ && getTimeInMillis() == ((Calendar) o).getTimeInMillis();
}
/**
* Returns a hash code for this calendar.
- * @return a hash code, which fullfits the general contract of
+ * @return a hash code, which fullfits the general contract of
* <code>hashCode()</code>
*/
public int hashCode()
@@ -791,7 +907,7 @@ public abstract class Calendar implements Serializable, Cloneable
}
/**
- * Compares the given calendar with this.
+ * 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.
@@ -804,7 +920,7 @@ public abstract class Calendar implements Serializable, Cloneable
}
/**
- * Compares the given calendar with this.
+ * 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.
@@ -831,11 +947,11 @@ public abstract class Calendar implements Serializable, Cloneable
/**
* 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
+ * the maximum for this field is reached, start over with the
* minimum value. <br>
*
* <strong>Note:</strong> There may be situation, where the other
- * fields must be changed, e.g rolling the month on May, 31.
+ * 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.
@@ -854,7 +970,7 @@ public abstract class Calendar implements Serializable, Cloneable
*
* @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.
+ * negative for rolling down.
* @throws ArrayIndexOutOfBoundsException if the field is outside
* the valid range. The value of field must be >= 0 and
* <= <code>FIELD_COUNT</code>.
@@ -874,7 +990,6 @@ public abstract class Calendar implements Serializable, Cloneable
}
}
-
/**
* Sets the time zone to the specified value.
* @param zone the new time zone
@@ -918,7 +1033,7 @@ public abstract class Calendar implements Serializable, Cloneable
/**
* Sets what the first day of week is. This is used for
- * WEEK_OF_MONTH and WEEK_OF_YEAR fields.
+ * 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)
@@ -928,7 +1043,7 @@ public abstract class Calendar implements Serializable, Cloneable
/**
* Gets what the first day of week is. This is used for
- * WEEK_OF_MONTH and WEEK_OF_YEAR fields.
+ * WEEK_OF_MONTH and WEEK_OF_YEAR fields.
* @return the first day of week. One of SUNDAY to SATURDAY.
*/
public int getFirstDayOfWeek()
@@ -972,7 +1087,6 @@ public abstract class Calendar implements Serializable, Cloneable
*/
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.
@@ -984,7 +1098,7 @@ public abstract class Calendar implements Serializable, Cloneable
* 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.
+ * @return the least maximum value.
*/
public abstract int getLeastMaximum(int field);
@@ -1000,16 +1114,15 @@ public abstract class Calendar implements Serializable, Cloneable
*/
public int getActualMinimum(int field)
{
- Calendar tmp = (Calendar)clone(); // To avoid restoring state
+ 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
+ tmp.add(field, -1); // Try to get smaller
if (tmp.get(field) != min - 1)
- break; // Done if not successful
-
+ break; // Done if not successful
}
return min;
}
@@ -1018,7 +1131,7 @@ public abstract class Calendar implements Serializable, Cloneable
* 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.
+ * @return the actual maximum value.
* @throws ArrayIndexOutOfBoundsException if the field is outside
* the valid range. The value of field must be >= 0 and
* <= <code>FIELD_COUNT</code>.
@@ -1026,7 +1139,7 @@ public abstract class Calendar implements Serializable, Cloneable
*/
public int getActualMaximum(int field)
{
- Calendar tmp = (Calendar)clone(); // To avoid restoring state
+ Calendar tmp = (Calendar) clone(); // To avoid restoring state
int max = tmp.getLeastMaximum(field);
int end = tmp.getMaximum(field);
tmp.set(field, max);
@@ -1048,7 +1161,7 @@ public abstract class Calendar implements Serializable, Cloneable
{
Calendar cal = (Calendar) super.clone();
cal.fields = (int[]) fields.clone();
- cal.isSet = (boolean[])isSet.clone();
+ cal.isSet = (boolean[]) isSet.clone();
return cal;
}
catch (CloneNotSupportedException ex)
@@ -1057,16 +1170,19 @@ public abstract class Calendar implements Serializable, Cloneable
}
}
- 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="
- };
-
+ 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
@@ -1109,7 +1225,7 @@ public abstract class Calendar implements Serializable, Cloneable
* says, that it could be omitted. */
private void writeObject(ObjectOutputStream stream) throws IOException
{
- if (!isTimeSet)
+ if (! isTimeSet)
computeTime();
stream.defaultWriteObject();
}
@@ -1121,7 +1237,7 @@ public abstract class Calendar implements Serializable, Cloneable
throws IOException, ClassNotFoundException
{
stream.defaultReadObject();
- if (!isTimeSet)
+ if (! isTimeSet)
computeTime();
if (serialVersionOnStream > 1)
@@ -1130,7 +1246,6 @@ public abstract class Calendar implements Serializable, Cloneable
// 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;
diff --git a/libjava/java/util/GregorianCalendar.java b/libjava/java/util/GregorianCalendar.java
index d99a9f2..710dd56 100644
--- a/libjava/java/util/GregorianCalendar.java
+++ b/libjava/java/util/GregorianCalendar.java
@@ -39,6 +39,7 @@ exception statement from your version. */
package java.util;
+
/**
* <p>
* This class represents the Gregorian calendar, that is used in most
@@ -46,7 +47,7 @@ package java.util;
* for dates smaller than the date of the change to the Gregorian calendar.
* The Gregorian calendar differs from the Julian calendar by a different
* leap year rule (no leap year every 100 years, except if year is divisible
- * by 400).
+ * by 400).
* </p>
* <p>
* This change date is different from country to country, and can be changed with
@@ -136,7 +137,7 @@ public class GregorianCalendar extends Calendar
* Constant representing the era BC (Before Christ).
*/
public static final int BC = 0;
-
+
/**
* Constant representing the era AD (Anno Domini).
*/
@@ -164,43 +165,46 @@ public class GregorianCalendar extends Calendar
private static final String bundleName = "gnu.java.locale.Calendar";
/**
- * Retrieves the resource bundle. The resources should be loaded
- * via this method only. Iff an application uses this method, the
- * resourcebundle is required.
+ * Days in the epoch. Relative Jan 1, year '0' which is not a leap year.
+ * (although there is no year zero, this does not matter.)
+ * This is consistent with the formula:
+ * = (year-1)*365L + ((year-1) >> 2)
+ *
+ * Plus the gregorian correction:
+ * Math.floor((year-1) / 400.) - Math.floor((year-1) / 100.);
+ * For a correct julian date, the correction is -2 instead.
*
- * @param locale the locale in use for this calendar.
- * @return A resource bundle for the calendar for the specified locale.
+ * The gregorian cutover in 1582 was 10 days, so by calculating the
+ * correction from year zero, we have 15 non-leap days (even centuries)
+ * minus 3 leap days (year 400,800,1200) = 12. Subtracting two corrects
+ * this to the correct number 10.
*/
- private static ResourceBundle getBundle(Locale locale)
- {
- return ResourceBundle.getBundle(bundleName, locale,
- ClassLoader.getSystemClassLoader());
- }
+ private static final int EPOCH_DAYS = 719162;
/**
* Constructs a new GregorianCalender representing the current
- * time, using the default time zone and the default locale.
+ * time, using the default time zone and the default locale.
*/
public GregorianCalendar()
{
this(TimeZone.getDefault(), Locale.getDefault());
}
-
+
/**
* Constructs a new GregorianCalender representing the current
- * time, using the specified time zone and the default locale.
- *
+ * time, using the specified time zone and the default locale.
+ *
* @param zone a time zone.
*/
public GregorianCalendar(TimeZone zone)
{
this(zone, Locale.getDefault());
}
-
+
/**
* Constructs a new GregorianCalender representing the current
* time, using the default time zone and the specified locale.
- *
+ *
* @param locale a locale.
*/
public GregorianCalendar(Locale locale)
@@ -212,15 +216,30 @@ public class GregorianCalendar extends Calendar
* Constructs a new GregorianCalender representing the current
* time with the given time zone and the given locale.
*
- * @param zone a time zone.
- * @param locale a locale.
+ * @param zone a time zone.
+ * @param locale a locale.
*/
public GregorianCalendar(TimeZone zone, Locale locale)
{
+ this(zone, locale, false);
+ setTimeInMillis(System.currentTimeMillis());
+ complete();
+ }
+
+ /**
+ * Common constructor that all constructors should call.
+ * @param zone a time zone.
+ * @param locale a locale.
+ * @param unused unused parameter to make the signature differ from
+ * the public constructor (TimeZone, Locale).
+ */
+ private GregorianCalendar(TimeZone zone, Locale locale, boolean unused)
+ {
super(zone, locale);
- ResourceBundle rb = getBundle(locale);
+ ResourceBundle rb = ResourceBundle.getBundle(bundleName, locale,
+ ClassLoader
+ .getSystemClassLoader());
gregorianCutover = ((Date) rb.getObject("gregorianCutOver")).getTime();
- setTimeInMillis(System.currentTimeMillis());
}
/**
@@ -232,7 +251,7 @@ public class GregorianCalendar extends Calendar
*/
public GregorianCalendar(int year, int month, int day)
{
- super();
+ this(TimeZone.getDefault(), Locale.getDefault(), false);
set(year, month, day);
}
@@ -248,7 +267,7 @@ public class GregorianCalendar extends Calendar
*/
public GregorianCalendar(int year, int month, int day, int hour, int minute)
{
- super();
+ this(TimeZone.getDefault(), Locale.getDefault(), false);
set(year, month, day, hour, minute);
}
@@ -264,10 +283,10 @@ public class GregorianCalendar extends Calendar
* @param minute corresponds to the MINUTE time field.
* @param second corresponds to the SECOND time field.
*/
- public GregorianCalendar(int year, int month, int day,
- int hour, int minute, int second)
+ public GregorianCalendar(int year, int month, int day, int hour, int minute,
+ int second)
{
- super();
+ this(TimeZone.getDefault(), Locale.getDefault(), false);
set(year, month, day, hour, minute, second);
}
@@ -308,71 +327,23 @@ public class GregorianCalendar extends Calendar
* </p>
*
* @param year a year (use a negative value for BC).
- * @return true, if the given year is a leap year, false otherwise.
+ * @return true, if the given year is a leap year, false otherwise.
*/
public boolean isLeapYear(int year)
{
+ // Only years divisible by 4 can be leap years
if ((year & 3) != 0)
- // Only years divisible by 4 can be leap years
return false;
- // compute the linear day of the 29. February of that year.
- // The 13 is the number of days, that were omitted in the Gregorian
- // Calender until the epoch.
- int julianDay = (((year-1) * (365*4+1)) >> 2) + (31+29 -
- (((1970-1) * (365*4+1)) / 4 + 1 - 13));
-
- // If that day is smaller than the gregorianChange the julian
- // rule applies: This is a leap year since it is divisible by 4.
- if (julianDay * (24 * 60 * 60 * 1000L) < gregorianCutover)
+ // Is the leap-day a Julian date? Then it's a leap year
+ if (! isGregorian(year, 31 + 29 - 1))
return true;
+ // Apply gregorian rules otherwise
return ((year % 100) != 0 || (year % 400) == 0);
}
/**
- * Get the linear time in milliseconds since the epoch. If you
- * specify a nonpositive year it is interpreted as BC as
- * following: 0 is 1 BC, -1 is 2 BC and so on. The date is
- * interpreted as gregorian if the change occurred before that date.
- *
- * @param year the year of the date.
- * @param dayOfYear the day of year of the date; 1 based.
- * @param millis the millisecond in that day.
- * @return the days since the epoch, may be negative.
- */
- private long getLinearTime(int year, int dayOfYear, int millis)
- {
- // The 13 is the number of days, that were omitted in the Gregorian
- // Calendar until the epoch.
- // We shift right by 2 instead of dividing by 4, to get correct
- // results for negative years (and this is even more efficient).
- int julianDay = ((year * (365 * 4 + 1)) >> 2) + dayOfYear -
- ((1970 * (365 * 4 + 1)) / 4 + 1 - 13);
- long time = julianDay * (24 * 60 * 60 * 1000L) + millis;
-
- if (time >= gregorianCutover)
- {
- // subtract the days that are missing in gregorian calendar
- // with respect to julian calendar.
- //
- // Okay, here we rely on the fact that the gregorian
- // calendar was introduced in the AD era. This doesn't work
- // with negative years.
- //
- // The additional leap year factor accounts for the fact that
- // a leap day is not seen on Jan 1 of the leap year.
- // And on and after the leap day, the leap day has already been
- // included in dayOfYear.
- int gregOffset = (year / 400) - (year / 100) + 2;
- if (isLeapYear (year, true))
- --gregOffset;
- time += gregOffset * (24 * 60 * 60 * 1000L);
- }
- return time;
- }
-
- /**
* Retrieves the day of the week corresponding to the specified
* day of the specified year.
*
@@ -382,8 +353,8 @@ public class GregorianCalendar extends Calendar
*/
private int getWeekDay(int year, int dayOfYear)
{
- int day =
- (int) (getLinearTime(year, dayOfYear, 0) / (24 * 60 * 60 * 1000L));
+ boolean greg = isGregorian(year, dayOfYear);
+ int day = (int) getLinearDay(year, dayOfYear, greg);
// The epoch was a thursday.
int weekday = (day + THURSDAY) % 7;
@@ -393,235 +364,360 @@ public class GregorianCalendar extends Calendar
}
/**
- * <p>
- * Calculate the dayOfYear from the fields array.
- * The relativeDays is used, to account for weeks that begin before
- * the Gregorian change and end after it.
- * </p>
- * <p>
- * We return two values. The first is used to determine, if we
- * should use the Gregorian calendar or the Julian calendar, in order
- * to handle the change year. The second is a relative day after the given
- * day. This is necessary for week calculation in the year in
- * which the Gregorian change occurs.
- * </p>
- *
- * @param year the year, negative for BC.
- * @return an array of two integer values, the first containing a reference
- * day in the current year, the second a relative count since this reference
- * day.
+ * Returns the day of the week for the first day of a given month (0..11)
*/
- private int[] getDayOfYear(int year)
+ private int getFirstDayOfMonth(int year, int month)
{
- if (isSet[MONTH])
- {
- int dayOfYear;
- if (fields[MONTH] > FEBRUARY)
- {
+ int[] dayCount = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
- // The months after February are regular:
- // 9 is an offset found by try and error.
- dayOfYear = (fields[MONTH] * (31 + 30 + 31 + 30 + 31) - 9) / 5;
- if (isLeapYear(year))
- dayOfYear++;
- }
- else
- dayOfYear = 31 * fields[MONTH];
+ if (month > 11)
+ {
+ year += (month / 12);
+ month = month % 12;
+ }
- if (isSet[DAY_OF_MONTH])
+ if (month < 0)
+ {
+ year += (int) month / 12;
+ month = month % 12;
+ if (month < 0)
{
- return new int[]
- {
- dayOfYear + fields[DAY_OF_MONTH], 0};
+ month += 12;
+ year--;
}
- if (isSet[WEEK_OF_MONTH] && isSet[DAY_OF_WEEK])
- {
- // the weekday of the first day in that month is:
- int weekday = getWeekDay(year, ++dayOfYear);
+ }
- return new int[]
- {
- dayOfYear,
- // the day of week in the first week
- // (weeks starting on sunday) is:
- fields[DAY_OF_WEEK] - weekday +
- // Now jump to the right week and correct the possible
- // error made by assuming sunday is the first week day.
- 7 * (fields[WEEK_OF_MONTH]
- + (fields[DAY_OF_WEEK] < getFirstDayOfWeek()? 0 : -1)
- + (weekday < getFirstDayOfWeek()? -1 : 0))};
- }
- if (isSet[DAY_OF_WEEK] && isSet[DAY_OF_WEEK_IN_MONTH])
- {
- // the weekday of the first day in that month is:
- int weekday = getWeekDay(year, ++dayOfYear);
- return new int[] {
- dayOfYear,
- fields[DAY_OF_WEEK] - weekday +
- 7 * (fields[DAY_OF_WEEK_IN_MONTH]
- + (fields[DAY_OF_WEEK] < weekday ? 0 : -1))};
- }
+ int dayOfYear = dayCount[month] + 1;
+ if (month > 1)
+ if (isLeapYear(year))
+ dayOfYear++;
+
+ boolean greg = isGregorian(year, dayOfYear);
+ int day = (int) getLinearDay(year, dayOfYear, greg);
+
+ // The epoch was a thursday.
+ int weekday = (day + THURSDAY) % 7;
+ if (weekday <= 0)
+ weekday += 7;
+ return weekday;
+ }
+
+ /**
+ * Takes a year, and a (zero based) day of year and determines
+ * if it is gregorian or not.
+ */
+ private boolean isGregorian(int year, int dayOfYear)
+ {
+ int relativeDay = (year - 1) * 365 + ((year - 1) >> 2) + dayOfYear
+ - EPOCH_DAYS; // gregorian days from 1 to epoch.
+ int gregFactor = (int) Math.floor((double) (year - 1) / 400.)
+ - (int) Math.floor((double) (year - 1) / 100.);
+
+ return ((relativeDay + gregFactor) * 60L * 60L * 24L * 1000L >= gregorianCutover);
+ }
+
+ /**
+ * Check set fields for validity, without leniency.
+ *
+ * @throws IllegalArgumentException if a field is invalid
+ */
+ private void nonLeniencyCheck() throws IllegalArgumentException
+ {
+ int[] month_days = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
+ int year = fields[YEAR];
+ int month = fields[MONTH];
+ int leap = isLeapYear(year) ? 1 : 0;
+
+ if (isSet[ERA] && fields[ERA] != AD && fields[ERA] != BC)
+ throw new IllegalArgumentException("Illegal ERA.");
+ if (isSet[YEAR] && fields[YEAR] < 1)
+ throw new IllegalArgumentException("Illegal YEAR.");
+ if (isSet[MONTH] && (month < 0 || month > 11))
+ throw new IllegalArgumentException("Illegal MONTH.");
+ if (isSet[WEEK_OF_YEAR])
+ {
+ int daysInYear = 365 + leap;
+ daysInYear += (getFirstDayOfMonth(year, 0) - 1); // pad first week
+ int last = getFirstDayOfMonth(year, 11) + 4;
+ if (last > 7)
+ last -= 7;
+ daysInYear += 7 - last;
+ int weeks = daysInYear / 7;
+ if (fields[WEEK_OF_YEAR] < 1 || fields[WEEK_OF_YEAR] > weeks)
+ throw new IllegalArgumentException("Illegal WEEK_OF_YEAR.");
}
- // MONTH + something did not succeed.
- if (isSet[DAY_OF_YEAR])
+ if (isSet[WEEK_OF_MONTH])
{
- return new int[] {0, fields[DAY_OF_YEAR]};
+ int weeks = (month == 1 && leap == 0) ? 4 : 5;
+ if (fields[WEEK_OF_MONTH] < 1 || fields[WEEK_OF_MONTH] > weeks)
+ throw new IllegalArgumentException("Illegal WEEK_OF_MONTH.");
}
-
- if (isSet[DAY_OF_WEEK] && isSet[WEEK_OF_YEAR])
+
+ if (isSet[DAY_OF_MONTH])
+ if (fields[DAY_OF_MONTH] < 1
+ || fields[DAY_OF_MONTH] > month_days[month]
+ + ((month == 1) ? leap : 0))
+ throw new IllegalArgumentException("Illegal DAY_OF_MONTH.");
+
+ if (isSet[DAY_OF_YEAR]
+ && (fields[DAY_OF_YEAR] < 1 || fields[DAY_OF_YEAR] > 365 + leap))
+ throw new IllegalArgumentException("Illegal DAY_OF_YEAR.");
+
+ if (isSet[DAY_OF_WEEK]
+ && (fields[DAY_OF_WEEK] < 1 || fields[DAY_OF_WEEK] > 7))
+ throw new IllegalArgumentException("Illegal DAY_OF_WEEK.");
+
+ if (isSet[DAY_OF_WEEK_IN_MONTH])
{
- int dayOfYear = getMinimalDaysInFirstWeek();
- // the weekday of the day, that begins the first week
- // in that year is:
- int weekday = getWeekDay(year, dayOfYear);
-
- return new int[] {
- dayOfYear,
- // the day of week in the first week
- // (weeks starting on sunday) is:
- fields[DAY_OF_WEEK] - weekday
- // Now jump to the right week and correct the possible
- // error made by assuming sunday is the first week day.
- + 7 * (fields[WEEK_OF_YEAR]
- + (fields[DAY_OF_WEEK] < getFirstDayOfWeek()? 0 : -1)
- + (weekday < getFirstDayOfWeek()? -1 : 0))};
+ int weeks = (month == 1 && leap == 0) ? 4 : 5;
+ if (fields[DAY_OF_WEEK_IN_MONTH] < -weeks
+ || fields[DAY_OF_WEEK_IN_MONTH] > weeks)
+ throw new IllegalArgumentException("Illegal DAY_OF_WEEK_IN_MONTH.");
}
- // As last resort return Jan, 1st.
- return new int[] {1, 0};
+ if (isSet[AM_PM] && fields[AM_PM] != AM && fields[AM_PM] != PM)
+ throw new IllegalArgumentException("Illegal AM_PM.");
+ if (isSet[HOUR] && (fields[HOUR] < 0 || fields[HOUR] > 12))
+ throw new IllegalArgumentException("Illegal HOUR.");
+ if (isSet[HOUR_OF_DAY]
+ && (fields[HOUR_OF_DAY] < 0 || fields[HOUR_OF_DAY] > 23))
+ throw new IllegalArgumentException("Illegal HOUR_OF_DAY.");
+ if (isSet[MINUTE] && (fields[MINUTE] < 0 || fields[MINUTE] > 59))
+ throw new IllegalArgumentException("Illegal MINUTE.");
+ if (isSet[SECOND] && (fields[SECOND] < 0 || fields[SECOND] > 59))
+ throw new IllegalArgumentException("Illegal SECOND.");
+ if (isSet[MILLISECOND]
+ && (fields[MILLISECOND] < 0 || fields[MILLISECOND] > 999))
+ throw new IllegalArgumentException("Illegal MILLISECOND.");
+ if (isSet[ZONE_OFFSET]
+ && (fields[ZONE_OFFSET] < -12 * 60 * 60 * 1000L
+ || fields[ZONE_OFFSET] > 12 * 60 * 60 * 1000L))
+ throw new IllegalArgumentException("Illegal ZONE_OFFSET.");
+ if (isSet[DST_OFFSET]
+ && (fields[DST_OFFSET] < -12 * 60 * 60 * 1000L
+ || fields[DST_OFFSET] > 12 * 60 * 60 * 1000L))
+ throw new IllegalArgumentException("Illegal DST_OFFSET.");
}
/**
* Converts the time field values (<code>fields</code>) to
- * milliseconds since the epoch UTC (<code>time</code>).
+ * milliseconds since the epoch UTC (<code>time</code>).
*
* @throws IllegalArgumentException if any calendar fields
* are invalid.
*/
protected synchronized void computeTime()
{
- int era = isSet[ERA] ? fields[ERA] : AD;
- int year = isSet[YEAR] ? fields[YEAR] : 1970;
- if (era == BC)
- year = 1 - year;
+ int millisInDay = 0;
+ int era = fields[ERA];
+ int year = fields[YEAR];
+ int month = fields[MONTH];
+ int day = fields[DAY_OF_MONTH];
+
+ int minute = fields[MINUTE];
+ int second = fields[SECOND];
+ int millis = fields[MILLISECOND];
+ int[] month_days = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
+ int[] dayCount = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
+ int hour = 0;
- int[] daysOfYear = getDayOfYear(year);
+ if (! isLenient())
+ nonLeniencyCheck();
- int hour = 0;
- if (isSet[HOUR_OF_DAY])
- hour = fields[HOUR_OF_DAY];
- else if (isSet[HOUR])
+ if (! isSet[MONTH] && (! isSet[DAY_OF_WEEK] || isSet[WEEK_OF_YEAR]))
+ {
+ // 5: YEAR + DAY_OF_WEEK + WEEK_OF_YEAR
+ if (isSet[WEEK_OF_YEAR])
+ {
+ int first = getFirstDayOfMonth(year, 0);
+ int offs = 1;
+ int daysInFirstWeek = getFirstDayOfWeek() - first;
+ if (daysInFirstWeek <= 0)
+ daysInFirstWeek += 7;
+
+ if (daysInFirstWeek < getMinimalDaysInFirstWeek())
+ offs += daysInFirstWeek;
+ else
+ offs -= 7 - daysInFirstWeek;
+ month = 0;
+ day = offs + 7 * (fields[WEEK_OF_YEAR] - 1);
+ offs = fields[DAY_OF_WEEK] - getFirstDayOfWeek();
+
+ if (offs < 0)
+ offs += 7;
+ day += offs;
+ }
+ else
+ {
+ // 4: YEAR + DAY_OF_YEAR
+ month = 0;
+ day = fields[DAY_OF_YEAR];
+ }
+ }
+ else
+ {
+ if (isSet[DAY_OF_WEEK])
+ {
+ int first = getFirstDayOfMonth(year, month);
+
+ // 3: YEAR + MONTH + DAY_OF_WEEK_IN_MONTH + DAY_OF_WEEK
+ if (isSet[DAY_OF_WEEK_IN_MONTH])
+ {
+ int offs = fields[DAY_OF_WEEK] - first;
+ if (offs < 0)
+ offs += 7;
+ day = 1 + 7 * (fields[DAY_OF_WEEK_IN_MONTH] - 1);
+ day += offs;
+ }
+ else
+ { // 2: YEAR + MONTH + WEEK_OF_MONTH + DAY_OF_WEEK
+ int offs = 1;
+ int daysInFirstWeek = getFirstDayOfWeek() - first;
+ if (daysInFirstWeek <= 0)
+ daysInFirstWeek += 7;
+
+ if (daysInFirstWeek < getMinimalDaysInFirstWeek())
+ offs += daysInFirstWeek;
+ else
+ offs -= 7 - daysInFirstWeek;
+
+ day = offs + 7 * (fields[WEEK_OF_MONTH] - 1);
+ offs = fields[DAY_OF_WEEK] - getFirstDayOfWeek();
+ if (offs < 0)
+ offs += 7;
+ day += offs;
+ }
+ }
+
+ // 1: YEAR + MONTH + DAY_OF_MONTH
+ }
+ if (era == BC && year > 0)
+ year = 1 - year;
+
+ // rest of code assumes day/month/year set
+ // should negative BC years be AD?
+ // get the hour (but no check for validity)
+ if (isSet[HOUR])
{
hour = fields[HOUR];
- if (isSet[AM_PM] && fields[AM_PM] == PM)
+ if (fields[AM_PM] == PM)
if (hour != 12) /* not Noon */
- hour += 12;
+ hour += 12;
/* Fix the problem of the status of 12:00 AM (midnight). */
- if (isSet[AM_PM] && fields[AM_PM] == AM && hour == 12)
+ if (fields[AM_PM] == AM && hour == 12)
hour = 0;
}
+ else
+ hour = fields[HOUR_OF_DAY];
- int minute = isSet[MINUTE] ? fields[MINUTE] : 0;
- int second = isSet[SECOND] ? fields[SECOND] : 0;
- int millis = isSet[MILLISECOND] ? fields[MILLISECOND] : 0;
- int millisInDay;
+ // Read the era,year,month,day fields and convert as appropriate.
+ // Calculate number of milliseconds into the day
+ // This takes care of both h, m, s, ms over/underflows.
+ long allMillis = (((hour * 60L) + minute) * 60L + second) * 1000L + millis;
+ day += allMillis / (24 * 60 * 60 * 1000L);
+ millisInDay = (int) (allMillis % (24 * 60 * 60 * 1000L));
- if (isLenient())
+ if (month < 0)
{
- // prevent overflow
- long allMillis = (((hour * 60L) + minute) * 60L + second) * 1000L
- + millis;
- daysOfYear[1] += allMillis / (24 * 60 * 60 * 1000L);
- millisInDay = (int) (allMillis % (24 * 60 * 60 * 1000L));
+ year += (int) month / 12;
+ month = month % 12;
+ if (month < 0)
+ {
+ month += 12;
+ year--;
+ }
}
- else
+ if (month > 11)
{
- if (hour < 0 || hour >= 24 || minute < 0 || minute > 59
- || second < 0 || second > 59 || millis < 0 || millis >= 1000)
- throw new IllegalArgumentException();
- millisInDay = (((hour * 60) + minute) * 60 + second) * 1000 + millis;
+ year += (month / 12);
+ month = month % 12;
}
- time = getLinearTime(year, daysOfYear[0], millisInDay);
- // Add the relative days after calculating the linear time, to
- // get right behaviour when jumping over the gregorianCutover.
- time += daysOfYear[1] * (24 * 60 * 60 * 1000L);
+ month_days[1] = isLeapYear(year) ? 29 : 28;
+ while (day <= 0)
+ {
+ if (month == 0)
+ {
+ year--;
+ month_days[1] = isLeapYear(year) ? 29 : 28;
+ }
+ month = (month + 11) % 12;
+ day += month_days[month];
+ }
+ while (day > month_days[month])
+ {
+ day -= (month_days[month]);
+ month = (month + 1) % 12;
+ if (month == 0)
+ {
+ year++;
+ month_days[1] = isLeapYear(year) ? 29 : 28;
+ }
+ }
- TimeZone zone = getTimeZone();
- int rawOffset = isSet[ZONE_OFFSET]
- ? fields[ZONE_OFFSET] : zone.getRawOffset();
-
- int dayOfYear = daysOfYear[0] + daysOfYear[1];
- // This formula isn't right, so check for month as a quick fix.
- // It doesn't compensate for leap years and puts day 30 in month 1
- // instead of month 0.
- int month = isSet[MONTH]
- ? fields[MONTH] : (dayOfYear * 5 + 3) / (31 + 30 + 31 + 30 + 31);
- // This formula isn't right, so check for day as a quick fix. It
- // doesn't compensate for leap years, either.
- int day = isSet[DAY_OF_MONTH] ? fields[DAY_OF_MONTH]
- : (6 + (dayOfYear * 5 + 3) % (31 + 30 + 31 + 30 + 31)) / 5;
- int weekday = ((int) (time / (24 * 60 * 60 * 1000L)) + THURSDAY) % 7;
+ // ok, by here we have valid day,month,year,era and millisinday
+ int dayOfYear = dayCount[month] + day - 1; // (day starts on 1)
+ if (isLeapYear(year) && month > 1)
+ dayOfYear++;
+
+ int relativeDay = (year - 1) * 365 + ((year - 1) >> 2) + dayOfYear
+ - EPOCH_DAYS; // gregorian days from 1 to epoch.
+ int gregFactor = (int) Math.floor((double) (year - 1) / 400.)
+ - (int) Math.floor((double) (year - 1) / 100.);
+
+ if ((relativeDay + gregFactor) * 60L * 60L * 24L * 1000L >= gregorianCutover)
+ relativeDay += gregFactor;
+ else
+ relativeDay -= 2;
+
+ time = relativeDay * (24 * 60 * 60 * 1000L) + millisInDay;
+
+ // the epoch was a Thursday.
+ int weekday = (int) (relativeDay + THURSDAY) % 7;
if (weekday <= 0)
weekday += 7;
- int dstOffset = isSet[DST_OFFSET]
- ? fields[DST_OFFSET] : (zone.getOffset((year < 0) ? BC : AD,
- (year < 0) ? 1 - year : year,
- month, day, weekday, millisInDay)
- - zone.getRawOffset());
- time -= rawOffset + dstOffset;
- isTimeSet = true;
- }
+ fields[DAY_OF_WEEK] = weekday;
- /**
- * <p>
- * Determines if the given year is a leap year.
- * </p>
- * <p>
- * To specify a year in the BC era, use a negative value calculated
- * as 1 - y, where y is the required year in BC. So, 1 BC is 0,
- * 2 BC is -1, 3 BC is -2, etc.
- * </p>
- *
- * @param year a year (use a negative value for BC).
- * @param gregorian if true, use the gregorian leap year rule.
- * @return true, if the given year is a leap year, false otherwise.
- */
- private boolean isLeapYear(int year, boolean gregorian)
- {
- if ((year & 3) != 0)
- // Only years divisible by 4 can be leap years
- return false;
+ // Time zone corrections.
+ TimeZone zone = getTimeZone();
+ int rawOffset = isSet[ZONE_OFFSET] ? fields[ZONE_OFFSET]
+ : zone.getRawOffset();
- if (!gregorian)
- return true;
+ int dstOffset = isSet[DST_OFFSET] ? fields[DST_OFFSET]
+ : (zone.getOffset((year < 0) ? BC : AD,
+ (year < 0) ? 1 - year
+ : year,
+ month, day, weekday,
+ millisInDay)
+ - zone.getRawOffset());
- // We rely on AD area here.
- return ((year % 100) != 0 || (year % 400) == 0);
+ time -= rawOffset + dstOffset;
+
+ isTimeSet = true;
}
/**
* Get the linear day in days since the epoch, using the
* Julian or Gregorian calendar as specified. If you specify a
* nonpositive year it is interpreted as BC as following: 0 is 1
- * BC, -1 is 2 BC and so on.
+ * BC, -1 is 2 BC and so on.
*
* @param year the year of the date.
* @param dayOfYear the day of year of the date; 1 based.
* @param gregorian <code>true</code>, if we should use the Gregorian rules.
* @return the days since the epoch, may be negative.
*/
- private int getLinearDay(int year, int dayOfYear, boolean gregorian)
- {
- // The 13 is the number of days, that were omitted in the Gregorian
- // Calender until the epoch.
- // We shift right by 2 instead of dividing by 4, to get correct
- // results for negative years (and this is even more efficient).
- int julianDay = ((year * (365 * 4 + 1)) >> 2) + dayOfYear -
- ((1970 * (365 * 4 + 1)) / 4 + 1 - 13);
-
+ public long getLinearDay(int year, int dayOfYear, boolean gregorian)
+ {
+ // The 13 is the number of days, that were omitted in the Gregorian
+ // Calender until the epoch.
+ // We shift right by 2 instead of dividing by 4, to get correct
+ // results for negative years (and this is even more efficient).
+ long julianDay = (year - 1) * 365L + ((year - 1) >> 2) + (dayOfYear - 1)
+ - EPOCH_DAYS; // gregorian days from 1 to epoch.
+
if (gregorian)
{
// subtract the days that are missing in gregorian calendar
@@ -633,11 +729,13 @@ public class GregorianCalendar extends Calendar
//
// The additional leap year factor accounts for the fact that
// a leap day is not seen on Jan 1 of the leap year.
- int gregOffset = (year / 400) - (year / 100) + 2;
- if (isLeapYear (year, true) && dayOfYear < 31 + 29)
- --gregOffset;
- julianDay += gregOffset;
+ int gregOffset = (int) Math.floor((double) (year - 1) / 400.)
+ - (int) Math.floor((double) (year - 1) / 100.);
+
+ return julianDay + gregOffset;
}
+ else
+ julianDay -= 2;
return julianDay;
}
@@ -646,26 +744,27 @@ public class GregorianCalendar extends Calendar
* day_of_year, day_of_month, day_of_week, and writes the result
* into the fields array.
*
- * @param day the linear day.
+ * @param day the linear day.
* @param gregorian true, if we should use Gregorian rules.
*/
- private void calculateDay(int day, boolean gregorian)
+ private void calculateDay(int[] fields, long day, boolean gregorian)
{
- // the epoch is a Thursday.
- int weekday = (day + THURSDAY) % 7;
+ // the epoch was a Thursday.
+ int weekday = (int) (day + THURSDAY) % 7;
if (weekday <= 0)
weekday += 7;
fields[DAY_OF_WEEK] = weekday;
// get a first approximation of the year. This may be one
// year too big.
- int year = 1970 + (gregorian
- ? ((day - 100) * 400) / (365 * 400 + 100 - 4 + 1)
- : ((day - 100) * 4) / (365 * 4 + 1));
+ int year = 1970
+ + (int) (gregorian
+ ? ((day - 100L) * 400L) / (365L * 400L + 100L - 4L
+ + 1L) : ((day - 100L) * 4L) / (365L * 4L + 1L));
if (day >= 0)
year++;
- int firstDayOfYear = getLinearDay(year, 1, gregorian);
+ long firstDayOfYear = getLinearDay(year, 1, gregorian);
// Now look in which year day really lies.
if (day < firstDayOfYear)
@@ -674,9 +773,9 @@ public class GregorianCalendar extends Calendar
firstDayOfYear = getLinearDay(year, 1, gregorian);
}
- day -= firstDayOfYear - 1; // day of year, one based.
+ day -= firstDayOfYear - 1; // day of year, one based.
- fields[DAY_OF_YEAR] = day;
+ fields[DAY_OF_YEAR] = (int) day;
if (year <= 0)
{
fields[ERA] = BC;
@@ -688,16 +787,16 @@ public class GregorianCalendar extends Calendar
fields[YEAR] = year;
}
- int leapday = isLeapYear(year, gregorian) ? 1 : 0;
+ int leapday = isLeapYear(year) ? 1 : 0;
if (day <= 31 + 28 + leapday)
{
- fields[MONTH] = day / 32; // 31->JANUARY, 32->FEBRUARY
- fields[DAY_OF_MONTH] = day - 31 * fields[MONTH];
+ fields[MONTH] = (int) day / 32; // 31->JANUARY, 32->FEBRUARY
+ fields[DAY_OF_MONTH] = (int) day - 31 * fields[MONTH];
}
else
{
// A few more magic formulas
- int scaledDay = (day - leapday) * 5 + 8;
+ int scaledDay = ((int) day - leapday) * 5 + 8;
fields[MONTH] = scaledDay / (31 + 30 + 31 + 30 + 31);
fields[DAY_OF_MONTH] = (scaledDay % (31 + 30 + 31 + 30 + 31)) / 5 + 1;
}
@@ -716,25 +815,26 @@ public class GregorianCalendar extends Calendar
fields[ZONE_OFFSET] = zone.getRawOffset();
long localTime = time + fields[ZONE_OFFSET];
- int day = (int) (localTime / (24 * 60 * 60 * 1000L));
+ long day = localTime / (24 * 60 * 60 * 1000L);
int millisInDay = (int) (localTime % (24 * 60 * 60 * 1000L));
+
if (millisInDay < 0)
{
millisInDay += (24 * 60 * 60 * 1000);
day--;
}
- calculateDay(day, gregorian);
- fields[DST_OFFSET] =
- zone.getOffset(fields[ERA], fields[YEAR], fields[MONTH],
- fields[DAY_OF_MONTH], fields[DAY_OF_WEEK],
- millisInDay) - fields[ZONE_OFFSET];
+ calculateDay(fields, day, gregorian);
+ fields[DST_OFFSET] = zone.getOffset(fields[ERA], fields[YEAR],
+ fields[MONTH], fields[DAY_OF_MONTH],
+ fields[DAY_OF_WEEK], millisInDay)
+ - fields[ZONE_OFFSET];
millisInDay += fields[DST_OFFSET];
if (millisInDay >= 24 * 60 * 60 * 1000)
{
millisInDay -= 24 * 60 * 60 * 1000;
- calculateDay(++day, gregorian);
+ calculateDay(fields, ++day, gregorian);
}
fields[DAY_OF_WEEK_IN_MONTH] = (fields[DAY_OF_MONTH] + 6) / 7;
@@ -749,13 +849,12 @@ public class GregorianCalendar extends Calendar
// Do the Correction: getMinimalDaysInFirstWeek() is always in the
// first week.
int minDays = getMinimalDaysInFirstWeek();
- int firstWeekday =
- (7 + getWeekDay(fields[YEAR], minDays) - getFirstDayOfWeek()) % 7;
+ int firstWeekday = (7 + getWeekDay(fields[YEAR], minDays)
+ - getFirstDayOfWeek()) % 7;
if (minDays - firstWeekday < 1)
weekOfYear++;
fields[WEEK_OF_YEAR] = weekOfYear;
-
int hourOfDay = millisInDay / (60 * 60 * 1000);
fields[AM_PM] = (hourOfDay < 12) ? AM : PM;
int hour = hourOfDay % 12;
@@ -767,14 +866,7 @@ public class GregorianCalendar extends Calendar
fields[SECOND] = millisInDay / (1000);
fields[MILLISECOND] = millisInDay % 1000;
-
- areFieldsSet = isSet[ERA] = isSet[YEAR] = isSet[MONTH] =
- isSet[WEEK_OF_YEAR] = isSet[WEEK_OF_MONTH] =
- isSet[DAY_OF_MONTH] = isSet[DAY_OF_YEAR] = isSet[DAY_OF_WEEK] =
- isSet[DAY_OF_WEEK_IN_MONTH] = isSet[AM_PM] = isSet[HOUR] =
- isSet[HOUR_OF_DAY] = isSet[MINUTE] = isSet[SECOND] =
- isSet[MILLISECOND] = isSet[ZONE_OFFSET] = isSet[DST_OFFSET] = true;
-
+ areFieldsSet = isSet[ERA] = isSet[YEAR] = isSet[MONTH] = isSet[WEEK_OF_YEAR] = isSet[WEEK_OF_MONTH] = isSet[DAY_OF_MONTH] = isSet[DAY_OF_YEAR] = isSet[DAY_OF_WEEK] = isSet[DAY_OF_WEEK_IN_MONTH] = isSet[AM_PM] = isSet[HOUR] = isSet[HOUR_OF_DAY] = isSet[MINUTE] = isSet[SECOND] = isSet[MILLISECOND] = isSet[ZONE_OFFSET] = isSet[DST_OFFSET] = true;
}
/**
@@ -782,7 +874,7 @@ public class GregorianCalendar extends Calendar
* equivalent to this if it is also a <code>GregorianCalendar</code>
* with the same time since the epoch under the same conditions
* (same change date and same time zone).
- *
+ *
* @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 necessarily have the same fields).
@@ -794,48 +886,20 @@ public class GregorianCalendar extends Calendar
*/
public boolean equals(Object o)
{
- if (!(o instanceof GregorianCalendar))
+ if (! (o instanceof GregorianCalendar))
return false;
GregorianCalendar cal = (GregorianCalendar) o;
return (cal.getTimeInMillis() == getTimeInMillis());
}
-// /**
-// * Compares the given calender 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 calender o.
-// */
-// public boolean before(Object o) {
-// if (!(o instanceof GregorianCalendar))
-// return false;
-
-// GregorianCalendar cal = (GregorianCalendar) o;
-// return (cal.getTimeInMillis() < getTimeInMillis());
-// }
-
-// /**
-// * Compares the given calender 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 calender o.
-// */
-// public boolean after(Object o) {
-// if (!(o instanceof GregorianCalendar))
-// return false;
-
-// GregorianCalendar cal = (GregorianCalendar) o;
-// return (cal.getTimeInMillis() > 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 one of the time field constants.
* @param amount the amount of time to add.
- * @exception IllegalArgumentException if <code>field</code> is
+ * @exception IllegalArgumentException if <code>field</code> is
* <code>ZONE_OFFSET</code>, <code>DST_OFFSET</code>, or invalid; or
* if <code>amount</code> contains an out-of-range value and the calendar
* is not in lenient mode.
@@ -859,18 +923,18 @@ public class GregorianCalendar extends Calendar
fields[MONTH] += 12;
fields[YEAR]--;
}
- isTimeSet = false;
int maxDay = getActualMaximum(DAY_OF_MONTH);
if (fields[DAY_OF_MONTH] > maxDay)
{
fields[DAY_OF_MONTH] = maxDay;
- isTimeSet = false;
}
+ set(YEAR, fields[YEAR]);
+ set(MONTH, fields[MONTH]);
break;
case DAY_OF_MONTH:
case DAY_OF_YEAR:
case DAY_OF_WEEK:
- if (!isTimeSet)
+ if (! isTimeSet)
computeTime();
time += amount * (24 * 60 * 60 * 1000L);
areFieldsSet = false;
@@ -878,59 +942,57 @@ public class GregorianCalendar extends Calendar
case WEEK_OF_YEAR:
case WEEK_OF_MONTH:
case DAY_OF_WEEK_IN_MONTH:
- if (!isTimeSet)
+ if (! isTimeSet)
computeTime();
time += amount * (7 * 24 * 60 * 60 * 1000L);
areFieldsSet = false;
break;
case AM_PM:
- if (!isTimeSet)
+ if (! isTimeSet)
computeTime();
time += amount * (12 * 60 * 60 * 1000L);
areFieldsSet = false;
break;
case HOUR:
case HOUR_OF_DAY:
- if (!isTimeSet)
+ if (! isTimeSet)
computeTime();
time += amount * (60 * 60 * 1000L);
areFieldsSet = false;
break;
case MINUTE:
- if (!isTimeSet)
+ if (! isTimeSet)
computeTime();
time += amount * (60 * 1000L);
areFieldsSet = false;
break;
case SECOND:
- if (!isTimeSet)
+ if (! isTimeSet)
computeTime();
time += amount * (1000L);
areFieldsSet = false;
break;
case MILLISECOND:
- if (!isTimeSet)
+ if (! isTimeSet)
computeTime();
time += amount;
areFieldsSet = false;
break;
case ZONE_OFFSET:
- case DST_OFFSET:
- default:
+ case DST_OFFSET:default:
throw new IllegalArgumentException("Invalid or unknown field");
}
}
-
/**
* 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.
+ * the maximum for this field is reached, start over with the
+ * minimum value.
*
* <strong>Note:</strong> 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.
+ * fields must be changed, e.g rolling the month on May, 31.
+ * The date June, 31 is automatically converted to July, 1.
* This requires lenient settings.
*
* @param field the time field. One of the time field constants.
@@ -972,7 +1034,6 @@ public class GregorianCalendar extends Calendar
isSet[DAY_OF_YEAR] = false;
isSet[WEEK_OF_YEAR] = false;
break;
-
case DAY_OF_MONTH:
isSet[WEEK_OF_MONTH] = false;
isSet[DAY_OF_WEEK] = false;
@@ -981,7 +1042,6 @@ public class GregorianCalendar extends Calendar
isSet[WEEK_OF_YEAR] = false;
time += delta * (24 * 60 * 60 * 1000L);
break;
-
case WEEK_OF_MONTH:
isSet[DAY_OF_MONTH] = false;
isSet[DAY_OF_WEEK_IN_MONTH] = false;
@@ -1013,7 +1073,6 @@ public class GregorianCalendar extends Calendar
isSet[DAY_OF_YEAR] = false;
time += delta * (7 * 24 * 60 * 60 * 1000L);
break;
-
case AM_PM:
isSet[HOUR_OF_DAY] = false;
time += delta * (12 * 60 * 60 * 1000L);
@@ -1027,7 +1086,6 @@ public class GregorianCalendar extends Calendar
isSet[AM_PM] = false;
time += delta * (60 * 60 * 1000L);
break;
-
case MINUTE:
time += delta * (60 * 1000L);
break;
@@ -1047,7 +1105,7 @@ public class GregorianCalendar extends Calendar
* with the minimum value and vice versa for negative amounts.
*
* <strong>Note:</strong> There may be situation, where the other
- * fields must be changed, e.g rolling the month on May, 31.
+ * fields must be changed, e.g rolling the month on May, 31.
* The date June, 31 is automatically corrected to June, 30.
*
* @param field the time field. One of the time field constants.
@@ -1084,16 +1142,23 @@ public class GregorianCalendar extends Calendar
/**
* The minimum values for the calendar fields.
*/
- private static final int[] minimums =
- { BC, 1, 0, 0, 1, 1, 1, SUNDAY, 1,
- AM, 1, 0, 1, 1, 1, -(12*60*60*1000), 0 };
+ private static final int[] minimums =
+ {
+ BC, 1, 0, 0, 1, 1, 1, SUNDAY, 1, AM,
+ 1, 0, 0, 0, 0, -(12 * 60 * 60 * 1000),
+ 0
+ };
/**
* The maximum values for the calendar fields.
*/
- private static final int[] maximums =
- { AD, 5000000, 11, 53, 5, 31, 366, SATURDAY, 5,
- PM, 12, 23, 59, 59, 999, +(12*60*60*1000), (12*60*60*1000) };
+ private static final int[] maximums =
+ {
+ AD, 5000000, 11, 53, 5, 31, 366,
+ SATURDAY, 5, PM, 12, 23, 59, 59, 999,
+ +(12 * 60 * 60 * 1000),
+ (12 * 60 * 60 * 1000)
+ };
/**
* Gets the smallest value that is allowed for the specified field.
@@ -1117,7 +1182,6 @@ public class GregorianCalendar extends Calendar
return maximums[field];
}
-
/**
* Gets the greatest minimum value that is allowed for the specified field.
* This is the largest value returned by the <code>getActualMinimum(int)</code>
@@ -1142,7 +1206,7 @@ public class GregorianCalendar extends Calendar
* 28 days).
*
* @param field the time field. One of the time field constants.
- * @return the least maximum value.
+ * @return the least maximum value.
* @see #getActualMaximum(int)
* @since 1.2
*/
@@ -1182,7 +1246,7 @@ public class GregorianCalendar extends Calendar
int min = getMinimalDaysInFirstWeek();
if (min == 0)
return 1;
- if (!areFieldsSet || !isSet[ERA] || !isSet[YEAR])
+ if (! areFieldsSet || ! isSet[ERA] || ! isSet[YEAR])
complete();
int year = fields[ERA] == AD ? fields[YEAR] : 1 - fields[YEAR];
@@ -1203,45 +1267,46 @@ public class GregorianCalendar extends Calendar
* 29, rather than 28.
*
* @param field the time field. One of the time field constants.
- * @return the actual maximum value.
+ * @return the actual maximum value.
*/
public int getActualMaximum(int field)
{
switch (field)
{
case WEEK_OF_YEAR:
- {
- if (!areFieldsSet || !isSet[ERA] || !isSet[YEAR])
+ {
+ if (! areFieldsSet || ! isSet[ERA] || ! isSet[YEAR])
complete();
+
// This is wrong for the year that contains the gregorian change.
// I.e it gives the weeks in the julian year or in the gregorian
// year in that case.
int year = fields[ERA] == AD ? fields[YEAR] : 1 - fields[YEAR];
int lastDay = isLeapYear(year) ? 366 : 365;
int weekday = getWeekDay(year, lastDay);
- int week = (lastDay + 6
- - (7 + weekday - getFirstDayOfWeek()) % 7) / 7;
+ int week = (lastDay + 6 - (7 + weekday - getFirstDayOfWeek()) % 7) / 7;
int minimalDays = getMinimalDaysInFirstWeek();
int firstWeekday = getWeekDay(year, minimalDays);
- /*
+ /*
* Is there a set of days at the beginning of the year, before the
* first day of the week, equal to or greater than the minimum number
* of days required in the first week?
*/
if (minimalDays - (7 + firstWeekday - getFirstDayOfWeek()) % 7 < 1)
return week + 1; /* Add week 1: firstWeekday through to firstDayOfWeek */
- }
- case DAY_OF_MONTH:
- {
- if (!areFieldsSet || !isSet[MONTH])
+ }
+ case DAY_OF_MONTH:
+ {
+ if (! areFieldsSet || ! isSet[MONTH])
complete();
int month = fields[MONTH];
+
// If you change this, you should also change
// SimpleTimeZone.getDaysInMonth();
if (month == FEBRUARY)
{
- if (!isSet[YEAR] || !isSet[ERA])
+ if (! isSet[YEAR] || ! isSet[ERA])
complete();
int year = fields[ERA] == AD ? fields[YEAR] : 1 - fields[YEAR];
return isLeapYear(year) ? 29 : 28;
@@ -1250,33 +1315,31 @@ public class GregorianCalendar extends Calendar
return 31 - (month & 1);
else
return 30 + (month & 1);
- }
+ }
case DAY_OF_YEAR:
- {
- if (!areFieldsSet || !isSet[ERA] || !isSet[YEAR])
+ {
+ if (! areFieldsSet || ! isSet[ERA] || ! isSet[YEAR])
complete();
int year = fields[ERA] == AD ? fields[YEAR] : 1 - fields[YEAR];
return isLeapYear(year) ? 366 : 365;
- }
+ }
case DAY_OF_WEEK_IN_MONTH:
- {
+ {
// This is wrong for the month that contains the gregorian change.
int daysInMonth = getActualMaximum(DAY_OF_MONTH);
+
// That's black magic, I know
return (daysInMonth - (fields[DAY_OF_MONTH] - 1) % 7 + 6) / 7;
- }
+ }
case WEEK_OF_MONTH:
- {
+ {
int daysInMonth = getActualMaximum(DAY_OF_MONTH);
int weekday = (daysInMonth - fields[DAY_OF_MONTH]
- + fields[DAY_OF_WEEK] - SUNDAY) % 7 + SUNDAY;
- return (daysInMonth + 6
- - (7 + weekday - getFirstDayOfWeek()) % 7) / 7;
- }
+ + fields[DAY_OF_WEEK] - SUNDAY) % 7 + SUNDAY;
+ return (daysInMonth + 6 - (7 + weekday - getFirstDayOfWeek()) % 7) / 7;
+ }
default:
return maximums[field];
}
}
-
-
}
diff --git a/libjava/java/util/SimpleTimeZone.java b/libjava/java/util/SimpleTimeZone.java
index 7d0e201..e50d92f 100644
--- a/libjava/java/util/SimpleTimeZone.java
+++ b/libjava/java/util/SimpleTimeZone.java
@@ -38,6 +38,7 @@ exception statement from your version. */
package java.util;
+
/**
* This class represents a simple time zone offset and handles
* daylight savings. It can only handle one daylight savings rule, so
@@ -49,14 +50,14 @@ package java.util;
* lying in the AD era.
*
* @see Calendar
- * @see GregorianCalender
+ * @see GregorianCalender
* @author Jochen Hoenicke
*/
public class SimpleTimeZone extends TimeZone
{
/**
* The raw time zone offset in milliseconds to GMT, ignoring
- * daylight savings.
+ * daylight savings.
* @serial
*/
private int rawOffset;
@@ -70,23 +71,22 @@ public class SimpleTimeZone extends TimeZone
/**
* The daylight savings offset. This is a positive offset in
* milliseconds with respect to standard time. Typically this
- * is one hour, but for some time zones this may be half an hour.
+ * is one hour, but for some time zones this may be half an our.
* @serial
* @since JDK1.1.4
*/
private int dstSavings = 60 * 60 * 1000;
/**
- * The first year, in which daylight savings rules applies.
+ * The first year, in which daylight savings rules applies.
* @serial
*/
private int startYear;
-
private static final int DOM_MODE = 1;
private static final int DOW_IN_MONTH_MODE = 2;
private static final int DOW_GE_DOM_MODE = 3;
private static final int DOW_LE_DOM_MODE = 4;
-
+
/**
* The mode of the start rule. This takes one of the following values:
* <dl>
@@ -119,7 +119,7 @@ public class SimpleTimeZone extends TimeZone
/**
* The month in which daylight savings start. This is one of the
- * constants Calendar.JANUARY, ..., Calendar.DECEMBER.
+ * constants Calendar.JANUARY, ..., Calendar.DECEMBER.
* @serial
*/
private int startMonth;
@@ -128,21 +128,21 @@ public class SimpleTimeZone extends TimeZone
* This variable can have different meanings. See startMode for details
* @see #startMode;
* @serial
- */
+ */
private int startDay;
-
+
/**
- * This variable specifies the day of week the change takes place. If
+ * This variable specifies the day of week the change takes place. If
* startMode == DOM_MODE, this is undefined.
* @serial
* @see #startMode;
- */
+ */
private int startDayOfWeek;
-
+
/**
* This variable specifies the time of change to daylight savings.
* This time is given in milliseconds after midnight local
- * standard time.
+ * standard time.
* @serial
*/
private int startTime;
@@ -157,9 +157,9 @@ public class SimpleTimeZone extends TimeZone
/**
* The month in which daylight savings ends. This is one of the
- * constants Calendar.JANUARY, ..., Calendar.DECEMBER.
+ * constants Calendar.JANUARY, ..., Calendar.DECEMBER.
* @serial
- */
+ */
private int endMonth;
/**
@@ -167,7 +167,7 @@ public class SimpleTimeZone extends TimeZone
* It can take the same values as startMode.
* @serial
* @see #startMode
- */
+ */
private int endMode;
/**
@@ -176,19 +176,19 @@ public class SimpleTimeZone extends TimeZone
* @see #startMode;
*/
private int endDay;
-
+
/**
- * This variable specifies the day of week the change takes place. If
+ * This variable specifies the day of week the change takes place. If
* endMode == DOM_MODE, this is undefined.
* @serial
* @see #startMode;
*/
private int endDayOfWeek;
-
+
/**
* This variable specifies the time of change back to standard time.
* This time is given in milliseconds after midnight local
- * standard time.
+ * standard time.
* @serial
*/
private int endTime;
@@ -210,8 +210,11 @@ public class SimpleTimeZone extends TimeZone
* @serial
*/
private byte[] monthLength = monthArr;
- private static final byte[] monthArr =
- {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
+ private static final byte[] monthArr =
+ {
+ 31, 28, 31, 30, 31, 30, 31, 31, 30,
+ 31, 30, 31
+ };
/**
* The version of the serialized data on the stream.
@@ -232,10 +235,9 @@ public class SimpleTimeZone extends TimeZone
* When streaming out this class it is always written in the latest
* version.
* @serial
- * @since JDK1.1.4
+ * @since JDK1.1.4
*/
private int serialVersionOnStream = 2;
-
private static final long serialVersionUID = -403250971215465050L;
/**
@@ -257,9 +259,9 @@ public class SimpleTimeZone extends TimeZone
/**
* Create a <code>SimpleTimeZone</code> with the given time offset
- * from GMT and without daylight savings.
+ * from GMT and without daylight savings.
* @param rawOffset the time offset from GMT in milliseconds.
- * @param id The identifier of this time zone.
+ * @param id The identifier of this time zone.
*/
public SimpleTimeZone(int rawOffset, String id)
{
@@ -273,7 +275,7 @@ public class SimpleTimeZone extends TimeZone
* Create a <code>SimpleTimeZone</code> with the given time offset
* from GMT and with daylight savings. The start/end parameters
* can have different meaning (replace WEEKDAY with a real day of
- * week). Only the first two meanings were supported by earlier
+ * week). Only the first two meanings were supported by earlier
* versions of jdk.
*
* <dl>
@@ -296,12 +298,12 @@ public class SimpleTimeZone extends TimeZone
* must make sure that this day lies in the same month. </dd>
* </dl>
*
- * If you give a non existing month, a day that is zero, or too big,
+ * If you give a non existing month, a day that is zero, or too big,
* or a dayOfWeek that is too big, the result is undefined.
*
* The start rule must have a different month than the end rule.
* This restriction shouldn't hurt for all possible time zones.
- *
+ *
* @param rawOffset The time offset from GMT in milliseconds.
* @param id The identifier of this time zone.
* @param startMonth The start month of daylight savings; use the
@@ -312,29 +314,26 @@ public class SimpleTimeZone extends TimeZone
* @param startTime A time in millis in standard time.
* @param endMonth The end month of daylight savings; use the
* constants in Calendar.
- * @param endday A day in month or a day of week number, as
+ * @param endday A day in month or a day of week number, as
* described above.
* @param endDayOfWeek The end rule day of week; see above.
* @param endTime A time in millis in standard time.
* @throws IllegalArgumentException if parameters are invalid or out of
* range.
*/
- public SimpleTimeZone(int rawOffset, String id,
- int startMonth, int startDayOfWeekInMonth,
- int startDayOfWeek, int startTime,
- int endMonth, int endDayOfWeekInMonth,
- int endDayOfWeek, int endTime)
+ public SimpleTimeZone(int rawOffset, String id, int startMonth,
+ int startDayOfWeekInMonth, int startDayOfWeek,
+ int startTime, int endMonth, int endDayOfWeekInMonth,
+ int endDayOfWeek, int endTime)
{
this.rawOffset = rawOffset;
setID(id);
useDaylight = true;
- setStartRule(startMonth, startDayOfWeekInMonth,
- startDayOfWeek, startTime);
+ setStartRule(startMonth, startDayOfWeekInMonth, startDayOfWeek, startTime);
setEndRule(endMonth, endDayOfWeekInMonth, endDayOfWeek, endTime);
if (startMonth == endMonth)
- throw new IllegalArgumentException
- ("startMonth and endMonth must be different");
+ throw new IllegalArgumentException("startMonth and endMonth must be different");
this.startYear = 0;
}
@@ -347,15 +346,13 @@ public class SimpleTimeZone extends TimeZone
* time in milliseconds. This must be positive.
* @since 1.2
*/
- public SimpleTimeZone(int rawOffset, String id,
- int startMonth, int startDayOfWeekInMonth,
- int startDayOfWeek, int startTime,
- int endMonth, int endDayOfWeekInMonth,
- int endDayOfWeek, int endTime, int dstSavings)
+ public SimpleTimeZone(int rawOffset, String id, int startMonth,
+ int startDayOfWeekInMonth, int startDayOfWeek,
+ int startTime, int endMonth, int endDayOfWeekInMonth,
+ int endDayOfWeek, int endTime, int dstSavings)
{
- this(rawOffset, id,
- startMonth, startDayOfWeekInMonth, startDayOfWeek, startTime,
- endMonth, endDayOfWeekInMonth, endDayOfWeek, endTime);
+ this(rawOffset, id, startMonth, startDayOfWeekInMonth, startDayOfWeek,
+ startTime, endMonth, endDayOfWeekInMonth, endDayOfWeek, endTime);
this.dstSavings = dstSavings;
}
@@ -376,12 +373,11 @@ public class SimpleTimeZone extends TimeZone
* range.
* @since 1.4
*/
- public SimpleTimeZone(int rawOffset, String id,
- int startMonth, int startDayOfWeekInMonth,
- int startDayOfWeek, int startTime, int startTimeMode,
- int endMonth, int endDayOfWeekInMonth,
- int endDayOfWeek, int endTime, int endTimeMode,
- int dstSavings)
+ public SimpleTimeZone(int rawOffset, String id, int startMonth,
+ int startDayOfWeekInMonth, int startDayOfWeek,
+ int startTime, int startTimeMode, int endMonth,
+ int endDayOfWeekInMonth, int endDayOfWeek,
+ int endTime, int endTimeMode, int dstSavings)
{
this.rawOffset = rawOffset;
setID(id);
@@ -394,12 +390,10 @@ public class SimpleTimeZone extends TimeZone
this.startTimeMode = startTimeMode;
this.endTimeMode = endTimeMode;
- setStartRule(startMonth, startDayOfWeekInMonth,
- startDayOfWeek, startTime);
+ setStartRule(startMonth, startDayOfWeekInMonth, startDayOfWeek, startTime);
setEndRule(endMonth, endDayOfWeekInMonth, endDayOfWeek, endTime);
if (startMonth == endMonth)
- throw new IllegalArgumentException
- ("startMonth and endMonth must be different");
+ throw new IllegalArgumentException("startMonth and endMonth must be different");
this.startYear = 0;
this.dstSavings = dstSavings;
@@ -432,6 +426,7 @@ public class SimpleTimeZone extends TimeZone
{
if (month < 0 || month > 11)
throw new IllegalArgumentException("month out of range");
+
int daysInMonth = getDaysInMonth(month, 1);
if (dayOfWeek == 0)
{
@@ -460,7 +455,6 @@ public class SimpleTimeZone extends TimeZone
}
}
-
/**
* Sets the daylight savings start rule. You must also set the
* end rule with <code>setEndRule</code> or the result of
@@ -514,14 +508,16 @@ public class SimpleTimeZone extends TimeZone
* @since 1.2
* @see SimpleTimeZone
*/
- public void setStartRule(int month, int day, int dayOfWeek, int time, boolean after)
+ public void setStartRule(int month, int day, int dayOfWeek, int time,
+ boolean after)
{
// FIXME: XXX: Validate that checkRule and offset processing work with on
// or before mode.
this.startDay = after ? Math.abs(day) : -Math.abs(day);
this.startDayOfWeek = after ? Math.abs(dayOfWeek) : -Math.abs(dayOfWeek);
- this.startMode = (dayOfWeek != 0) ? (after ? DOW_GE_DOM_MODE : DOW_LE_DOM_MODE)
- : checkRule(month, day, dayOfWeek);
+ this.startMode = (dayOfWeek != 0)
+ ? (after ? DOW_GE_DOM_MODE : DOW_LE_DOM_MODE)
+ : checkRule(month, day, dayOfWeek);
this.startDay = Math.abs(this.startDay);
this.startDayOfWeek = Math.abs(this.startDayOfWeek);
@@ -591,7 +587,7 @@ public class SimpleTimeZone extends TimeZone
*
* Note that this API isn't incredibly well specified. It appears that the
* after flag must override the parameters, since normally, the day and
- * dayofweek can select this. I.e., if day &lt; 0 and dayOfWeek &lt; 0, on or
+ * dayofweek can select this. I.e., if day < 0 and dayOfWeek < 0, on or
* before mode is chosen. But if after == true, this implementation
* overrides the signs of the other arguments. And if dayOfWeek == 0, it
* falls back to the behavior in the other APIs. I guess this should be
@@ -606,14 +602,16 @@ public class SimpleTimeZone extends TimeZone
* @since 1.2
* @see #setStartRule
*/
- public void setEndRule(int month, int day, int dayOfWeek, int time, boolean after)
+ public void setEndRule(int month, int day, int dayOfWeek, int time,
+ boolean after)
{
// FIXME: XXX: Validate that checkRule and offset processing work with on
// or before mode.
this.endDay = after ? Math.abs(day) : -Math.abs(day);
this.endDayOfWeek = after ? Math.abs(dayOfWeek) : -Math.abs(dayOfWeek);
- this.endMode = (dayOfWeek != 0) ? (after ? DOW_GE_DOM_MODE : DOW_LE_DOM_MODE)
- : checkRule(month, day, dayOfWeek);
+ this.endMode = (dayOfWeek != 0)
+ ? (after ? DOW_GE_DOM_MODE : DOW_LE_DOM_MODE)
+ : checkRule(month, day, dayOfWeek);
this.endDay = Math.abs(this.endDay);
this.endDayOfWeek = Math.abs(endDayOfWeek);
@@ -648,7 +646,7 @@ public class SimpleTimeZone extends TimeZone
}
/**
- * Gets the time zone offset, for current date, modified in case of
+ * Gets the time zone offset, for current date, modified in case of
* daylight savings. This is the offset to add to UTC to get the local
* time.
*
@@ -674,8 +672,8 @@ public class SimpleTimeZone extends TimeZone
* @return the time zone offset in milliseconds.
* @throws IllegalArgumentException if arguments are incorrect.
*/
- public int getOffset(int era, int year, int month,
- int day, int dayOfWeek, int millis)
+ public int getOffset(int era, int year, int month, int day, int dayOfWeek,
+ int millis)
{
int daysInMonth = getDaysInMonth(month, year);
if (day < 1 || day > daysInMonth)
@@ -683,7 +681,7 @@ public class SimpleTimeZone extends TimeZone
if (dayOfWeek < Calendar.SUNDAY || dayOfWeek > Calendar.SATURDAY)
throw new IllegalArgumentException("dayOfWeek out of range");
if (month < Calendar.JANUARY || month > Calendar.DECEMBER)
- throw new IllegalArgumentException("month out of range");
+ throw new IllegalArgumentException("month out of range:" + month);
// This method is called by Calendar, so we mustn't use that class.
int daylightSavings = 0;
@@ -691,27 +689,22 @@ public class SimpleTimeZone extends TimeZone
{
// This does only work for Gregorian calendars :-(
// This is mainly because setStartYear doesn't take an era.
-
- boolean afterStart = !isBefore(year, month, day, dayOfWeek, millis,
- startMode, startMonth,
- startDay, startDayOfWeek, startTime);
+ boolean afterStart = ! isBefore(year, month, day, dayOfWeek, millis,
+ startMode, startMonth, startDay,
+ startDayOfWeek, startTime);
boolean beforeEnd = isBefore(year, month, day, dayOfWeek,
millis + dstSavings,
- endMode, endMonth,
- endDay, endDayOfWeek, endTime);
+ endMode, endMonth, endDay, endDayOfWeek,
+ endTime);
if (startMonth < endMonth)
- {
- // use daylight savings, if the date is after the start of
- // savings, and before the end of savings.
- daylightSavings = afterStart && beforeEnd ? dstSavings : 0;
- }
+ // use daylight savings, if the date is after the start of
+ // savings, and before the end of savings.
+ daylightSavings = afterStart && beforeEnd ? dstSavings : 0;
else
- {
- // use daylight savings, if the date is before the end of
- // savings, or after the start of savings.
- daylightSavings = beforeEnd || afterStart ? dstSavings : 0;
- }
+ // use daylight savings, if the date is before the end of
+ // savings, or after the start of savings.
+ daylightSavings = beforeEnd || afterStart ? dstSavings : 0;
}
return rawOffset + daylightSavings;
}
@@ -740,7 +733,7 @@ public class SimpleTimeZone extends TimeZone
* milliseconds with respect to standard time. Typically this
* is one hour, but for some time zones this may be half an our.
* @return the daylight savings offset in milliseconds.
- *
+ *
* @since 1.2
*/
public int getDSTSavings()
@@ -760,7 +753,7 @@ public class SimpleTimeZone extends TimeZone
{
if (dstSavings <= 0)
throw new IllegalArgumentException("illegal value for dstSavings");
-
+
this.dstSavings = dstSavings;
}
@@ -774,23 +767,28 @@ public class SimpleTimeZone extends TimeZone
}
/**
- * Returns the number of days in the given month. It does always
- * use the Gregorian leap year rule.
+ * Returns the number of days in the given month.
+ * Uses gregorian rules prior to 1582 (The default and earliest cutover)
* @param month The month, zero based; use one of the Calendar constants.
* @param year The year.
*/
private int getDaysInMonth(int month, int year)
{
- // Most of this is copied from GregorianCalendar.getActualMaximum()
if (month == Calendar.FEBRUARY)
{
- return ((year & 3) == 0 && (year % 100 != 0 || year % 400 == 0))
- ? 29 : 28;
+ if ((year & 3) != 0)
+ return 28;
+
+ // Assume default Gregorian cutover,
+ // all years prior to this must be Julian
+ if (year < 1582)
+ return 29;
+
+ // Gregorian rules
+ return ((year % 100) != 0 || (year % 400) == 0) ? 29 : 28;
}
- else if (month < Calendar.AUGUST)
- return 31 - (month & 1);
else
- return 30 + (month & 1);
+ return monthArr[month];
}
/**
@@ -804,23 +802,19 @@ public class SimpleTimeZone extends TimeZone
* @param mode the change mode; same semantic as startMode.
* @param month the change month; same semantic as startMonth.
* @param day the change day; same semantic as startDay.
- * @param dayOfWeek the change day of week;
+ * @param dayOfWeek the change day of week;
* @param millis the change time in millis since midnight standard time.
* same semantic as startDayOfWeek.
* @return true, if cal is before the change, false if cal is on
* or after the change.
*/
- private boolean isBefore(int calYear,
- int calMonth, int calDayOfMonth, int calDayOfWeek,
- int calMillis, int mode, int month,
- int day, int dayOfWeek, int millis)
+ private boolean isBefore(int calYear, int calMonth, int calDayOfMonth,
+ int calDayOfWeek, int calMillis, int mode,
+ int month, int day, int dayOfWeek, int millis)
{
-
// This method is called by Calendar, so we mustn't use that class.
// We have to do all calculations by hand.
-
// check the months:
-
// XXX - this is not correct:
// for the DOW_GE_DOM and DOW_LE_DOM modes the change date may
// be in a different month.
@@ -835,7 +829,7 @@ public class SimpleTimeZone extends TimeZone
return calDayOfMonth < day;
break;
case DOW_IN_MONTH_MODE:
- {
+ {
// This computes the day of month of the day of type
// "dayOfWeek" that lies in the same (sunday based) week as cal.
calDayOfMonth += (dayOfWeek - calDayOfWeek);
@@ -844,7 +838,6 @@ public class SimpleTimeZone extends TimeZone
// after dividing by 7). If we count from the end of the
// month, we get want a -7 based number counting the days from
// the end:
-
if (day < 0)
calDayOfMonth -= getDaysInMonth(calMonth, calYear) + 7;
else
@@ -857,9 +850,9 @@ public class SimpleTimeZone extends TimeZone
// 20 21 22 23 24 25 26 -23-22-21-20-19-18-17
// 27 28 29 30 31 32 33 -16-15-14-13-12-11-10
// 34 35 36 -9 -8 -7
-
// Now we calculate the day of week in month:
int week = calDayOfMonth / 7;
+
// day > 0 day < 0
// S M T W T F S S M T W T F S
// 1 1 1 1 1 1 -5 -5 -4 -4 -4 -4
@@ -867,7 +860,6 @@ public class SimpleTimeZone extends TimeZone
// 2 3 3 3 3 3 3 -3 -3 -3 -2 -2 -2 -2
// 3 4 4 4 4 4 4 -2 -2 -2 -1 -1 -1 -1
// 4 5 5 -1 -1 -1
-
if (week != day)
return week < day;
@@ -876,26 +868,25 @@ public class SimpleTimeZone extends TimeZone
// daylight savings starts/ends on the given day.
break;
- }
-
+ }
case DOW_LE_DOM_MODE:
// The greatest sunday before or equal December, 12
// is the same as smallest sunday after or equal December, 6.
day = Math.abs(day) - 6;
-
case DOW_GE_DOM_MODE:
-
// Calculate the day of month of the day of type
// "dayOfWeek" that lies before (or on) the given date.
- calDayOfMonth -= (calDayOfWeek < dayOfWeek ? 7 : 0)
- + calDayOfWeek - dayOfWeek;
+ calDayOfMonth -= (calDayOfWeek < dayOfWeek ? 7 : 0) + calDayOfWeek
+ - dayOfWeek;
if (calDayOfMonth < day)
return true;
if (calDayOfWeek != dayOfWeek || calDayOfMonth >= day + 7)
return false;
+
// now we have the same day
break;
}
+
// the millis decides:
return (calMillis < millis);
}
@@ -914,40 +905,35 @@ public class SimpleTimeZone extends TimeZone
/**
* Generates the hashCode for the SimpleDateFormat object. It is
* the rawOffset, possibly, if useDaylightSavings is true, xored
- * with startYear, startMonth, startDayOfWeekInMonth, ..., endTime.
+ * with startYear, startMonth, startDayOfWeekInMonth, ..., endTime.
*/
public synchronized int hashCode()
{
- return rawOffset ^
- (useDaylight ?
- startMonth ^ startDay ^ startDayOfWeek ^ startTime
- ^ endMonth ^ endDay ^ endDayOfWeek ^ endTime : 0);
+ return rawOffset
+ ^ (useDaylight
+ ? startMonth ^ startDay ^ startDayOfWeek ^ startTime ^ endMonth
+ ^ endDay ^ endDayOfWeek ^ endTime : 0);
}
public synchronized boolean equals(Object o)
{
if (this == o)
return true;
- if (!(o instanceof SimpleTimeZone))
+ if (! (o instanceof SimpleTimeZone))
return false;
SimpleTimeZone zone = (SimpleTimeZone) o;
- if (zone.hashCode() != hashCode()
- || !getID().equals(zone.getID())
- || rawOffset != zone.rawOffset || useDaylight != zone.useDaylight)
+ if (zone.hashCode() != hashCode() || ! getID().equals(zone.getID())
+ || rawOffset != zone.rawOffset || useDaylight != zone.useDaylight)
return false;
- if (!useDaylight)
+ if (! useDaylight)
return true;
- return (startYear == zone.startYear
- && startMonth == zone.startMonth
- && startDay == zone.startDay
- && startDayOfWeek == zone.startDayOfWeek
- && startTime == zone.startTime
- && startTimeMode == zone.startTimeMode
- && endMonth == zone.endMonth
- && endDay == zone.endDay
- && endDayOfWeek == zone.endDayOfWeek
- && endTime == zone.endTime
- && endTimeMode == zone.endTimeMode);
+ return (startYear == zone.startYear && startMonth == zone.startMonth
+ && startDay == zone.startDay
+ && startDayOfWeek == zone.startDayOfWeek
+ && startTime == zone.startTime
+ && startTimeMode == zone.startTimeMode && endMonth == zone.endMonth
+ && endDay == zone.endDay && endDayOfWeek == zone.endDayOfWeek
+ && endTime == zone.endTime && endTimeMode == zone.endTimeMode);
}
/**
@@ -962,25 +948,21 @@ public class SimpleTimeZone extends TimeZone
{
if (this == other)
return true;
- if (!(other instanceof SimpleTimeZone))
+ if (! (other instanceof SimpleTimeZone))
return false;
SimpleTimeZone zone = (SimpleTimeZone) other;
- if (zone.hashCode() != hashCode()
- || rawOffset != zone.rawOffset || useDaylight != zone.useDaylight)
+ if (zone.hashCode() != hashCode() || rawOffset != zone.rawOffset
+ || useDaylight != zone.useDaylight)
return false;
- if (!useDaylight)
+ if (! useDaylight)
return true;
- return (startYear == zone.startYear
- && startMonth == zone.startMonth
- && startDay == zone.startDay
- && startDayOfWeek == zone.startDayOfWeek
- && startTime == zone.startTime
- && startTimeMode == zone.startTimeMode
- && endMonth == zone.endMonth
- && endDay == zone.endDay
- && endDayOfWeek == zone.endDayOfWeek
- && endTime == zone.endTime
- && endTimeMode == zone.endTimeMode);
+ return (startYear == zone.startYear && startMonth == zone.startMonth
+ && startDay == zone.startDay
+ && startDayOfWeek == zone.startDayOfWeek
+ && startTime == zone.startTime
+ && startTimeMode == zone.startTimeMode && endMonth == zone.endMonth
+ && endDay == zone.endDay && endDayOfWeek == zone.endDayOfWeek
+ && endTime == zone.endTime && endTimeMode == zone.endTimeMode);
}
/**
@@ -991,26 +973,17 @@ public class SimpleTimeZone extends TimeZone
{
// the test for useDaylight is an incompatibility to jdk1.2, but
// I think this shouldn't hurt.
- return getClass().getName() + "["
- + "id=" + getID()
- + ",offset=" + rawOffset
- + ",dstSavings=" + dstSavings
- + ",useDaylight=" + useDaylight
- + (useDaylight ?
- ",startYear=" + startYear
- + ",startMode=" + startMode
- + ",startMonth=" + startMonth
- + ",startDay=" + startDay
- + ",startDayOfWeek=" + startDayOfWeek
- + ",startTime=" + startTime
- + ",startTimeMode=" + startTimeMode
- + ",endMode=" + endMode
- + ",endMonth=" + endMonth
- + ",endDay=" + endDay
- + ",endDayOfWeek=" + endDayOfWeek
- + ",endTime=" + endTime
- + ",endTimeMode=" + endTimeMode
- : "") + "]";
+ return getClass().getName() + "[" + "id=" + getID() + ",offset="
+ + rawOffset + ",dstSavings=" + dstSavings + ",useDaylight="
+ + useDaylight
+ + (useDaylight
+ ? ",startYear=" + startYear + ",startMode=" + startMode
+ + ",startMonth=" + startMonth + ",startDay=" + startDay
+ + ",startDayOfWeek=" + startDayOfWeek + ",startTime="
+ + startTime + ",startTimeMode=" + startTimeMode + ",endMode="
+ + endMode + ",endMonth=" + endMonth + ",endDay=" + endDay
+ + ",endDayOfWeek=" + endDayOfWeek + ",endTime=" + endTime
+ + ",endTimeMode=" + endTimeMode : "") + "]";
}
/**
@@ -1029,7 +1002,8 @@ public class SimpleTimeZone extends TimeZone
startMode = DOW_IN_MONTH_MODE;
startTimeMode = WALL_TIME;
endTimeMode = WALL_TIME;
- serialVersionOnStream = 2; }
+ serialVersionOnStream = 2;
+ }
else
{
int length = input.readInt();
@@ -1054,29 +1028,31 @@ public class SimpleTimeZone extends TimeZone
* <code>start/endDay(OfWeek)</code>-Fields are written in the
* DOW_IN_MONTH_MODE rule, since this was the only supported rule
* in 1.1.
- *
+ *
* In the optional section, we write first the length of an byte
* array as int and afterwards the byte array itself. The byte
* array contains in this release four elements, namely the real
* startDay, startDayOfWeek endDay, endDayOfWeek in that Order.
* These fields are needed, because for compatibility reasons only
* approximative values are written to the required section, as
- * described above.
+ * described above.
*/
private void writeObject(java.io.ObjectOutputStream output)
throws java.io.IOException
{
byte[] byteArray = new byte[]
- {
- (byte) startDay, (byte) startDayOfWeek,
- (byte) endDay, (byte) endDayOfWeek};
+ {
+ (byte) startDay, (byte) startDayOfWeek, (byte) endDay,
+ (byte) endDayOfWeek
+ };
/* calculate the approximation for JDK 1.1 */
switch (startMode)
{
case DOM_MODE:
- startDayOfWeek = Calendar.SUNDAY; // random day of week
- // fall through
+ startDayOfWeek = Calendar.SUNDAY; // random day of week
+
+ // fall through
case DOW_GE_DOM_MODE:
case DOW_LE_DOM_MODE:
startDay = (startDay + 6) / 7;
@@ -1085,7 +1061,8 @@ public class SimpleTimeZone extends TimeZone
{
case DOM_MODE:
endDayOfWeek = Calendar.SUNDAY;
- // fall through
+
+ // fall through
case DOW_GE_DOM_MODE:
case DOW_LE_DOM_MODE:
endDay = (endDay + 6) / 7;
diff --git a/libjava/java/util/TimeZone.java b/libjava/java/util/TimeZone.java
index 0685e60..7c81179 100644
--- a/libjava/java/util/TimeZone.java
+++ b/libjava/java/util/TimeZone.java
@@ -447,6 +447,7 @@ public abstract class TimeZone implements java.io.Serializable, Cloneable
Calendar.MARCH, -1, Calendar.SUNDAY, 2000 * 3600,
Calendar.OCTOBER, -1, Calendar.SUNDAY, 2000 * 3600);
timezones0.put("CET", tz);
+ timezones0.put("CEST", tz);
timezones0.put("ECT", tz);
timezones0.put("MET", tz);
timezones0.put("Africa/Ceuta", tz);