Calendar/Date/TimeZone/Text merge

Mark Wielaard mark@klomp.org
Mon Feb 21 03:09:00 GMT 2005


Hi,

I believe we have a nice patch now. It doesn't import all the
LocaleInformation classes or StringBuilder from GNU Classpath. 

2005-02-20  Mark Wielaard  <mark@klomp.org>

	* gnu/java/locale/LocaleInformation_en.java: Extend
	localPatternChars to "GyMdkHmsSEDFwWahKzYeugAZ".

2005-02-20  Mark Wielaard  <mark@klomp.org>

	* java/text/SimpleDateFormat.java
	(SimpleDateFormat(String, DateFormatSymbols)): Throw
	NullPointerException when formatData is null.

2005-02-20  Mark Wielaard  <mark@klomp.org>

	* java/util/SimpleTimeZone.java (getOffset): Calculate beforeEnd by
	taking dstSavings into account.

2005-02-20  Sven de Marothy <sven@physto.se>

	* java/text/SimpleDateFormat.java,
	(parse): Set correct DST_OFFSET to the correct value.

2005-02-20  Mark Wielaard  <mark@klomp.org>

	* java/util/SimpleTimeZone.java (checkRule): Throw
	IllegalArgumentException when month out of range.

2005-02-20  Sven de Marothy  <sven@physto.se>

	* java/util/GregorianCalendar.java,
	(add): Don't set fields directly anymore. Use set()

2005-02-20  Mark Wielaard  <mark@klomp.org>

	* java/text/SimpleDateFormat.java (CompiledField.toString):
	Use StringBuffer, not StringBuilder.
	(toString): Likewise.

2005-02-20  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-20  Sven de Marothy  <sven@physto.se>

	* java/util/Calendar.java 
	(Calendar): Constructor should clear fields.

2005-02-20  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-20  Sven de Marothy  <sven@physto.se>

	* java/util/Calendar.java
	(set) Invalidate all fields on first call to set().

2005-02-20  Sven de Marothy  <sven@physto.se>

	* java/util/GregorianCalendar.java
	(computeTime): Fixed handling of time zones.

2005-02-20  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-20  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-20  Sven de Marothy <sven@physto.se>

	* java/util/Calendar.java: Reformatted.
	* java/util/GregorianCalendar.java: Reformatted.
	* java/util/SimpleTimeZone.java: Reformatted.

2005-02-20  Sven de Marothy <sven@physto.se>

        * java/util/GregorianCalendar.java
        (GregorianCalendar): Update fields in the constructor

2005-02-20  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-20  Noa Resare  <address@hidden>

	* java/util/Calendar.java(set):
	Fix for DST related regression.

2005-02-20  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-20  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-20  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-20  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-20  Ito Kazumitsu  <kaz@maczuka.gcd.org>

	* java/text/SimpleDateFormat.java:
	(parse): Set the DST offset to 0 when parsing
	GMT offset timezones.

2005-02-20  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-20  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-20  Sven de Marothy <sven@physto.se>

	* java/text/SimpleDateFormat.java
	(parse): comparison should be case-insensitive, ignore null
	strings.

This imports all fixes from GNU Classpath, give no new regressions and
200 new PASSes on mauve. Some sample programs work fine with this patch
applied.

OK to commit?

Cheers,

Mark
-------------- next part --------------
? gnu/java/awt/peer/gtk/GtkMenuItemPeer.mark
? java/util/GregorianCalendar.java.cleaned
Index: gnu/java/locale/LocaleInformation_en.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/gnu/java/locale/LocaleInformation_en.java,v
retrieving revision 1.6
diff -u -r1.6 LocaleInformation_en.java
--- gnu/java/locale/LocaleInformation_en.java	29 Jul 2004 08:59:39 -0000	1.6
+++ gnu/java/locale/LocaleInformation_en.java	20 Feb 2005 21:06:37 -0000
@@ -159,7 +159,7 @@
     { "shortWeekdays", shortWeekdays },
     { "ampms", ampms },
     { "eras", eras },
-    { "localPatternChars", "GyMdkHmsSEDFwWahKz" },
+    { "localPatternChars", "GyMdkHmsSEDFwWahKzYeugAZ" },
     { "zoneStrings", zoneStrings },
 
     { "shortDateFormat", "M/d/yy" },         // Java's Y2K bug.
Index: java/text/DateFormat.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/text/DateFormat.java,v
retrieving revision 1.19
diff -u -r1.19 DateFormat.java
--- java/text/DateFormat.java	17 Feb 2005 07:48:41 -0000	1.19
+++ java/text/DateFormat.java	20 Feb 2005 21:06:37 -0000
@@ -70,29 +70,221 @@
 
   /* 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 @@
 	= 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
Index: java/text/SimpleDateFormat.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/text/SimpleDateFormat.java,v
retrieving revision 1.29
diff -u -r1.29 SimpleDateFormat.java
--- java/text/SimpleDateFormat.java	22 Oct 2004 17:14:25 -0000	1.29
+++ java/text/SimpleDateFormat.java	20 Feb 2005 21:06:38 -0000
@@ -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.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.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 @@
  */
 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 @@
 
     // 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 @@
     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 @@
 	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 @@
   }
   
   /**
-   * 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 @@
   }
 
   /**
-   * 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 @@
   }
 
   /**
-   * 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 @@
     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 @@
     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 String toLocalizedPattern()
   {
     String localChars = formatData.getLocalPatternChars();
-    return applyLocalizedPattern (pattern, standardChars, localChars);
+    return translateLocalizedPattern(pattern, standardChars, localChars);
   }
 
   /**
@@ -271,6 +478,8 @@
    * 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 @@
    * 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 @@
   }
 
   /**
-   * 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 @@
    * 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 @@
     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 @@
 		// 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 @@
 		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 @@
     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 @@
         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 @@
     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;
+  }
+
 }
Index: java/util/Calendar.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/util/Calendar.java,v
retrieving revision 1.25
diff -u -r1.25 Calendar.java
--- java/util/Calendar.java	22 Oct 2004 17:14:26 -0000	1.25
+++ java/util/Calendar.java	20 Feb 2005 21:06:38 -0000
@@ -51,7 +51,7 @@
  * 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 @@
  * 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 @@
  *
  * 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 @@
  * @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 @@
    * 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 @@
    * 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 @@
    * 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 @@
    * 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 @@
    * Useful constant for 12-hour clock.
    */
   public static final int AM = 0;
+
   /**
    * Useful constant for 12-hour clock.
    */
@@ -292,21 +329,25 @@
    * @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 @@
 
   /**
    * 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 @@
   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 @@
   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 @@
     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 @@
     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 @@
 	      }
 	  }
 
-        // 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 @@
 	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 @@
       {
 	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 @@
    * 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 final Date getTime()
   {
-    if (!isTimeSet)
+    if (! isTimeSet)
       computeTime();
     return new Date(time);
   }
@@ -562,7 +613,7 @@
    */
   public long getTimeInMillis()
   {
-    if (!isTimeSet)
+    if (! isTimeSet)
       computeTime();
     return time;
   }
@@ -575,9 +626,9 @@
    */
   public void setTimeInMillis(long time)
   {
+    clear();
     this.time = time;
     isTimeSet = true;
-    computeFields();
   }
 
   /**
@@ -593,14 +644,14 @@
   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 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 @@
 	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 @@
     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 @@
    * @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 @@
   {
     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 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 @@
 
   /**
    * 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 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 @@
   }
 
   /**
-   * 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 @@
   }
 
   /**
-   * 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 @@
   /**
    * 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 @@
    *
    * @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 @@
       }
   }
 
-
   /**
    * Sets the time zone to the specified value.
    * @param zone the new time zone
@@ -918,7 +1033,7 @@
 
   /**
    * 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 @@
 
   /**
    * 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 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 @@
    * 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 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 @@
    * 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 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 @@
       {
 	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 @@
       }
   }
 
-  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 @@
    * says, that it could be omitted.  */
   private void writeObject(ObjectOutputStream stream) throws IOException
   {
-    if (!isTimeSet)
+    if (! isTimeSet)
       computeTime();
     stream.defaultWriteObject();
   }
@@ -1121,7 +1237,7 @@
     throws IOException, ClassNotFoundException
   {
     stream.defaultReadObject();
-    if (!isTimeSet)
+    if (! isTimeSet)
       computeTime();
 
     if (serialVersionOnStream > 1)
@@ -1130,7 +1246,6 @@
 	// 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;
Index: java/util/GregorianCalendar.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/util/GregorianCalendar.java,v
retrieving revision 1.25
diff -u -r1.25 GregorianCalendar.java
--- java/util/GregorianCalendar.java	8 Nov 2004 23:04:34 -0000	1.25
+++ java/util/GregorianCalendar.java	20 Feb 2005 21:06:38 -0000
@@ -39,6 +39,7 @@
 
 package java.util;
 
+
 /**
  * <p>
  * This class represents the Gregorian calendar, that is used in most
@@ -46,7 +47,7 @@
  * 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 @@
    * Constant representing the era BC (Before Christ).
    */
   public static final int BC = 0;
-  
+
   /**
    * Constant representing the era AD (Anno Domini).
    */
@@ -164,43 +165,46 @@
   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.
-   *
-   * @param locale the locale in use for this calendar.
-   * @return A resource bundle for the calendar for the specified locale.
+   * 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.
+   *
+   * 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 @@
    * 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 GregorianCalendar(int year, int month, int day)
   {
-    super();
+    this(TimeZone.getDefault(), Locale.getDefault(), false);
     set(year, month, day);
   }
 
@@ -248,7 +267,7 @@
    */
   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 @@
    * @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 @@
    * </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 @@
    */
   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 @@
   }
 
   /**
-   * <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 (isSet[DAY_OF_MONTH])
-	  {
-	    return new int[]
-	    {
-	    dayOfYear + fields[DAY_OF_MONTH], 0};
-	  }
-	if (isSet[WEEK_OF_MONTH] && isSet[DAY_OF_WEEK])
-	  {
-	    // the weekday of the first day in that month is:
-	    int weekday = getWeekDay(year, ++dayOfYear);
+    if (month > 11)
+      {
+	year += (month / 12);
+	month = month % 12;
+      }
 
-	    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])
+    if (month < 0)
+      {
+	year += (int) month / 12;
+	month = month % 12;
+	if (month < 0)
 	  {
-	    // 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))};
+	    month += 12;
+	    year--;
 	  }
       }
 
-    // MONTH + something did not succeed.
-    if (isSet[DAY_OF_YEAR])
-      {
-	return new int[] {0, fields[DAY_OF_YEAR]};
-      }
-      
-    if (isSet[DAY_OF_WEEK] && isSet[WEEK_OF_YEAR])
-      {
-	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 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;
+  }
 
-    // As last resort return Jan, 1st.
-    return new int[] {1, 0};
+  /**
+   * 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.");
+      }
+
+    if (isSet[WEEK_OF_MONTH])
+      {
+	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_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 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.");
+      }
+
+    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;
-
-    if (isLenient())
-      {
-	// 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));
+    // 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 (month < 0)
+      {
+	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;
-      }
-    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);
+	year += (month / 12);
+	month = month % 12;
+      }
 
+    month_days[1] = isLeapYear(year) ? 29 : 28;
 
-    TimeZone zone = getTimeZone();
-    int rawOffset = isSet[ZONE_OFFSET]
-      ? fields[ZONE_OFFSET] : zone.getRawOffset();
+    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;
+	  }
+      }
+
+    // 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;
 
-    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;
+    // 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 @@
 	//
 	// 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 @@
    * 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 @@
 	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 @@
 	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 @@
     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 @@
     // 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 @@
     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 @@
    * 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 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 @@
 	    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 @@
       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 @@
 	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 @@
 	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 @@
 	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 @@
 	isSet[AM_PM] = false;
 	time += delta * (60 * 60 * 1000L);
 	break;
-
       case MINUTE:
 	time += delta * (60 * 1000L);
 	break;
@@ -1047,7 +1105,7 @@
    * 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 @@
   /**
    * 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 @@
     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 @@
    * 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 @@
 	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 @@
    * 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 @@
 	    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];
       }
   }
-
-
 }
Index: java/util/SimpleTimeZone.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/util/SimpleTimeZone.java,v
retrieving revision 1.15
diff -u -r1.15 SimpleTimeZone.java
--- java/util/SimpleTimeZone.java	10 Jan 2005 18:26:40 -0000	1.15
+++ java/util/SimpleTimeZone.java	20 Feb 2005 21:06:38 -0000
@@ -38,6 +38,7 @@
 
 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 @@
  * 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 @@
   /**
    * 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 @@
 
   /**
    * 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 @@
    * 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 @@
 
   /**
    * 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 @@
    * It can take the same values as startMode.
    * @serial
    * @see #startMode
-   */   
+   */
   private int endMode;
 
   /**
@@ -176,19 +176,19 @@
    * @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 @@
    * @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 @@
    * 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 @@
 
   /**
    * 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 @@
    * 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 @@
    * 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 @@
    * @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 @@
    * 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)
-  {
-    this(rawOffset, id,
-	 startMonth, startDayOfWeekInMonth, startDayOfWeek, startTime,
-	 endMonth, endDayOfWeekInMonth, endDayOfWeek, endTime);
+  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.dstSavings = dstSavings;
   }
@@ -376,12 +373,11 @@
    * 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 @@
     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 @@
   {
     if (month < 0 || month > 11)
       throw new IllegalArgumentException("month out of range");
+
     int daysInMonth = getDaysInMonth(month, 1);
     if (dayOfWeek == 0)
       {
@@ -460,7 +455,6 @@
       }
   }
 
-
   /**
    * 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 @@
    * @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 @@
    *
    * 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 < 0 and dayOfWeek < 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 @@
    * @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 @@
   }
 
   /**
-   * 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 @@
    * @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 @@
     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 @@
       {
 	// 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 @@
    * 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 @@
   {
     if (dstSavings <= 0)
       throw new IllegalArgumentException("illegal value for dstSavings");
-    
+
     this.dstSavings = dstSavings;
   }
 
@@ -774,23 +767,28 @@
   }
 
   /**
-   * 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 @@
    * @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 @@
 	  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 @@
 	  // 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 @@
 	  // 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 @@
 	  //  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 @@
 
 	  // 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 @@
   /**
    * 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 @@
   {
     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 @@
   {
     // 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 @@
 	startMode = DOW_IN_MONTH_MODE;
 	startTimeMode = WALL_TIME;
 	endTimeMode = WALL_TIME;
-	serialVersionOnStream = 2;      }
+	serialVersionOnStream = 2;
+      }
     else
       {
 	int length = input.readInt();
@@ -1054,29 +1028,31 @@
    * <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 @@
       {
       case DOM_MODE:
 	endDayOfWeek = Calendar.SUNDAY;
-	// fall through
+
+      // fall through
       case DOW_GE_DOM_MODE:
       case DOW_LE_DOM_MODE:
 	endDay = (endDay + 6) / 7;
Index: java/util/TimeZone.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/util/TimeZone.java,v
retrieving revision 1.22
diff -u -r1.22 TimeZone.java
--- java/util/TimeZone.java	10 Jan 2005 18:26:40 -0000	1.22
+++ java/util/TimeZone.java	20 Feb 2005 21:06:38 -0000
@@ -447,6 +447,7 @@
 	   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);
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 189 bytes
Desc: This is a digitally signed message part
URL: <http://gcc.gnu.org/pipermail/java-patches/attachments/20050221/6e638ef4/attachment.sig>


More information about the Java-patches mailing list