This is the mail archive of the java-patches@sources.redhat.com mailing list for the Java project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

PATCH: Serialization Mods


Folks,
I forgot to send this out on Friday.  My apologies.

Note that Bryce has updated java/util/BitSet.java since this was
checked in.
--warrenl



2000-10-27  Warren Levy  <warrenl@cygnus.com>

	* java/util/natGregorianCalendar.cc (computeFields): Set the isSet__
	array elements to true.

2000-10-27  Warren Levy  <warrenl@cygnus.com>

	* Makefile.am: Added locale files from Classpath.
	* Makefile.in: Rebuilt.
	* gnu/java/locale/Calendar.java: New file.
	* gnu/java/locale/Calendar_de.java: New file.
	* gnu/java/locale/Calendar_en.java: New file.
	* gnu/java/locale/Calendar_nl.java: New file.
	* java/lang/ClassNotFoundException.java: Replaced with Classpath file.
	* java/math/BigDecimal.java (intVal): Renamed from 'num' for
	serialization compatibility.
	(scale): Made private.
	(serialVersionUID): New field.
	* java/math/BigInteger.java (ival): Made transient.
	(words): Made transient.
	(bitCount): New serialization field.
	(bitLength): Ditto.
	(firstNonzeroByteNum): Ditto.
	(lowestSetBit): Ditto.
	(magnitude): Ditto.
	(signum): Ditto.
	(serialVersionUID): New field.
	(readObject): New method.
	(writeObject): New method.
	* java/util/BitSet.java (serialVersionUID): New field.
	* java/util/Calendar.java: Replaced with Classpath file.
	* java/util/GregorianCalendar.java (GregorianCalendar): Pass result
	of getDefault() for TimeZone or Locale instead of passing nulls.
	* java/util/Locale.java (serialVersionUID): New field.
	(writeObject): New method.
	(readObject): New method.
	* java/util/SimpleTimeZone.java: Replaced with Classpath file.


Index: Makefile.am
===================================================================
RCS file: /cvs/java/libgcj/libjava/Makefile.am,v
retrieving revision 1.96
retrieving revision 1.97
diff -u -p -r1.96 -r1.97
--- Makefile.am	2000/10/25 22:11:37	1.96
+++ Makefile.am	2000/10/27 10:33:46	1.97
@@ -998,6 +998,10 @@ gnu/java/io/ObjectIdentityWrapper.java \
 gnu/java/lang/ArrayHelper.java \
 gnu/java/lang/ClassHelper.java \
 gnu/java/lang/reflect/TypeSignature.java \
+gnu/java/locale/Calendar.java \
+gnu/java/locale/Calendar_de.java \
+gnu/java/locale/Calendar_en.java \
+gnu/java/locale/Calendar_nl.java \
 gnu/java/security/provider/Gnu.java \
 gnu/java/security/provider/SHA.java \
 gnu/java/security/provider/SHA1PRNG.java \
Index: Makefile.in
===================================================================
RCS file: /cvs/java/libgcj/libjava/Makefile.in,v
retrieving revision 1.104
retrieving revision 1.105
diff -u -p -r1.104 -r1.105
--- Makefile.in	2000/10/25 22:11:37	1.104
+++ Makefile.in	2000/10/27 10:33:46	1.105
@@ -742,6 +742,10 @@ gnu/java/io/ObjectIdentityWrapper.java \
 gnu/java/lang/ArrayHelper.java \
 gnu/java/lang/ClassHelper.java \
 gnu/java/lang/reflect/TypeSignature.java \
+gnu/java/locale/Calendar.java \
+gnu/java/locale/Calendar_de.java \
+gnu/java/locale/Calendar_en.java \
+gnu/java/locale/Calendar_nl.java \
 gnu/java/security/provider/Gnu.java \
 gnu/java/security/provider/SHA.java \
 gnu/java/security/provider/SHA1PRNG.java \
@@ -1256,6 +1260,8 @@ DEP_FILES =  .deps/$(srcdir)/$(CONVERT_D
 .deps/gnu/java/io/ObjectIdentityWrapper.P \
 .deps/gnu/java/lang/ArrayHelper.P .deps/gnu/java/lang/ClassHelper.P \
 .deps/gnu/java/lang/reflect/TypeSignature.P \
+.deps/gnu/java/locale/Calendar.P .deps/gnu/java/locale/Calendar_de.P \
+.deps/gnu/java/locale/Calendar_en.P .deps/gnu/java/locale/Calendar_nl.P \
 .deps/gnu/java/security/provider/Gnu.P \
 .deps/gnu/java/security/provider/SHA.P \
 .deps/gnu/java/security/provider/SHA1PRNG.P .deps/interpret.P \
Index: gnu/java/locale/Calendar.java
===================================================================
--- /dev/null	Tue May  5 13:32:27 1998
+++ gnu/java/locale/Calendar.java	Tue Oct 24 17:10:15 2000
@@ -0,0 +1,112 @@
+/* Calendar.java -- Default Calendar locale data
+   Copyright (C) 1999 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+ 
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+As a special exception, if you link this library with other files to
+produce an executable, this library does not by itself cause the
+resulting executable to be covered by the GNU General Public License.
+This exception does not however invalidate any other reasons why the
+executable file might be covered by the GNU General Public License. */
+
+
+package gnu.java.locale;
+
+import java.util.ListResourceBundle;
+import java.util.Locale;
+import java.util.Date;
+
+/**
+ * This class contains locale data for java.util.Calendar.<br>
+ *
+ * If you localize this to another language only set fields, that
+ * you change.  See Calendar_de for an example.  Also add your
+ * locale to this list of availableLocales below in this(!) file.
+ *
+ * @author Jochen Hoenicke
+ */
+public class Calendar extends ListResourceBundle
+{
+  /**
+   * The locales for which Calendar is localized.
+   */
+  private static final Locale[] availableLocales = {
+    Locale.GERMAN, Locale.ENGLISH, new Locale("nl", "")
+  };
+
+  /**
+   * This is the default calendar class, that is returned on
+   * java.util.Calendar.getInstance().
+   * @see java.util.Calendar#getInstance()
+   */
+  private static final String calendarClass = "java.util.GregorianCalendar";
+  
+  /**
+   * This is used by java.util.Calendar.
+   * @see java.util.Calendar#getFirstDayOfWeek()
+   */
+  private static final Integer firstDayOfWeek
+    = new Integer(java.util.Calendar.SUNDAY);
+  /**
+   * This is used by java.util.Calendar.
+   * @see java.util.Calendar#getMinimalDaysInFirstWeek()
+   */
+  private static final Integer minimalDaysInFirstWeek = new Integer(1);
+
+  /**
+   * The point at which the Gregorian calendar rules were used.
+   * The default for most catholic
+   * countries is midnight (UTC) on October 5, 1582 (Julian),
+   * or October 15, 1582 (Gregorian).
+   * @see java.util.GregorianCalendar#getGregorianCutOver
+   */
+  /* If you change this date be aware, that this formular does only 
+   * work for months from MARCH to DECEMBER and doesn't work in 
+   * leap years (look in java.util.GregorianCalendar.getDayOfYear for
+   * more info).
+   */
+  private static final Date gregorianCutOver = new Date
+  ((24*60*60*1000L) *
+   (((1582*(365*4+1))/4 + 
+     (java.util.Calendar.OCTOBER*(31+30+31+30+31) - 9) / 5 + 5) -
+    ((1970*(365*4+1))/4 + 1 - 13)));
+  
+  /**
+   * This is the object array used to hold the keys and values
+   * for this bundle
+   */
+  private static final Object[][] contents =
+  {
+    { "availableLocales", availableLocales },
+    { "calendarClass", calendarClass },
+    { "firstDayOfWeek", firstDayOfWeek },
+    { "minimalDaysInFirstWeek", minimalDaysInFirstWeek },
+    { "gregorianCutOver", gregorianCutOver }
+  };
+
+  /**
+   * This method returns the object array of key, value pairs containing
+   * the data for this bundle.
+   *
+   * @return The key, value information.
+   */
+  public Object[][] getContents()
+  {
+    return(contents);
+  }
+}
Index: gnu/java/locale/Calendar_de.java
===================================================================
--- /dev/null	Tue May  5 13:32:27 1998
+++ gnu/java/locale/Calendar_de.java	Tue Oct 24 17:10:15 2000
@@ -0,0 +1,60 @@
+/* Calendar_de.java -- German calendar locale data
+   Copyright (C) 1999 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+ 
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+As a special exception, if you link this library with other files to
+produce an executable, this library does not by itself cause the
+resulting executable to be covered by the GNU General Public License.
+This exception does not however invalidate any other reasons why the
+executable file might be covered by the GNU General Public License. */
+
+
+package gnu.java.locale;
+
+import java.util.ListResourceBundle;
+import java.util.Calendar;
+
+/**
+ * This class contains locale data for java.util.Calendar specific for 
+ * german language.
+ * @author Jochen Hoenicke
+ */
+public class Calendar_de extends ListResourceBundle
+{
+  /**
+   * This is the object array used to hold the keys and values
+   * for this bundle
+   */
+  private static final Object[][] contents =
+  {
+    { "firstDayOfWeek", new Integer(Calendar.MONDAY) },
+    { "minimalDaysInFirstWeek", new Integer(4) },
+  };
+
+  /**
+   * This method returns the object array of key, value pairs containing
+   * the data for this bundle.
+   *
+   * @return The key, value information.
+   */
+  public Object[][] getContents()
+  {
+    return contents;
+  }
+}
Index: gnu/java/locale/Calendar_en.java
===================================================================
--- /dev/null	Tue May  5 13:32:27 1998
+++ gnu/java/locale/Calendar_en.java	Tue Oct 24 17:10:15 2000
@@ -0,0 +1,59 @@
+/* Calendar_en.java -- English calendar locale data
+   Copyright (C) 1999 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+ 
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+As a special exception, if you link this library with other files to
+produce an executable, this library does not by itself cause the
+resulting executable to be covered by the GNU General Public License.
+This exception does not however invalidate any other reasons why the
+executable file might be covered by the GNU General Public License. */
+
+
+package gnu.java.locale;
+
+import java.util.ListResourceBundle;
+import java.util.Calendar;
+
+/**
+ * This class contains locale data for java.util.Calendar specific for 
+ * english language.
+ * @author Jochen Hoenicke
+ */
+public class Calendar_en extends ListResourceBundle
+{
+  /**
+   * This is the object array used to hold the keys and values
+   * for this bundle
+   */
+  private static final Object[][] contents =
+  {
+    /* Use default values. */
+  };
+
+  /**
+   * This method returns the object array of key, value pairs containing
+   * the data for this bundle.
+   *
+   * @return The key, value information.
+   */
+  public Object[][] getContents()
+  {
+    return contents;
+  }
+}
Index: gnu/java/locale/Calendar_nl.java
===================================================================
--- /dev/null	Tue May  5 13:32:27 1998
+++ gnu/java/locale/Calendar_nl.java	Tue Oct 24 17:10:15 2000
@@ -0,0 +1,63 @@
+/* Calendar_nl.java -- Dutch calendar locale data
+   Copyright (C) 1999 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+ 
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+As a special exception, if you link this library with other files to
+produce an executable, this library does not by itself cause the
+resulting executable to be covered by the GNU General Public License.
+This exception does not however invalidate any other reasons why the
+executable file might be covered by the GNU General Public License. */
+
+
+package gnu.java.locale;
+
+import java.util.ListResourceBundle;
+import java.util.Calendar;
+
+/**
+ * This class contains locale data for java.util.Calendar specific for 
+ * dutch language.
+ * @author Mark Wielaard
+ */
+public class Calendar_nl extends ListResourceBundle
+{
+  /**
+   * This is the object array used to hold the keys and values
+   * for this bundle
+   */
+  private static final Object[][] contents =
+  {
+    { "firstDayOfWeek", new Integer(Calendar.MONDAY) },
+
+    /* XXX - I guess the default for gregorianCutover 
+     * is also true for the Netherlands. But is it?
+     */
+  };
+
+  /**
+   * This method returns the object array of key, value pairs containing
+   * the data for this bundle.
+   *
+   * @return The key, value information.
+   */
+  public Object[][] getContents()
+  {
+    return contents;
+  }
+}
Index: java/lang/ClassNotFoundException.java
===================================================================
RCS file: /cvs/java/libgcj/libjava/java/lang/ClassNotFoundException.java,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -p -r1.4 -r1.5
--- ClassNotFoundException.java	2000/06/27 05:10:02	1.4
+++ ClassNotFoundException.java	2000/10/27 10:33:46	1.5
@@ -1,61 +1,164 @@
-/* Copyright (C) 1998, 1999, 2000  Free Software Foundation
+/* ClassNotFoundException.java -- exception thrown when attempting to load
+   a class when no definition for the class can be found.
+   Copyright (C) 1998 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+ 
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+As a special exception, if you link this library with other files to
+produce an executable, this library does not by itself cause the
+resulting executable to be covered by the GNU General Public License.
+This exception does not however invalidate any other reasons why the
+executable file might be covered by the GNU General Public License. */
 
-   This file is part of libgcj.
 
-This software is copyrighted work licensed under the terms of the
-Libgcj License.  Please consult the file "LIBGCJ_LICENSE" for
-details.  */
- 
 package java.lang;
- 
+
+import java.io.ObjectOutputStream;
+import java.io.ObjectInputStream;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.io.PrintWriter;
+
 /**
- * @author Warren Levy <warrenl@cygnus.com>
- * @date September 18, 1998.  
- */
-/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3
- * "The Java Language Specification", ISBN 0-201-63451-1
- * plus online API docs for JDK 1.2 beta from http://www.javasoft.com.
- * Status:  Believed complete and correct.
+ * Exceptions may be thrown by one part of a Java program and caught
+ * by another in order to deal with exceptional conditions.  This 
+ * exception can by thrown by specific methods of <code>ClassLoader</code>
+ * and <code>Class</code> when attempting to load a class when no definition
+ * for the specified class can be found.
+ *
+ * @since JDK 1.0
+ * 
+ * @author Brian Jones
  */
- 
 public class ClassNotFoundException extends Exception
 {
-  // TODO12:
-  // Throwable ex;
+  static final long serialVersionUID = 9176873029745254542L;
 
+  private Throwable ex = null;
+  
+  /**
+   * Create an exception without a message.
+   */
   public ClassNotFoundException()
-  {
-    super();
-  }
-
-  // TODO12:
-  // public ClassNotFoundException(String msg, Throwable ex)
-  // {
-  //   FIXME: Set 'ex' here.
-  // }
-
-  public ClassNotFoundException(String msg)
-  {
-    super(msg);
-  }
-
-  // TODO12:
-  // public Throwable getException()
-  // {
-  // }
-
-  // TBD: if this needs to be implemented
-  // public void printStackTrace()
-  // {
-  // }
-
-  // TBD: if this needs to be implemented
-  // public void printStackTrace(PrintStream ps)
-  // {
-  // }
-
-  // TBD: if this needs to be implemented
-  // public void printStackTrace(PrintWriter pw)
-  // {
-  // }
+    {
+      super();
+    }
+
+  /**
+   * Create an exception with a message.
+   */
+  public ClassNotFoundException(String s)
+    {
+      super(s);
+    }
+
+  /**
+   * Create an exception with a message and include the exception 
+   * which occurred while loading the class.
+   *
+   * @param ex the exception which occurred while loading the class
+   *
+   * @since JDK 1.2
+   */
+  public ClassNotFoundException(String s, Throwable ex)
+    {
+      super(s);
+      this.ex = ex;
+    }
+
+  /**
+   * Returns the exception which occurred while loading the class, 
+   * otherwise returns null.
+   * 
+   * @since JDK 1.2
+   */
+  public Throwable getException()
+    {
+      return ex;
+    }
+
+  /**
+   * Print a stack trace of the exception that occurred.
+   */
+  public void printStackTrace()
+    {
+      if (ex == null)
+        {
+          super.printStackTrace();
+        }
+      else
+        {
+          ex.printStackTrace();
+        }
+    }
+
+  /**
+   * Print a stack trace of the exception that occurred to 
+   * the specified <code>PrintStream</code>.
+   */
+  public void printStackTrace(PrintStream ps)
+    {
+      if (ex == null)
+        {
+          super.printStackTrace(ps);
+        }
+      else
+        {
+          ex.printStackTrace(ps);
+        }
+    }
+
+  /**
+   * Print a stack trace of the exception that occurred to 
+   * the specified <code>PrintWriter</code>.
+   */
+  public void printStackTrace(PrintWriter pw)
+    {
+      if (ex == null)
+        {
+          super.printStackTrace(pw);
+        }
+      else
+        {
+          ex.printStackTrace(pw);
+        }
+    }
+
+  /**
+   * Serialize the object in a manner binary compatible with the JDK 1.2
+   */
+  private void writeObject(java.io.ObjectOutputStream s) 
+    throws IOException
+    {
+      ObjectOutputStream.PutField oFields;
+      oFields = s.putFields();
+      oFields.put("ex", this.ex);
+      s.writeFields(); 
+    }
+
+  /**
+   * Deserialize the object in a manner binary compatible with the JDK 1.2
+   */    
+  private void readObject(java.io.ObjectInputStream s)
+    throws IOException, ClassNotFoundException
+    {
+      ObjectInputStream.GetField oFields;
+      oFields = s.readFields();
+      ex = (Throwable)oFields.get("ex", (Throwable)null);
+    }
 }
Index: java/math/BigDecimal.java
===================================================================
RCS file: /cvs/java/libgcj/libjava/java/math/BigDecimal.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -p -r1.1 -r1.2
--- BigDecimal.java	2000/04/11 09:21:53	1.1
+++ BigDecimal.java	2000/10/27 10:33:46	1.2
@@ -29,8 +29,9 @@ package java.math;
 import java.math.BigInteger;
 
 public class BigDecimal extends Number implements Comparable {
-  BigInteger num;
-  int scale;
+  private BigInteger intVal;
+  private int scale;
+  private static final long serialVersionUID = 6108874887143696463L;
 
   private final static BigDecimal ZERO = 
     new BigDecimal (BigInteger.valueOf (0), 0);
@@ -56,7 +57,7 @@ public class BigDecimal extends Number i
   {
     if (scale < 0) 
       throw new NumberFormatException ("scale of " + scale + " is < 0");
-    this.num = num;
+    this.intVal = num;
     this.scale = scale;
   }
 
@@ -68,7 +69,7 @@ public class BigDecimal extends Number i
   public BigDecimal (String num) throws NumberFormatException 
   {
     int point = num.indexOf('.');
-    this.num = new BigInteger (point == -1 ? num :
+    this.intVal = new BigInteger (point == -1 ? num :
 			       num.substring (0, point) + 
 			       num.substring (point + 1));
     scale = num.length() - (point == -1 ? num.length () : point + 1);
@@ -99,8 +100,8 @@ public class BigDecimal extends Number i
     // For addition, need to line up decimals.  Note that the movePointRight
     // method cannot be used for this as it might return a BigDecimal with
     // scale == 0 instead of the scale we need.
-    BigInteger op1 = num;
-    BigInteger op2 = val.num;
+    BigInteger op1 = intVal;
+    BigInteger op2 = val.intVal;
     if (scale < val.scale)
       op1 = op1.multiply (BigInteger.valueOf (10).pow (val.scale - scale));
     else if (scale > val.scale)
@@ -116,7 +117,7 @@ public class BigDecimal extends Number i
 
   public BigDecimal multiply (BigDecimal val) 
   {
-    return new BigDecimal (num.multiply (val.num), scale + val.scale);
+    return new BigDecimal (intVal.multiply (val.intVal), scale + val.scale);
   }
 
   public BigDecimal divide (BigDecimal val, int roundingMode) 
@@ -135,13 +136,13 @@ public class BigDecimal extends Number i
     if (scale < 0)
       throw new ArithmeticException ("scale is negative: " + scale);
 
-    if (num.signum () == 0)	// handle special case of 0.0/0.0
+    if (intVal.signum () == 0)	// handle special case of 0.0/0.0
       return ZERO;
     
-    BigInteger dividend = num.multiply (BigInteger.valueOf (10).pow 
+    BigInteger dividend = intVal.multiply (BigInteger.valueOf (10).pow 
 					(newScale + 1 - (scale - val.scale)));
     
-    BigInteger parts[] = dividend.divideAndRemainder (val.num);
+    BigInteger parts[] = dividend.divideAndRemainder (val.intVal);
 //      System.out.println("int: " + parts[0]);
 //      System.out.println("rem: " + parts[1]);
 
@@ -194,12 +195,12 @@ public class BigDecimal extends Number i
   public int compareTo (BigDecimal val) 
   {
     if (scale == val.scale)
-      return num.compareTo (val.num);
+      return intVal.compareTo (val.intVal);
 
     BigInteger thisParts[] = 
-      num.divideAndRemainder (BigInteger.valueOf (10).pow (scale));
+      intVal.divideAndRemainder (BigInteger.valueOf (10).pow (scale));
     BigInteger valParts[] =
-      val.num.divideAndRemainder (BigInteger.valueOf (10).pow (val.scale));
+      val.intVal.divideAndRemainder (BigInteger.valueOf (10).pow (val.scale));
     
     int compare;
     if ((compare = thisParts[0].compareTo (valParts[0])) != 0)
@@ -263,7 +264,7 @@ public class BigDecimal extends Number i
 
   public BigDecimal movePointLeft (int n)
   {
-    return (n < 0) ? movePointRight (-n) : new BigDecimal (num, scale + n);
+    return (n < 0) ? movePointRight (-n) : new BigDecimal (intVal, scale + n);
   }
 
   public BigDecimal movePointRight (int n)
@@ -272,15 +273,15 @@ public class BigDecimal extends Number i
       return movePointLeft (-n);
 
     if (scale >= n)
-      return new BigDecimal (num, scale - n);
+      return new BigDecimal (intVal, scale - n);
 
-    return new BigDecimal (num.multiply 
+    return new BigDecimal (intVal.multiply 
 			   (BigInteger.valueOf (10).pow (n - scale)), 0);
   }
 
   public int signum () 
   {
-    return num.signum ();
+    return intVal.signum ();
   }
 
   public int scale () 
@@ -290,17 +291,17 @@ public class BigDecimal extends Number i
   
   public BigDecimal abs () 
   {
-    return new BigDecimal (num.abs (), scale);
+    return new BigDecimal (intVal.abs (), scale);
   }
 
   public BigDecimal negate () 
   {
-    return new BigDecimal (num.negate (), scale);
+    return new BigDecimal (intVal.negate (), scale);
   }
 
   public String toString () 
   {
-    String bigStr = num.toString();
+    String bigStr = intVal.toString();
     if (scale == 0) 
       return bigStr;
 
@@ -322,7 +323,8 @@ public class BigDecimal extends Number i
 
   public BigInteger toBigInteger () 
   {
-    return scale == 0 ? num : num.divide (BigInteger.valueOf (10).pow (scale));
+    return scale == 0 ? intVal :
+      intVal.divide (BigInteger.valueOf (10).pow (scale));
   }
 
 
Index: java/math/BigInteger.java
===================================================================
RCS file: /cvs/java/libgcj/libjava/java/math/BigInteger.java,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -p -r1.7 -r1.8
--- BigInteger.java	2000/03/24 09:18:12	1.7
+++ BigInteger.java	2000/10/27 10:33:46	1.8
@@ -11,6 +11,9 @@ details.  */
 package java.math;
 import gnu.gcj.math.*;
 import java.util.Random;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.IOException;
 
 /**
  * @author Warren Levy <warrenl@cygnus.com>
@@ -35,10 +38,19 @@ public class BigInteger extends Number i
    * If words == null, the ival is the value of this BigInteger.
    * Otherwise, the first ival elements of words make the value
    * of this BigInteger, stored in little-endian order, 2's-complement form. */
-  private int ival;
-  private int[] words;
+  transient private int ival;
+  transient private int[] words;
 
+  // Serialization fields.
+  private int bitCount = -1;
+  private int bitLength = -1;
+  private int firstNonzeroByteNum = -2;
+  private int lowestSetBit = -2;
+  private byte[] magnitude;
+  private int signum;
+  private static final long serialVersionUID = -8287574255936472291L;
 
+
   /** We pre-allocate integers in the range minFixNum..maxFixNum. */
   private static final int minFixNum = -100;
   private static final int maxFixNum = 1024;
@@ -2200,5 +2212,23 @@ public class BigInteger extends Number i
 	i = bitCount(x_words, x_len);
       }
     return isNegative() ? x_len * 32 - i : i;
+  }
+
+  private void readObject(ObjectInputStream s)
+    throws IOException, ClassNotFoundException
+  {
+    s.defaultReadObject();
+    words = byteArrayToIntArray(magnitude, signum < 0 ? -1 : 0);
+    BigInteger result = make(words, words.length);
+    this.ival = result.ival;
+    this.words = result.words;
+  }
+
+  private void writeObject(ObjectOutputStream s)
+    throws IOException, ClassNotFoundException
+  {
+    signum = signum();
+    magnitude = toByteArray();
+    s.defaultWriteObject();
   }
 }
Index: java/util/BitSet.java
===================================================================
RCS file: /cvs/java/libgcj/libjava/java/util/BitSet.java,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -p -r1.5 -r1.6
--- BitSet.java	2000/05/04 15:50:34	1.5
+++ BitSet.java	2000/10/27 10:33:46	1.6
@@ -174,4 +174,5 @@ public final class BitSet implements Clo
 
   // The actual bits.
   private long[] bits;
+  private static final long serialVersionUID = 7997698588986878753L;
 }
Index: java/util/Calendar.java
===================================================================
RCS file: /cvs/java/libgcj/libjava/java/util/Calendar.java,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -p -r1.6 -r1.7
--- Calendar.java	2000/03/07 19:55:27	1.6
+++ Calendar.java	2000/10/27 10:33:46	1.7
@@ -1,274 +1,978 @@
-/* Copyright (C) 1998, 1999, 2000  Free Software Foundation
+/* java.util.Calendar
+   Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
 
-   This file is part of libgcj.
+This file is part of GNU Classpath.
 
-This software is copyrighted work licensed under the terms of the
-Libgcj License.  Please consult the file "LIBGCJ_LICENSE" for
-details.  */
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+As a special exception, if you link this library with other files to
+produce an executable, this library does not by itself cause the
+resulting executable to be covered by the GNU General Public License.
+This exception does not however invalidate any other reasons why the
+executable file might be covered by the GNU General Public License. */
 
+
 package java.util;
+import java.lang.reflect.InvocationTargetException;
+import java.io.*;
 
 /**
- * @author Per Bothner <bothner@cygnus.com>
- * @date October 24, 1998.
- */
-
-/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3,
- * and "The Java Language Specification", ISBN 0-201-63451-1.
- * Status:  Unimplemented:  getAvailableLocales.
- *   No Locale knowledge.
+ * This class is an abstract base class for Calendars, which can be
+ * used to convert between <code>Date</code> objects and a set of
+ * 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
+ * a <code>GregorianCalendar</code> for the current date. <br>
+ *
+ * If you want to convert a date from the Year, Month, Day, DayOfWeek,
+ * etc.  Representation to a <code>Date</code>-Object, you can create
+ * a new Calendar with <code>getInstance()</code>,
+ * <code>clear()</code> all fields, <code>set(int,int)</code> the
+ * fields you need and convert it with <code>getTime()</code>. <br>
+ *
+ * If you want to convert a <code>Date</code>-object to the Calendar
+ * representation, create a new Calendar, assign the
+ * <code>Date</code>-Object with <code>setTime()</code>, and read the
+ * fields with <code>get(int)</code>. <br>
+ *
+ * When computing the date from time fields, it may happen, that there
+ * are either two few fields set, or some fields are inconsistent.  This
+ * cases will handled in a calender specific way.  Missing fields are
+ * replaced by the fields of the epoch: 1970 January 1 00:00. <br>
+ *
+ * To understand, how the day of year is computed out of the fields
+ * look at the following table.  It is traversed from top to bottom,
+ * and for the first line all fields are set, that line is used to
+ * compute the day. <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>
+ *
+ * <STRONG>Note:</STRONG> This can differ for non-Gregorian calendar. <br>
+ *
+ * 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
+ * <code>add</code>ing/substracting a fixed amount to a field.
+ *
+ * @see Date
+ * @see GregorianCalendar
+ * @see TimeZone
+ * @see java.text.DateFormat 
  */
-
-public abstract class Calendar implements java.io.Serializable, Cloneable
+public abstract class Calendar implements Serializable, Cloneable
 {
-  public final static int JANUARY = 0;
-  public final static int FEBRUARY = 1;
-  public final static int MARCH = 2;
-  public final static int APRIL = 3;
-  public final static int MAY = 4;
-  public final static int JUNE = 5;
-  public final static int JULY = 6;
-  public final static int AUGUST = 7;
-  public final static int SEPTEMBER = 8;
-  public final static int OCTOBER = 9;
-  public final static int NOVEMBER = 10;
-  public final static int DECEMBER = 11;
-  public final static int UNDECIMBER = 12;
-
-  public final static int SUNDAY = 1;
-  public final static int MONDAY = 2;
-  public final static int TUESDAY = 3;
-  public final static int WEDNESDAY = 4;
-  public final static int THURSDAY = 5;
-  public final static int FRIDAY = 6;
-  public final static int SATURDAY = 7;
-
-  public final static int AM = 0;
-  public final static int PM = 1;
-
-  public final static int FIELD_COUNT = 17;
-
-  // These constants are not docuemnted, but were determined using
-  // a simple test program.
-  public final static int ERA = 0;
-  public final static int YEAR = 1;
-  public final static int MONTH = 2;
-  public final static int WEEK_OF_YEAR = 3;
-  public final static int WEEK_OF_MONTH = 4;
-  public final static int DATE = 5;
-  public final static int DAY_OF_MONTH = 5;
-  public final static int DAY_OF_YEAR = 6;
-  public final static int DAY_OF_WEEK = 7;
-  public final static int DAY_OF_WEEK_IN_MONTH = 8;
-  public final static int AM_PM = 9;
-  public final static int HOUR = 10;
-  public final static int HOUR_OF_DAY = 11;
-  public final static int MINUTE = 12;
-  public final static int SECOND = 13;
-  public final static int MILLISECOND = 14;
-  public final static int ZONE_OFFSET = 15;
-  public final static int DST_OFFSET = 16;
-
-  // The fields are as specified in Sun's "Serialized Form"
-  // in the JDK 1.2 beta 4 API specification.
-  protected boolean areFieldsSet;
-  protected int[] fields;
-  private int firstDayOfWeek;
-  protected boolean[] isSet;
-  protected boolean isTimeSet;
-  private boolean lenient;
-  private int minimalDaysInFirstWeek;
-  private int nextStamp;
-  //private int serialVersionOnStream;
+  /**
+   * Constant representing the era time field.
+   */
+  public static final int ERA = 0;
+  /**
+   * Constant representing the year time field.
+   */
+  public static final int YEAR = 1;
+  /**
+   * Constant representing the month time field.  This field
+   * should contain one of the JANUARY,...,DECEMBER constants below.
+   */
+  public static final int MONTH = 2;
+  /**
+   * Constant representing the week of the year field.
+   * @see #setFirstDayOfWeek(int)
+   */
+  public static final int WEEK_OF_YEAR = 3;
+  /**
+   * Constant representing the week of the month time field.
+   * @see #setFirstDayOfWeek(int)
+   */
+  public static final int WEEK_OF_MONTH = 4;
+  /**
+   * Constant representing the day time field, synonym for DAY_OF_MONTH.
+   */
+  public static final int DATE = 5;
+  /**
+   * Constant representing the day time field.
+   */
+  public static final int DAY_OF_MONTH = 5;
+  /**
+   * Constant representing the day of year time field.  This is
+   * 1 for the first day in month.
+   */
+  public static final int DAY_OF_YEAR = 6;
+  /**
+   * Constant representing the day of week time field.  This field
+   * should contain one of the SUNDAY,...,SATURDAY constants below.
+   */
+  public static final int DAY_OF_WEEK = 7;
+  /**
+   * Constant representing the day-of-week-in-month field.  For
+   * instance this field contains 2 for the second thursday in a
+   * month.  If you give a negative number here, the day will count
+   * from the end of the month.
+   */
+  public static final int DAY_OF_WEEK_IN_MONTH = 8;
+  /**
+   * Constant representing the part of the day for 12-hour clock.  This
+   * should be one of AM or PM.
+   */
+  public static final int AM_PM = 9;
+  /**
+   * Constant representing the hour time field for 12-hour clock.
+   */
+  public static final int HOUR = 10;
+  /**
+   * Constant representing the hour of day time field for 24-hour clock.
+   */
+  public static final int HOUR_OF_DAY = 11;
+  /**
+   * Constant representing the minute of hour time field.
+   */
+  public static final int MINUTE = 12;
+  /**
+   * Constant representing the second time field.
+   */
+  public static final int SECOND = 13;
+  /**
+   * Constant representing the millisecond time field.
+   */
+  public static final int MILLISECOND = 14;
+  /**
+   * Constant representing the time zone offset time field for the
+   * time given in the other fields.  It is measured in
+   * milliseconds.  The default is the offset of the time zone.  
+   */
+  public static final int ZONE_OFFSET = 15;
+  /**
+   * Constant representing the daylight saving time offset in
+   * milliseconds.  The default is the value given by the time zone.  
+   */
+  public static final int DST_OFFSET = 16;
+  /**
+   * Number of time fields.
+   */
+  public static final int FIELD_COUNT = 17;
+
+  /**
+   * Constant representing Sunday.
+   */
+  public static final int SUNDAY = 1;
+  /**
+   * Constant representing Monday.
+   */
+  public static final int MONDAY = 2;
+  /**
+   * Constant representing Tuesday.
+   */
+  public static final int TUESDAY = 3;
+  /**
+   * Constant representing Wednesday.
+   */
+  public static final int WEDNESDAY = 4;
+  /**
+   * Constant representing Thursday.
+   */
+  public static final int THURSDAY = 5;
+  /**
+   * Constant representing Friday.
+   */
+  public static final int FRIDAY = 6;
+  /**
+   * Constant representing Saturday.
+   */
+  public static final int SATURDAY = 7;
+
+  /**
+   * Constant representing January.
+   */
+  public static final int JANUARY = 0;
+  /**
+   * Constant representing February.
+   */
+  public static final int FEBRUARY = 1;
+  /**
+   * Constant representing March.
+   */
+  public static final int MARCH = 2;
+  /**
+   * Constant representing April.
+   */
+  public static final int APRIL = 3;
+  /**
+   * Constant representing May.
+   */
+  public static final int MAY = 4;
+  /**
+   * Constant representing June.
+   */
+  public static final int JUNE = 5;
+  /**
+   * Constant representing July.
+   */
+  public static final int JULY = 6;
+  /**
+   * Constant representing August.
+   */
+  public static final int AUGUST = 7;
+  /**
+   * Constant representing September.
+   */
+  public static final int SEPTEMBER = 8;
+  /**
+   * Constant representing October.
+   */
+  public static final int OCTOBER = 9;
+  /**
+   * Constant representing November.
+   */
+  public static final int NOVEMBER = 10;
+  /**
+   * Constant representing December.
+   */
+  public static final int DECEMBER = 11;
+  /**
+   * Constant representing Undecimber. This is an artifical name useful
+   * for lunar calendars.
+   */
+  public static final int UNDECIMBER = 12;
+
+  /**
+   * Useful constant for 12-hour clock.
+   */
+  public static final int AM = 0;
+  /**
+   * Useful constant for 12-hour clock.
+   */
+  public static final int PM = 1;
+
+  /**
+   * The time fields.  The array is indexed by the constants YEAR to
+   * DST_OFFSET.
+   * @serial
+   */
+  protected int[] fields = new int[FIELD_COUNT];
+  /**
+   * The flags which tell if the fields above have a value.
+   * @serial
+   */
+  protected boolean[] isSet = new boolean[FIELD_COUNT];
+  /**
+   * The time in milliseconds since the epoch.
+   * @serial
+   */
   protected long time;
+  /**
+   * Tells if the above field has a valid value.
+   * @serial
+   */
+  protected boolean isTimeSet;
+  /**
+   * Tells if the fields have a valid value.  This superseeds the isSet
+   * array.
+   * @serial
+   */
+  protected boolean areFieldsSet;
+
+  /**
+   * The time zone of this calendar.  Used by sub classes to do UTC / local
+   * time conversion.  Sub classes can access this field with getTimeZone().
+   * @serial
+   */
   private TimeZone zone;
 
-  protected Calendar ()
-  {
-    this (null, null);
-  }
+  /**
+   * Specifies if the date/time interpretation should be lenient.
+   * If the flag is set, a date such as "February 30, 1996" will be
+   * treated as the 29th day after the February 1.  If this flag
+   * is false, such dates will cause an exception.
+   * @serial
+   */
+  private boolean lenient;
 
-  protected Calendar (TimeZone zone, Locale loc)
-  {
-    fields = new int[FIELD_COUNT];
-    isSet = new boolean[FIELD_COUNT];
-    firstDayOfWeek = SUNDAY;  // Locale-dependent.  FIXME.
-    this.zone = zone != null ? zone : TimeZone.getDefault();
-  }
+  /**
+   * Sets what the first day of week is.  This is used for
+   * WEEK_OF_MONTH and WEEK_OF_YEAR fields. 
+   * @serial
+   */
+  private int firstDayOfWeek;
 
-  public Object clone ()
-  {
-    try
-      {
-	return super.clone();
-      }
-    catch (CloneNotSupportedException ex)
+  /**
+   * Sets how many days are required in the first week of the year.
+   * If the first day of the year should be the first week you should
+   * set this value to 1.  If the first week must be a full week, set
+   * it to 7.
+   * @serial
+   */
+  private int minimalDaysInFirstWeek;
+
+  /**
+   * 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>
+   * <dd>JDK 1.1.6 or later.  This always writes a correct `time' value
+   * on the stream, as well as the other fields, to be compatible with
+   * earlier versions</dd>
+   * @since JDK1.1.6
+   * @serial
+   */
+  private int serialVersionOnStream = 1;
+
+  /**
+   * XXX - I have not checked the compatibility.  The documentation of
+   * the serialized-form is quite hairy...
+   */
+  static final long serialVersionUID = -1807547505821590642L;
+
+  /**
+   * The name of the resource bundle.
+   */
+  private static final String bundleName = "gnu.java.locale.Calendar";
+
+  /**
+   * Constructs a new Calender with the default time zone and the default
+   * locale.
+   */
+  protected Calendar()
+  {
+    this(TimeZone.getDefault(), Locale.getDefault());
+  }
+
+  /**
+   * Constructs a new Calender with the given time zone and the given
+   * locale.
+   * @param zone a time zone.
+   * @param locale a locale.
+   */
+  protected Calendar(TimeZone zone, Locale locale)
+  {
+    this.zone = zone;
+    lenient = true;
+
+    ResourceBundle rb = ResourceBundle.getBundle(bundleName, locale);
+
+    firstDayOfWeek = ((Integer) rb.getObject("firstDayOfWeek")).intValue();
+    minimalDaysInFirstWeek =
+      ((Integer) rb.getObject("minimalDaysInFirstWeek")).intValue();
+  }
+
+  /**
+   * Creates a calendar representing the actual time, using the default
+   * time zone and locale.
+   */
+  public static synchronized Calendar getInstance()
+  {
+    return getInstance(TimeZone.getDefault(), Locale.getDefault());
+  }
+
+  /**
+   * Creates a calendar representing the actual time, using the given
+   * time zone and the default locale.
+   * @param zone a time zone.
+   */
+  public static synchronized Calendar getInstance(TimeZone zone)
+  {
+    return getInstance(zone, Locale.getDefault());
+  }
+
+  /**
+   * Creates a calendar representing the actual time, using the default
+   * time zone and the given locale.
+   * @param locale a locale.
+   */
+  public static synchronized Calendar getInstance(Locale locale)
+  {
+    return getInstance(TimeZone.getDefault(), locale);
+  }
+
+  /**
+   * Creates a calendar representing the actual time, using the given
+   * time zone and locale.
+   * @param zone a time zone.
+   * @param locale a locale.
+   */
+  public static synchronized Calendar getInstance(TimeZone zone, Locale locale)
+  {
+    String calendarClassName = null;
+    ResourceBundle rb = ResourceBundle.getBundle(bundleName, locale);
+    calendarClassName = rb.getString("calendarClass");
+    if (calendarClassName != null)
       {
-	throw new RuntimeException("internal error - "+ex);
+	try
+	  {
+	    Class calendarClass = Class.forName(calendarClassName);
+	    if (Calendar.class.isAssignableFrom(calendarClass))
+	      {
+		return (Calendar) calendarClass.getConstructor(
+		  new Class[] { TimeZone.class, Locale.class}
+		).newInstance(new Object[] {zone, locale} );
+	      }
+	  }
+	catch (ClassNotFoundException ex) {}
+	catch (IllegalAccessException ex) {}
+	catch (NoSuchMethodException ex) {}
+	catch (InstantiationException ex) {}
+	catch (InvocationTargetException ex) {}
+	// XXX should we ignore these errors or throw an exception ?
       }
-  }
-
-  public String toString ()
-  {
-    // We have much latitude in how we implement this.
-    return ("areFieldsSet " + areFieldsSet
-	    + "; fields " + fields
-	    + "; firstDayOfWeek " + firstDayOfWeek
-	    + "; isSet " + isSet
-	    + "; isTimeSet " + isTimeSet
-	    + "; lenient " + lenient
-	    + "; minimalDaysInFirstWeek " + minimalDaysInFirstWeek
-	    + "; nextStamp " + nextStamp
-	    + "; time " + time
-	    + "; zone " + zone);
-  }
-
-  public static Calendar getInstance ()
-  {
-    return new GregorianCalendar ();
-  }
-
-  public static Calendar getInstance (TimeZone zone)
-  {
-    return new GregorianCalendar (zone);
-  }
-
-  public static Calendar getInstance (Locale locale)
-  {
-    return new GregorianCalendar (locale);
+    return new GregorianCalendar(zone, locale);
   }
 
-  public static Calendar getInstance (TimeZone zone, Locale locale)
+  /**
+   * Gets the set of locales for which a Calendar is availiable.
+   * @exception MissingResourceException if locale data couldn't be found.
+   * @return the set of locales.
+   */
+  public static synchronized Locale[] getAvailableLocales()
   {
-    return new GregorianCalendar (zone, locale);
+    ResourceBundle rb = ResourceBundle.getBundle(bundleName,
+						 new Locale("", ""));
+    return (Locale[]) rb.getObject("availableLocales");
   }
 
-  public boolean isLenient() { return lenient; }
-  public void setLenient (boolean lenient) { this.lenient = lenient; }
+  /**
+   * Converts the time field values (<code>fields</code>) to
+   * milliseconds since the epoch UTC (<code>time</code>).  Override
+   * this method if you write your own Calendar.  */
+  protected abstract void computeTime();
 
-  public int getFirstDayOfWeek ()
-  {
-    return firstDayOfWeek;
-  }
+  /**
+   * 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.  
+   */
+  protected abstract void computeFields();
 
-  public void setFirstDayOfWeek (int value)
+  /**
+   * Converts the time represented by this object to a
+   * <code>Date</code>-Object.
+   * @return the Date.
+   */
+  public final Date getTime()
+  {
+    if (!isTimeSet)
+      computeTime();
+    return new Date(time);
+  }
+
+  /**
+   * Sets this Calender's time to the given Date.  All time fields
+   * are invalidated by this method.
+   */
+  public final void setTime(Date date)
   {
-    firstDayOfWeek = value;
+    setTimeInMillis(date.getTime());
   }
 
-  public int getMinimalDaysInFirstWeek ()
+  /**
+   * Returns the time represented by this Calendar.
+   * @return the time in milliseconds since the epoch.
+   */
+  protected long getTimeInMillis()
   {
-    return minimalDaysInFirstWeek;
+    if (!isTimeSet)
+      computeTime();
+    return time;
   }
 
-  public void setMinimalDaysInFirstWeek (int value)
+  /**
+   * Sets this Calender's time to the given Time.  All time fields
+   * are invalidated by this method.
+   * @param time the time in milliseconds since the epoch
+   */
+  protected void setTimeInMillis(long time)
   {
-    minimalDaysInFirstWeek = value;
+    this.time = time;
+    isTimeSet = true;
+    computeFields();
   }
 
-  public TimeZone getTimeZone ()
+  /**
+   * Gets the value of the specified field.  They are recomputed
+   * if they are invalid.
+   * @param field the time field. One of the time field constants.
+   * @return the value of the specified field
+   */
+  public final int get(int field)
   {
-    return zone;
+    complete();
+    return fields[field];
   }
 
-  public void setTimeZone (TimeZone tz)
+  /**
+   * 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
+   * <code>areFieldsSet</code> or <code>isSet[field]</code> is false.
+   */
+  protected final int internalGet(int field)
+  {
+    return fields[field];
+  }
+
+  /**
+   * Sets the time field with the given value.  This does invalidate
+   * the time in milliseconds.
+   * @param field the time field. One of the time field constants
+   * @param value the value to be set.
+   */
+  public final void set(int field, int value)
   {
-    zone = tz;
+    if (!areFieldsSet)
+      computeFields();
+    isTimeSet = false;
+    fields[field] = value;
+    isSet[field] = true;
   }
-
-  abstract public void add(int fld, int amount);
-  abstract public void roll (int fld, boolean up);
 
-  public final void set (int year, int month, int date)
+  /**
+   * Sets the fields for year, month, and date
+   * @param year the year.
+   * @param month the month, one of the constants JANUARY..UNDICEMBER.
+   * @param date the day of the month
+   */
+  public final void set(int year, int month, int date)
   {
-    set(YEAR, year);
-    set(MONTH, month);
-    set(DATE, date);
+    if (!areFieldsSet)
+      computeFields();
+    isTimeSet = false;
+    fields[YEAR] = year;
+    fields[MONTH] = month;
+    fields[DATE] = date;
+    isSet[YEAR] = isSet[MONTH] = isSet[DATE] = true;
   }
 
-  public final void set (int year, int month, int date, int hour, int minute)
+  /**
+   * Sets the fields for year, month, date, hour, and minute
+   * @param year the year.
+   * @param month the month, one of the constants JANUARY..UNDICEMBER.
+   * @param date the day of the month
+   * @param hour the hour of day.
+   * @param minute the minute.
+   */
+  public final void set(int year, int month, int date, int hour, int minute)
   {
     set(year, month, date);
-    set(HOUR_OF_DAY, hour);
-    set(MINUTE, minute);
-  }
-
-  public final void set (int year, int month, int date,
-			 int hour, int minute, int second)
+    fields[HOUR] = hour;
+    fields[MINUTE] = minute;
+    isSet[HOUR] = isSet[MINUTE] = true;
+  }
+
+  /**
+   * Sets the fields for year, month, date, hour, and minute
+   * @param year the year.
+   * @param month the month, one of the constants JANUARY..UNDICEMBER.
+   * @param date the day of the month
+   * @param hour the hour of day.
+   * @param minute the minute.
+   * @param second the second.
+   */
+  public final void set(int year, int month, int date,
+			int hour, int minute, int second)
   {
     set(year, month, date, hour, minute);
-    set(SECOND, second);
+    fields[SECOND] = second;
+    isSet[SECOND] = true;
   }
 
-  public final void set (int fld, int value)
+  /**
+   * Clears the values of all the time fields.
+   */
+  public final void clear()
   {
-    if (! areFieldsSet) computeFields();
-    fields[fld] = value;
     isTimeSet = false;
+    areFieldsSet = false;
+    for (int i = 0; i < FIELD_COUNT; i++)
+      isSet[i] = false;
   }
 
-  public final void clear (int fld)
+  /**
+   * Clears the values of the specified time field.
+   * @param field the time field. One of the time field constants.
+   */
+  public final void clear(int field)
   {
-    fields[fld] = 0;
-    isSet[fld] = false;
+    isTimeSet = false;
     areFieldsSet = false;
+    isSet[field] = false;
   }
 
-  public final void clear ()
+  /**
+   * Determines if the specified field has a valid value.
+   * @return true if the specified field has a value.
+   */
+  public final boolean isSet(int field)
   {
-    for (int fld = FIELD_COUNT;  --fld >= 0; )
-      {
-	fields[fld] = 0;
-	isSet[fld] = false;
-      }
-    areFieldsSet = false;
+    return isSet[field];
   }
 
+  /**
+   * Fills any unset fields in the time field list
+   * @return true if the specified field has a value.  
+   */
   protected void complete()
+  {
+    if (!isTimeSet)
+      computeTime();
+    if (!areFieldsSet)
+      computeFields();
+  }
+
+  /**
+   * Compares the given calender 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 neccessary have the same fields).
+   */
+  public boolean equals(Object o)
+  {
+    return (o instanceof Calendar)
+      && getTimeInMillis() == ((Calendar) o).getTimeInMillis();
+  }
+
+  /**
+   * Returns a hash code for this calendar.
+   * @return a hash code, which fullfits the general contract of 
+   * <code>hashCode()</code>
+   */
+  public int hashCode()
+  {
+    long time = getTimeInMillis();
+    return (int) ((time & 0xffffffffL) ^ (time >> 32));
+  }
+
+  /**
+   * 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.
+   * @exception ClassCastException if o is not an calendar.
+   * @since JDK1.2 you don't need to override this method
+   */
+  public boolean before(Object o)
+  {
+    return getTimeInMillis() < ((Calendar) o).getTimeInMillis();
+  }
+
+  /**
+   * Compares the given 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.
+   * @exception ClassCastException if o is not an calendar.
+   * @since JDK1.2 you don't need to override this method
+   */
+  public boolean after(Object o)
+  {
+    return getTimeInMillis() > ((Calendar) o).getTimeInMillis();
+  }
+
+  /**
+   * Adds the specified amount of time to the given time field.  The
+   * amount may be negative to subtract the time.  If the field overflows
+   * it does what you expect: Jan, 25 + 10 Days is Feb, 4.
+   * @param field the time field. One of the time field constants.
+   * @param amount the amount of time.
+   */
+  public abstract void add(int field, int amount);
+
+  /**
+   * Rolls the specified time field up or down.  This means add one
+   * to the specified field, but don't change the other fields.  If
+   * the maximum for this field is reached, start over with the 
+   * minimum value.  <br>
+   *
+   * <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.
+   * @param field the time field. One of the time field constants.
+   * @param up the direction, true for up, false for down.
+   */
+  public abstract void roll(int field, boolean up);
+
+  /**
+   * Rolls up or down the specified time field by the given amount.
+   * A negative amount rolls down.  The default implementation is
+   * call <code>roll(int, boolean)</code> for the specified amount.
+   *
+   * Subclasses should override this method to do more intuitiv things.
+   *
+   * @param field the time field. One of the time field constants.
+   * @param amount the amount to roll by, positive for rolling up,
+   * negative for rolling down.  
+   * @since JDK1.2
+   */
+  public void roll(int field, int amount)
   {
-    if (!isTimeSet) computeTime();
-    if (!areFieldsSet) computeFields();
+    while (amount > 0)
+      {
+	roll(field, true);
+	amount--;
+      }
+    while (amount < 0)
+      {
+	roll(field, false);
+	amount++;
+      }
   }
 
-  protected abstract void computeFields();
-  protected abstract void computeTime();
 
-  protected final int internalGet (int fld) { return fields[fld]; }
+  /**
+   * Sets the time zone to the specified value.
+   * @param zone the new time zone
+   */
+  public void setTimeZone(TimeZone zone)
+  {
+    this.zone = zone;
+  }
 
-  public final int get(int fld)
+  /**
+   * Gets the time zone of this calendar
+   * @return the current time zone.
+   */
+  public TimeZone getTimeZone()
   {
-    complete();
-    return fields[fld];
+    return zone;
   }
 
-  public abstract boolean after (Object cal);
-  public abstract boolean before (Object cal);
-  public abstract boolean equals (Object obj);
+  /**
+   * Specifies if the date/time interpretation should be lenient.
+   * If the flag is set, a date such as "February 30, 1996" will be
+   * treated as the 29th day after the February 1.  If this flag
+   * is false, such dates will cause an exception.
+   * @param lenient true, if the date should be interpreted linient,
+   * false if it should be interpreted strict.
+   */
+  public void setLenient(boolean lenient)
+  {
+    this.lenient = lenient;
+  }
+
+  /**
+   * Tells if the date/time interpretation is lenient.
+   * @return true, if the date should be interpreted linient,
+   * false if it should be interpreted strict.
+   */
+  public boolean isLenient()
+  {
+    return lenient;
+  }
+
+  /**
+   * Sets what the first day of week is.  This is used for
+   * WEEK_OF_MONTH and WEEK_OF_YEAR fields. 
+   * @param value the first day of week.  One of SUNDAY to SATURDAY.
+   */
+  public void setFirstDayOfWeek(int value)
+  {
+    firstDayOfWeek = value;
+  }
 
-  protected long getTimeInMillis()
+  /**
+   * Gets what the first day of week is.  This is used for
+   * WEEK_OF_MONTH and WEEK_OF_YEAR fields. 
+   * @return the first day of week.  One of SUNDAY to SATURDAY.
+   */
+  public int getFirstDayOfWeek()
   {
-    if (!isTimeSet) computeTime();
-    return time;
+    return firstDayOfWeek;
   }
 
-  public final Date getTime() { return new Date(getTimeInMillis()); }
+  /**
+   * Sets how many days are required in the first week of the year.
+   * If the first day of the year should be the first week you should
+   * set this value to 1.  If the first week must be a full week, set
+   * it to 7.
+   * @param value the minimal days required in the first week.
+   */
+  public void setMinimalDaysInFirstWeek(int value)
+  {
+    minimalDaysInFirstWeek = value;
+  }
 
-  public final void setTime (Date date)
+  /**
+   * Gets how many days are required in the first week of the year.
+   * @return the minimal days required in the first week.
+   * @see #setMinimalDaysInFirstWeek
+   */
+  public int getMinimalDaysInFirstWeek()
   {
-    setTimeInMillis(date.getTime());
+    return minimalDaysInFirstWeek;
   }
 
-  protected void setTimeInMillis (long millis)
+  /**
+   * Gets the smallest value that is allowed for the specified field.
+   * @param field the time field. One of the time field constants.
+   * @return the smallest value.
+   */
+  public abstract int getMinimum(int field);
+
+  /**
+   * Gets the biggest value that is allowed for the specified field.
+   * @param field the time field. One of the time field constants.
+   * @return the biggest value.
+   */
+  public abstract int getMaximum(int field);
+
+
+  /**
+   * Gets the greatest minimum value that is allowed for the specified field.
+   * @param field the time field. One of the time field constants.
+   * @return the greatest minimum value.
+   */
+  public abstract int getGreatestMinimum(int field);
+
+  /**
+   * Gets the smallest maximum value that is allowed for the
+   * specified field.  For example this is 28 for DAY_OF_MONTH.
+   * @param field the time field. One of the time field constants.
+   * @return the least maximum value.  
+   */
+  public abstract int getLeastMaximum(int field);
+
+  /**
+   * Gets the actual minimum value that is allowed for the specified field.
+   * This value is dependant on the values of the other fields.
+   * @param field the time field. One of the time field constants.
+   * @return the actual minimum value.
+   * @since jdk1.2
+   */
+  // FIXME: XXX: Not abstract in JDK 1.2.
+  // public abstract int getActualMinimum(int field);
+
+  /**
+   * Gets the actual maximum value that is allowed for the specified field.
+   * This value is dependant on the values of the other fields.
+   * @param field the time field. One of the time field constants.
+   * @return the actual maximum value.  
+   * @since jdk1.2
+   */
+  // FIXME: XXX: Not abstract in JDK 1.2.
+  // public abstract int getActualMaximum(int field);
+
+  /**
+   * Return a clone of this object.
+   */
+  public Object clone()
   {
-    time = millis;
-    isTimeSet = true;
-    clear();
+    try
+      {
+	Calendar cal = (Calendar) super.clone();
+	cal.fields = (int[]) fields.clone();
+	cal.isSet = (boolean[])isSet.clone();
+	return cal;
+      }
+    catch (CloneNotSupportedException ex)
+      {
+	return null;
+      }
   }
 
-  abstract public int getMaximum(int fld);
-  abstract public int getMinimum(int fld);
-  abstract public int getGreatestMinimum(int fld);
-  abstract public int getLeastMaximum(int fld);
+  private final static String[] fieldNames = {
+    ",ERA=", ",YEAR=", ",MONTH=",
+    ",WEEK_OF_YEAR=", ",WEEK_OF_MONTH=",
+    ",DAY_OF_MONTH=", ",DAY_OF_YEAR=", ",DAY_OF_WEEK=",
+    ",DAY_OF_WEEK_IN_MONTH=",
+    ",AM_PM=", ",HOUR=", ",HOUR_OF_DAY=",
+    ",MINUTE=", ",SECOND=", ",MILLISECOND=",
+    ",ZONE_OFFSET=", ",DST_OFFSET="
+  };
+
+
+  /**
+   * Returns a string representation of this object.  It is mainly
+   * for debugging purposes and its content is implementation
+   * specific.
+   */
+  public String toString()
+  {
+    StringBuffer sb = new StringBuffer();
+    sb.append(getClass().getName()).append('[');
+    sb.append("time=");
+    if (isTimeSet)
+      sb.append(time);
+    else
+      sb.append("?");
+    sb.append(",zone=" + zone);
+    sb.append(",areFieldsSet=" + areFieldsSet);
+    for (int i = 0; i < FIELD_COUNT; i++)
+      {
+	sb.append(fieldNames[i]);
+	if (isSet[i])
+	  sb.append(fields[i]);
+	else
+	  sb.append("?");
+      }
+    sb.append(",lenient=").append(lenient);
+    sb.append(",firstDayOfWeek=").append(firstDayOfWeek);
+    sb.append(",minimalDaysInFirstWeek=").append(minimalDaysInFirstWeek);
+    sb.append("]");
+    return sb.toString();
+  }
+
+  /**
+   * Saves the state of the object to the stream.  Ideally we would
+   * only write the time field, but we need to be compatible with
+   * earlier versions. <br>
+   *
+   * This doesn't write the JDK1.1 field nextStamp to the stream, as
+   * I don't know what it is good for, and because the documentation
+   * says, that it could be omitted.  */
+  private void writeObject(ObjectOutputStream stream) throws IOException
+  {
+    if (!isTimeSet)
+      computeTime();
+    stream.defaultWriteObject();
+  }
+
+  /**
+   * Reads the object back from stream (deserialization).
+   */
+  private void readObject(ObjectInputStream stream)
+    throws IOException, ClassNotFoundException
+  {
+    stream.defaultReadObject();
+    if (!isTimeSet)
+      computeTime();
 
-  public final boolean isSet(int fld) { return isSet[fld]; }
+    if (serialVersionOnStream > 1)
+      {
+	// This is my interpretation of the serial number:
+	// Sun wants to remove all fields from the stream someday
+	// and will then increase the serialVersion number again.
+	// We prepare to be compatible.
+
+	fields = new int[FIELD_COUNT];
+	isSet = new boolean[FIELD_COUNT];
+	areFieldsSet = false;
+      }
+  }
 }
Index: java/util/GregorianCalendar.java
===================================================================
RCS file: /cvs/java/libgcj/libjava/java/util/GregorianCalendar.java,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -p -r1.5 -r1.6
--- GregorianCalendar.java	2000/09/08 19:37:09	1.5
+++ GregorianCalendar.java	2000/10/27 10:33:46	1.6
@@ -1,4 +1,4 @@
-/* Copyright (C) 1998, 1999  Free Software Foundation
+/* Copyright (C) 1998, 1999, 2000  Free Software Foundation
 
    This file is part of libgcj.
 
@@ -93,17 +93,17 @@ public class GregorianCalendar extends C
 
   public GregorianCalendar ()
   {
-    this(null, null);
+    this(TimeZone.getDefault (), Locale.getDefault ());
   }
 
   public GregorianCalendar (TimeZone zone)
   {
-    this (zone, null);
+    this (zone, Locale.getDefault ());
   }
 
   public GregorianCalendar (Locale locale)
   {
-    this (null, locale);
+    this (TimeZone.getDefault (), locale);
   }
 
   public GregorianCalendar (TimeZone zone, Locale locale)
Index: java/util/natGregorianCalendar.cc
===================================================================
RCS file: /cvs/java/libgcj/libjava/java/util/natGregorianCalendar.cc,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -p -r1.6 -r1.7
--- natGregorianCalendar.cc	2000/04/21 20:38:43	1.6
+++ natGregorianCalendar.cc	2000/10/27 11:53:53	1.7
@@ -111,4 +111,6 @@ java::util::GregorianCalendar::computeFi
   elements(fields)[DST_OFFSET] = tim.tm_isdst <= 0 ? 0 : 60*60*1000;
   elements(fields)[ZONE_OFFSET] = getTimeZone()->getRawOffset();
   areFieldsSet = true;
+  for (int i = 0; i < FIELD_COUNT; i++)
+    elements(isSet__)[i] = true;
 }
Index: java/util/Locale.java
===================================================================
RCS file: /cvs/java/libgcj/libjava/java/util/Locale.java,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -p -r1.6 -r1.7
--- Locale.java	2000/05/04 15:50:34	1.6
+++ Locale.java	2000/10/27 10:33:46	1.7
@@ -26,6 +26,7 @@ public final class Locale implements jav
   private String language;
   private String variant;
   private static Locale defaultLocale;
+  private static final long serialVersionUID = 9149081749638150636L;
 
   // These are as specified in the JDK 1.2 AP documentation
 
@@ -144,5 +145,29 @@ public final class Locale implements jav
 	  }
       }
     return result.toString();
+  }
+
+ /**
+   * @serialdata According to jdk1.2 the hashcode should always be 
+   * written as -1; 
+   */
+  private void writeObject(java.io.ObjectOutputStream output)
+    throws java.io.IOException
+  {
+    int tmpHashcode = hashcode;
+    hashcode = -1;
+    output.defaultWriteObject();
+    hashcode = tmpHashcode;
+  }
+
+  /**
+   * @serialdata  According to jdk1.2 the hashCode is always invalid
+   * and must be recomputed.
+   */
+  private void readObject(java.io.ObjectInputStream input)
+    throws java.io.IOException, ClassNotFoundException
+  {
+    input.defaultReadObject();
+    hashcode = language.hashCode() ^ country.hashCode() ^ variant.hashCode();
   }
 }
Index: java/util/SimpleTimeZone.java
===================================================================
RCS file: /cvs/java/libgcj/libjava/java/util/SimpleTimeZone.java,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -p -r1.4 -r1.5
--- SimpleTimeZone.java	2000/03/07 19:55:27	1.4
+++ SimpleTimeZone.java	2000/10/27 10:33:46	1.5
@@ -1,208 +1,830 @@
-/* Copyright (C) 1998, 1999, 2000  Free Software Foundation
+/* java.util.SimpleTimeZone
+   Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
 
-   This file is part of libgcj.
+This file is part of GNU Classpath.
 
-This software is copyrighted work licensed under the terms of the
-Libgcj License.  Please consult the file "LIBGCJ_LICENSE" for
-details.  */
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+As a special exception, if you link this library with other files to
+produce an executable, this library does not by itself cause the
+resulting executable to be covered by the GNU General Public License.
+This exception does not however invalidate any other reasons why the
+executable file might be covered by the GNU General Public License. */
 
+
 package java.util;
 
-/**
- * @author Per Bothner <bothner@cygnus.com>
- * @date October 24, 1998.
- */
-
-/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3.
- * Status:  Does not know how to figure out if daylight savings time
- *   is in effect;  hence only correct for zones without DST.
- *   No known spec for hashCode.
- */
+import java.text.DateFormatSymbols;
 
+/**
+ * This class represents a simple time zone offset and handles
+ * daylight savings.  It can only handle one daylight savings rule, so
+ * it can't represent historical changes.
+ *
+ * This object is tightly bound to the Gregorian calendar.  It assumes
+ * a regular seven days week, and the month lengths are that of the
+ * Gregorian Calendar.  It can only handle daylight savings for years
+ * lying in the AD era.
+ *
+ * @see Calendar
+ * @see GregorianCalender 
+ * @author Jochen Hoenicke */
 public class SimpleTimeZone extends TimeZone
 {
-  // The fields are as specified in Sun's "Serialized Form"
-  // in the JDK 1.2 beta 4 API specification.
-
-  int dstSavings = 60 * 60 * 1000;
-
-  int rawOffset;
-
-  // int serialVersionOnStream;
-
-  int startDay;
-  int startDayOfWeek;
-  int startMode;  /// Seems to be JDK 1.2 only.
-
-  int startMonth;
-
-  int startTime;
-
-  int startYear;
-
-  int endDay;
-
-  int endDayOfWeek;
-
-  int endMode;  // Seems to be JDK 1.2 only.
-
-  int endMonth;
+  /**
+   * The raw time zone offset in milliseconds to GMT, ignoring
+   * daylight savings.  
+   * @serial
+   */
+  private int rawOffset;
+
+  /**
+   * True, if this timezone uses daylight savings, false otherwise.
+   * @serial
+   */
+  private boolean useDaylight;
+
+  /**
+   * 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 our.
+   * @serial
+   * @since JDK1.1.4
+   */
+  private int dstSavings = 60 * 60 * 1000;
+
+  /**
+   * 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>
+   * <dt>DOM_MODE (1)</dt>
+   * <dd> startDay contains the day in month of the start date,
+   * startDayOfWeek is unused. </dd>
+   * <dt>DOW_IN_MONTH_MODE (2)</dt>
+   * <dd> The startDay gives the day of week in month, and
+   * startDayOfWeek the day of week.  For example startDay=2 and
+   * startDayOfWeek=Calender.SUNDAY specifies that the change is on
+   * the second sunday in that month.  You must make sure, that this
+   * day always exists (ie. don't specify the 5th sunday).
+   * </dd>
+   * <dt>DOW_GE_DOM_MODE (3)</dt>
+   * <dd> The start is on the first startDayOfWeek on or after
+   * startDay.  For example startDay=13 and
+   * startDayOfWeek=Calendar.FRIDAY specifies that the daylight
+   * savings start on the first FRIDAY on or after the 13th of that
+   * Month. Make sure that the change is always in the given month, or
+   * the result is undefined.
+   * </dd>
+   * <dt>DOW_LE_DOM_MONTH (4)</dt>
+   * <dd> The start is on the first startDayOfWeek on or before the
+   * startDay.  Make sure that the change is always in the given
+   * month, or the result is undefined.
+   </dd>
+   * </dl>
+   * @serial */
+  private int startMode;
+
+  /**
+   * The month in which daylight savings start.  This is one of the
+   * constants Calendar.JANUARY, ..., Calendar.DECEMBER.  
+   * @serial
+   */
+  private int startMonth;
+
+  /**
+   * 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 
+   * 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.  
+   * @serial
+   */
+  private int startTime;
+   
+  /**
+   * The month in which daylight savings ends.  This is one of the
+   * constants Calendar.JANUARY, ..., Calendar.DECEMBER.  
+   * @serial
+   */   
+  private int endMonth;
+
+  /**
+   * This variable gives the mode for the end of daylight savings rule.
+   * It can take the same values as startMode.
+   * @serial
+   * @see #startMode
+   */   
+  private int endMode;
+
+  /**
+   * This variable can have different meanings.  See startMode for details
+   * @serial
+   * @see #startMode;
+   */
+  private int endDay;
+  
+  /**
+   * 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.  
+   * @serial
+   */
+  private int endTime;
+
+  /**
+   * This variable points to a deprecated array from JDK 1.1.  It is
+   * ignored in JDK 1.2 but streamed out for compatibility with JDK 1.1.
+   * The array contains the lengths of the months in the year and is
+   * assigned from a private static final field to avoid allocating
+   * the array for every instance of the object.
+   * Note that static final fields are not serialized.
+   * @serial
+   */
+  private byte[] monthLength = monthArr;
+  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.
+   * <dl>
+   * <dt>0 or not present on stream</dt>
+   * <dd> JDK 1.1.3 or earlier, only provides this fields:
+   * rawOffset, startDay, startDayOfWeek, startMonth, startTime,
+   * startYear, endDay, endDayOfWeek, endMonth, endTime
+   * </dd>
+   * <dd> JDK 1.1.4 or later. This includes three new fields, namely
+   * startMode, endMode and dstSavings.  And there is a optional section
+   * as described in writeObject.
+   * </dd>
+   *
+   * XXX - JDK 1.2 Beta 4 docu states 1.1.4, but my 1.1.5 has the old
+   * version.
+   *
+   * When streaming out this class it is always written in the latest
+   * version.
+   * @serial
+   * @since JDK1.1.4 
+   */
+  private int serialVersionOnStream = 1;
+
+  private static final long serialVersionUID = -403250971215465050L;
+
+  /**
+   * Create a <code>SimpleTimeZone</code> with the given time offset
+   * from GMT and without daylight savings.  
+   * @param rawOffset the time offset from GMT in milliseconds.
+   * @param id The identifier of this time zone.  
+   */
+  public SimpleTimeZone(int rawOffset, String id)
+  {
+    this.rawOffset = rawOffset;
+    setID(id);
+    useDaylight = false;
+    startYear = 0;
+  }
+
+  /**
+   * 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 
+   * versions of jdk.
+   *
+   * <dl>
+   * <dt><code>day &gt; 0, dayOfWeek = Calendar.WEEKDAY</code></dt>
+   * <dd>The start/end of daylight savings is on the <code>day</code>-th
+   * <code>WEEKDAY</code> in the given month. </dd>
+   * <dt><code>day &lt; 0, dayOfWeek = Calendar.WEEKDAY</code></dt>
+   * <dd>The start/end of daylight savings is on the <code>-day</code>-th
+   * <code>WEEKDAY</code> counted from the <i>end</i> of the month. </dd>
+   * <dt><code>day &gt; 0, dayOfWeek = 0</code></dt>
+   * <dd>The start/end of daylight is on the <code>day</code>-th day of
+   * the month. </dd>
+   * <dt><code>day &gt; 0, dayOfWeek = -Calendar.WEEKDAY</code></dt>
+   * <dd>The start/end of daylight is on the first WEEKDAY on or after
+   * the <code>day</code>-th day of the month.  You must make sure that
+   * this day lies in the same month. </dd>
+   * <dt><code>day &lt; 0, dayOfWeek = -Calendar.WEEKDAY</code></dt>
+   * <dd>The start/end of daylight is on the first WEEKDAY on or
+   * <i>before</i> the <code>-day</code>-th day of the month.  You
+   * 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, 
+   * 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
+   * constants in Calendar.
+   * @param startday A day in month or a day of week number, as
+   * described above.
+   * @param startDayOfWeek The start rule day of week; see above.
+   * @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 
+   * described above.
+   * @param endDayOfWeek The end rule day of week; see above.
+   * @param endTime A time in millis in standard time.  */
+  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;
 
-  int endTime;
+    setStartRule(startMonth, startDayOfWeekInMonth,
+		 startDayOfWeek, startTime);
+    setEndRule(endMonth, endDayOfWeekInMonth, endDayOfWeek, endTime);
+    if (startMonth == endMonth)
+      throw new IllegalArgumentException
+	("startMonth and endMonth must be different");
+    this.startYear = 0;
+  }
+
+  /**
+   * This constructs a new SimpleTimeZone that supports a daylight savings
+   * rule.  The parameter are the same as for the constructor above, except
+   * there is the additional dstSavaings parameter.
+   *
+   * @param dstSavings the amount of savings for daylight savings
+   * time in milliseconds.  This must be positive.
+   */
+  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;
+  }
+
+  /**
+   * Sets the first year, where daylight savings applies.  The daylight
+   * savings rule never apply for years in the BC era.  Note that this
+   * is gregorian calendar specific.
+   * @param year the start year.
+   */
+  public void setStartYear(int year)
+  {
+    startYear = year;
+    useDaylight = true;
+  }
+
+  /**
+   * Checks if the month, day, dayOfWeek arguments are in range and
+   * returns the mode of the rule.
+   * @param month the month parameter as in the constructor
+   * @param day the day parameter as in the constructor
+   * @param dayOfWeek the day of week parameter as in the constructor
+   * @return the mode of this rule see startMode.
+   * @exception IllegalArgumentException if parameters are out of range.
+   * @see #SimpleTimeZone(int, String, int, int, int, int, int, int, int, int)
+   * @see #startMode
+   */
+  private int checkRule(int month, int day, int dayOfWeek)
+  {
+    int daysInMonth = getDaysInMonth(month, 1);
+    if (dayOfWeek == 0)
+      {
+	if (day <= 0 || day > daysInMonth)
+	  throw new IllegalArgumentException("day out of range");
+	return DOM_MODE;
+      }
+    else if (dayOfWeek > 0)
+      {
+	if (Math.abs(day) > (daysInMonth + 6) / 7)
+	  throw new IllegalArgumentException("dayOfWeekInMonth out of range");
+	if (dayOfWeek > Calendar.SATURDAY)
+	  throw new IllegalArgumentException("dayOfWeek out of range");
+	return DOW_IN_MONTH_MODE;
+      }
+    else
+      {
+	if (day == 0 || Math.abs(day) > daysInMonth)
+	  throw new IllegalArgumentException("day out of range");
+	if (dayOfWeek < -Calendar.SATURDAY)
+	  throw new IllegalArgumentException("dayOfWeek out of range");
+	if (day < 0)
+	  return DOW_LE_DOM_MODE;
+	else
+	  return DOW_GE_DOM_MODE;
+      }
+  }
 
-  // byte[] monthLength;
 
-  boolean useDaylight;
+  /**
+   * Sets the daylight savings start rule.  You must also set the
+   * end rule with <code>setEndRule</code> or the result of
+   * getOffset is undefined.  For the parameters see the ten-argument
+   * constructor above.
+   *
+   * @param month The month where daylight savings start, zero
+   * based.  You should use the constants in Calendar.
+   * @param day A day of month or day of week in month.
+   * @param dayOfWeek The day of week where daylight savings start.
+   * @param time The time in milliseconds standard time where daylight
+   * savings start.
+   * @see SimpleTimeZone */
+  public void setStartRule(int month, int day, int dayOfWeek, int time)
+  {
+    this.startMode = checkRule(month, day, dayOfWeek);
+    this.startMonth = month;
+    // FIXME: XXX: JDK 1.2 allows negative values and has 2 new variations
+    // of this method.
+    this.startDay = Math.abs(day);
+    this.startDayOfWeek = Math.abs(dayOfWeek);
+    this.startTime = time;
+    useDaylight = true;
+  }
 
-  public SimpleTimeZone (int rawOffset, String ID)
+  /**
+   * Sets the daylight savings end rule.  You must also set the
+   * start rule with <code>setStartRule</code> or the result of
+   * getOffset is undefined. For the parameters see the ten-argument
+   * constructor above.
+   *
+   * @param rawOffset The time offset from GMT.
+   * @param id  The identifier of this time zone.
+   * @param Month The end month of daylight savings.
+   * @param day A day in month, or a day of week in month.
+   * @param DayOfWeek A day of week, when daylight savings ends.
+   * @param Time A time in millis in standard time.
+   * @see #setStartRule */
+  public void setEndRule(int month, int day, int dayOfWeek, int time)
   {
-    setID(ID);
-    this.rawOffset = rawOffset;
+    this.endMode = checkRule(month, day, dayOfWeek);
+    this.endMonth = month;
+    // FIXME: XXX: JDK 1.2 allows negative values and has 2 new variations
+    // of this method.
+    this.endDay = Math.abs(day);
+    this.endDayOfWeek = Math.abs(dayOfWeek);
+    this.endTime = time;
+    useDaylight = true;
   }
+
+  /**
+   * 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.
+   *
+   * In the standard JDK the results given by this method may result in
+   * inaccurate results at the end of February or the beginning of March.
+   * To avoid this, you should use Calendar instead:
+   * <pre>
+   * offset = cal.get(Calendar.ZONE_OFFSET) + cal.get(Calendar.DST_OFFSET);
+   * </pre>
+   * You could also use in
+   *
+   * This version doesn't suffer this inaccuracy.
+   *
+   * @param era the era of the given date
+   * @param year the year of the given date
+   * @param month the month of the given date, 0 for January.
+   * @param day the day of month
+   * @param dayOfWeek the day of week; this must be matching the
+   * other fields.
+   * @param millis the millis in the day (in local standard time)
+   * @return the time zone offset in milliseconds.  */
+  public int getOffset(int era, int year, int month,
+		       int day, int dayOfWeek, int millis)
+  {
+    // This method is called by Calendar, so we mustn't use that class.
+    int daylightSavings = 0;
+    if (useDaylight && era == GregorianCalendar.AD && year >= startYear)
+      {
+	// This does only work for Gregorian calendars :-(
+	// This is mainly because setStartYear doesn't take an era.
 
-  public SimpleTimeZone (int rawOffset, String ID,
-			 int startMonth, int startDay,
-			 int startDayOfWeek, int startTime,
-			 int endMonth, int endDay,
-			 int endDayOfWeek, int endTime)
-  {
-    this(rawOffset, ID);
-    setStartRule (startMonth, startDay, startDayOfWeek, startTime);
-    setEndRule (endMonth, endDay, endDayOfWeek, endTime);
-  }
-
-  public int getRawOffset() { return rawOffset; }
-  public void setRawOffset (int offsetMillis) { rawOffset = offsetMillis; }
-
-  public int getOffset (int era, int year, int month, int day,
-			int dayOfWeek, int millis)
-  {
-    int offset = getRawOffset();
-    if (useDaylight)
-      {
-	if (startYear != 0
-	    && (year < startYear || era == GregorianCalendar.BC))
-	  return offset;
-	boolean midYearSummer = startMonth < endMonth;
-	if (midYearSummer ? (month < startMonth || month > endMonth)
-	    : (month < startMonth && month > endMonth))
-	  return offset; // Definitely not DST.
-	if (midYearSummer ? (month > startMonth && month < endMonth)
-	    : (month > startMonth || month < endMonth))
-	  return offset + dstSavings;  // Definitely DST.
-	// Now it gets more complicated.  Bail for now.
-	throw new Error("not implemented - SimpleTimeZone.getOffset");
+	boolean afterStart = !isBefore(year, month, day, dayOfWeek, millis,
+				       startMode, startMonth,
+				       startDay, startDayOfWeek, startTime);
+	boolean beforeEnd = isBefore(year, month, day, dayOfWeek, millis,
+				     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;
+	  }
+	else
+	  {
+	    // use daylight savings, if the date is before the end of
+	    // savings, or after the start of savings.
+	    daylightSavings = beforeEnd || afterStart ? dstSavings : 0;
+	  }
       }
-    return offset;
+    return rawOffset + daylightSavings;
   }
-
-  public boolean useDaylightTime() { return useDaylight; }
 
-  public boolean inDaylightTime(Date date)
+  /**
+   * Returns the time zone offset to GMT in milliseconds, ignoring
+   * day light savings.
+   * @return the time zone offset.  */
+  public int getRawOffset()
   {
-    if (! useDaylight)
-      return false;
-    throw new Error("not implemented - SimpleTimeZone.inDaylightTime");
+    return rawOffset;
   }
-
-  public int getDSTSavings () { return dstSavings; }
 
-  public void setDSTSavings (int millisSavedDuringDST)
-  { dstSavings = millisSavedDuringDST; }
+  /**
+   * Sets the standard time zone offset to GMT.
+   * @param rawOffset The time offset from GMT in milliseconds.
+   */
+  public void setRawOffset(int rawOffset)
+  {
+    this.rawOffset = rawOffset;
+  }
 
-  public void setStartRule (int month, int dayOfWeekInMonth,
-			    int dayOfWeek, int time)
+  /**
+   * Gets 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 our.
+   * @return the daylight savings offset in milliseconds.
+   * @since JDK1.1.4?
+   */
+  public int getDSTSavings()
+  {
+    return dstSavings;
+  }
+
+  /**
+   * Returns if this time zone uses daylight savings time.
+   * @return true, if we use daylight savings time, false otherwise.
+   */
+  public boolean useDaylightTime()
+  {
+    return useDaylight;
+  }
+
+  /**
+   * Returns the number of days in the given month.  It does always
+   * use the Gregorian leap year rule.  
+   * @param month The month, zero based; use one of the Calendar constants.
+   * @param year  The year.
+   */
+  private int getDaysInMonth(int month, int year)
   {
-    this.startMonth = month;
-    this.startDay = dayOfWeekInMonth;
-    this.startDayOfWeek = dayOfWeek;
-    this.startTime = time;
-    this.useDaylight = true;
+    // Most of this is copied from GregorianCalendar.getActualMaximum()
+    if (month == Calendar.FEBRUARY)
+      {
+	return ((year & 3) == 0 && (year % 100 != 0 || year % 400 == 0))
+	  ? 29 : 28;
+      }
+    else if (month < Calendar.AUGUST)
+        return 31 - (month & 1);
+    else
+      return 30 + (month & 1);
+  }
+
+  /**
+   * Checks if the date given in calXXXX, is before the change between
+   * dst and standard time.
+   * @param calYear the year of the date to check (for leap day cheking).
+   * @param calMonth the month of the date to check.
+   * @param calDay the day of month of the date to check.
+   * @param calDayOfWeek the day of week of the date to check.
+   * @param calMillis the millis of day of the date to check (standard time).
+   * @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 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)
+  {
+
+    // 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.
+    if (calMonth != month)
+      return calMonth < month;
+
+    // check the day:
+    switch (mode)
+      {
+      case DOM_MODE:
+	if (calDayOfMonth != day)
+	  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);
+
+	  // Now we convert it to 7 based number (to get a one based offset
+	  // 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
+	    calDayOfMonth += 6;
+
+	  //  day > 0                    day < 0
+	  //  S  M  T  W  T  F  S        S  M  T  W  T  F  S
+	  //     7  8  9 10 11 12         -36-35-34-33-32-31
+	  // 13 14 15 16 17 18 19      -30-29-28-27-26-25-24
+	  // 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
+	  //  1  2  2  2  2  2  2       -4 -4 -4 -3 -3 -3 -3
+	  //  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;
+
+	  if (calDayOfWeek != dayOfWeek)
+	    return calDayOfWeek < dayOfWeek;
+
+	  // 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 -= 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;
+	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);
   }
 
-  public void setEndRule (int month, int dayOfWeekInMonth,
-			    int dayOfWeek, int time)
+  /**
+   * Determines if the given date is in daylight savings time.
+   * @return true, if it is in daylight savings time, false otherwise.
+   */
+  public boolean inDaylightTime(Date date)
   {
-    this.endMonth = month;
-    this.endDay = dayOfWeekInMonth;
-    this.endDayOfWeek = dayOfWeek;
-    this.endTime = time;
-    this.useDaylight = true;
+    Calendar cal = Calendar.getInstance(this);
+    cal.setTime(date);
+    return (cal.get(Calendar.DST_OFFSET) != 0);
   }
 
-  public void setStartYear (int year)
+  /**
+   * Generates the hashCode for the SimpleDateFormat object.  It is
+   * the rawOffset, possibly, if useDaylightSavings is true, xored
+   * with startYear, startMonth, startDayOfWeekInMonth, ..., endTime.  
+   */
+  public synchronized int hashCode()
   {
-    this.startYear = startYear;
+    return rawOffset ^
+      (useDaylight ?
+       startMonth ^ startDay ^ startDayOfWeek ^ startTime
+       ^ endMonth ^ endDay ^ endDayOfWeek ^ endTime : 0);
   }
 
-  public boolean hasSameRules (TimeZone other)
+  public synchronized boolean equals(Object o)
   {
-    if (this == other)
+    if (this == o)
       return true;
-    if (! (other instanceof SimpleTimeZone))
-      return false;
-    SimpleTimeZone o = (SimpleTimeZone) other;
-    if (rawOffset != o.rawOffset)
+    if (!(o instanceof SimpleTimeZone))
       return false;
-    if (useDaylight != o.useDaylight)
+    SimpleTimeZone zone = (SimpleTimeZone) o;
+    if (zone.hashCode() != hashCode()
+	|| !getID().equals(zone.getID())
+	|| rawOffset != zone.rawOffset || useDaylight != zone.useDaylight)
       return false;
-    if (! useDaylight)
+    if (!useDaylight)
       return true;
-    return startDay == o.startDay
-      && startDayOfWeek == o.startDayOfWeek
-      && startMonth == o.startMonth
-      && startTime == o.startTime
-      && endDay == o.endDay
-      && endDayOfWeek == o.endDayOfWeek
-      && endMonth == o.endMonth
-      && endTime == o.endTime
-      && startYear == o.startYear
-      && startMode == o.startMode
-      && endMode == o.endMode;
-  }
-
-  public boolean equals (Object obj)
+    return (startYear == zone.startYear
+	    && startMonth == zone.startMonth
+	    && startDay == zone.startDay
+	    && startDayOfWeek == zone.startDayOfWeek
+	    && startTime == zone.startTime
+	    && endMonth == zone.endMonth
+	    && endDay == zone.endDay
+	    && endDayOfWeek == zone.endDayOfWeek
+	    && endTime == zone.endTime);
+  }
+
+  /**
+   * Test if the other time zone uses the same rule and only
+   * possibly differs in ID.  This implementation for this particular
+   * class will return true if the other object is a SimpleTimeZone,
+   * the raw offsets and useDaylight are identical and if useDaylight
+   * is true, also the start and end datas are identical.
+   * @return true if this zone uses the same rule.
+   */
+  public boolean hasSameRules(TimeZone other)
   {
-    if (! (obj instanceof SimpleTimeZone))
+    if (this == other)
+      return true;
+    if (!(other instanceof SimpleTimeZone))
       return false;
-    SimpleTimeZone other = (SimpleTimeZone) obj;
-    return getID() == other.getID() && hasSameRules(other);
-  }
-
-  public Object clone ()
+    SimpleTimeZone zone = (SimpleTimeZone) other;
+    if (zone.hashCode() != hashCode()
+	|| rawOffset != zone.rawOffset || useDaylight != zone.useDaylight)
+      return false;
+    if (!useDaylight)
+      return true;
+    return (startYear == zone.startYear
+	    && startMonth == zone.startMonth
+	    && startDay == zone.startDay
+	    && startDayOfWeek == zone.startDayOfWeek
+	    && startTime == zone.startTime
+	    && endMonth == zone.endMonth
+	    && endDay == zone.endDay
+	    && endDayOfWeek == zone.endDayOfWeek && endTime == zone.endTime);
+  }
+
+  /**
+   * Returns a string representation of this SimpleTimeZone object.
+   * @return a string representation of this SimpleTimeZone object.
+   */
+  public String toString()
+  {
+    // 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
+	 + ",endMode=" + endMode
+	 + ",endMonth=" + endMonth
+	 + ",endDay=" + endDay
+	 + ",endDayOfWeek=" + endDayOfWeek
+	 + ",endTime=" + endTime : "") + "]";
+  }
+
+  /**
+   * Reads a serialized simple time zone from stream.
+   * @see #writeObject
+   */
+  private void readObject(java.io.ObjectInputStream input)
+    throws java.io.IOException, ClassNotFoundException
   {
-    // We know the superclass just call's Object's generic cloner.
-    return super.clone ();
+    input.defaultReadObject();
+    if (serialVersionOnStream == 0)
+      {
+	// initialize the new fields to default values.
+	dstSavings = 60 * 60 * 1000;
+	endMode = DOW_IN_MONTH_MODE;
+	startMode = DOW_IN_MONTH_MODE;
+	serialVersionOnStream = 1;
+      }
+    else
+      {
+	int length = input.readInt();
+	byte[]byteArray = new byte[length];
+	input.read(byteArray, 0, length);
+	if (length >= 4)
+	  {
+	    // Lets hope that Sun does extensions to the serialized
+	    // form in a sane manner.
+	    startDay = byteArray[0];
+	    startDayOfWeek = byteArray[1];
+	    endDay = byteArray[2];
+	    endDayOfWeek = byteArray[3];
+	  }
+      }
   }
+
+  /**
+   * Serializes this object to a stream.  @serialdata The object is
+   * first written in the old JDK 1.1 format, so that it can be read
+   * by by the old classes.  This means, that the
+   * <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.  
+   */
+  private void writeObject(java.io.ObjectOutputStream output)
+    throws java.io.IOException
+  {
+    byte[] byteArray = new byte[]
+    {
+      (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
+      case DOW_GE_DOM_MODE:
+      case DOW_LE_DOM_MODE:
+	startDay = (startDay + 6) / 7;
+      }
+    switch (endMode)
+      {
+      case DOM_MODE:
+	endDayOfWeek = Calendar.SUNDAY;
+	// fall through
+      case DOW_GE_DOM_MODE:
+      case DOW_LE_DOM_MODE:
+	endDay = (endDay + 6) / 7;
+      }
 
-  public String toString ()
-  {
-    // The docs don't say much about how we might implement this.
-    // We choose a debugging implementation.
-    return ("dstSavings " + dstSavings
-	    + "; rawOffset " + rawOffset
-	    + "; startDay " + startDay
-	    + "; startDayOfWeek " + startDayOfWeek
-	    + "; startMode " + startMode
-	    + "; startMonth " + startMonth
-	    + "; startTime " + startTime
-	    + "; startYear " + startYear
-	    + "; endDay " + endDay
-	    + "; endDayOfWeek " + endDayOfWeek
-	    + "; endMode " + endMode
-	    + "; endMonth " + endMonth
-	    + "; endTime " + endTime
-	    + "; useDaylight " + useDaylight);
-  }
-
-  public int hashCode ()
-  {
-    // FIXME - this does not folow any spec (since none is public)!
-    int hash = rawOffset;
-    if (useDaylight)
-      hash += dstSavings + startYear + startMode + endMode
-	+ startDay + startDayOfWeek + startMonth + startTime
-	+ endDay + endDayOfWeek + endMonth + endTime;
-    return hash;
+    // the required part:
+    output.defaultWriteObject();
+    // the optional part:
+    output.writeInt(byteArray.length);
+    output.write(byteArray, 0, byteArray.length);
   }
 }


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]