aboutsummaryrefslogtreecommitdiff
path: root/libjava
diff options
context:
space:
mode:
authortromey <tromey@138bc75d-0d04-0410-961f-82ee72b054a4>2001-05-10 18:13:17 +0000
committertromey <tromey@138bc75d-0d04-0410-961f-82ee72b054a4>2001-05-10 18:13:17 +0000
commitfcd5d3ed60dbef4a7ffc14dd032948b748adcc07 (patch)
treebe72e5f9af087633db647f380105f2fe59d2eb9e /libjava
parent8195e9cad8cebaaf1edaef7a2ab381111b872c8c (diff)
2001-05-10 Tom Tromey <tromey@redhat.com>
* java/util/GregorianCalendar.java: Imported from Classpath. * gnu/java/locale/LocaleInformation_nl.java: New file from Classpath. * gnu/java/locale/LocaleInformation_en.java: Likewise. * gnu/java/locale/LocaleInformation_de.java: Likewise. * gnu/java/locale/LocaleInformation.java: Likewise. * natGregorianCalendar.cc: Removed. * Makefile.in: Rebuilt. * Makefile.am (nat_source_files): Removed natGregorianCalendar.cc. 2001-05-10 Tom Tromey <tromey@redhat.com> * java/text/SimpleDateFormat.java (computeCenturyStart): New method. (defaultCenturyStart): Use it. (readObject): Likewise. (SimpleDateFormat): Clear the calendar. Set the grouping on the number format. (parse): Copy the calendar before modifying it. Correctly handle the time zone. * java/util/Calendar.java (clear): Set field value(s) to 0. 2001-05-10 Jeff Sturm <jsturm@one-point.com> * Calendar.java (get): Clear areFieldsSet if requested field is not set. (set): Unset fields that depend on new value. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@41942 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'libjava')
-rw-r--r--libjava/ChangeLog32
-rw-r--r--libjava/Makefile.am1
-rw-r--r--libjava/Makefile.in64
-rw-r--r--libjava/gnu/java/locale/LocaleInformation.java37
-rw-r--r--libjava/gnu/java/locale/LocaleInformation_de.java220
-rw-r--r--libjava/gnu/java/locale/LocaleInformation_en.java332
-rw-r--r--libjava/gnu/java/locale/LocaleInformation_nl.java338
-rw-r--r--libjava/java/text/SimpleDateFormat.java62
-rw-r--r--libjava/java/util/Calendar.java65
-rw-r--r--libjava/java/util/GregorianCalendar.java1174
-rw-r--r--libjava/java/util/natGregorianCalendar.cc159
11 files changed, 2085 insertions, 399 deletions
diff --git a/libjava/ChangeLog b/libjava/ChangeLog
index 5a95e2fc84d..c803cd672b0 100644
--- a/libjava/ChangeLog
+++ b/libjava/ChangeLog
@@ -1,3 +1,35 @@
+2001-05-10 Tom Tromey <tromey@redhat.com>
+
+ * java/util/GregorianCalendar.java: Imported from Classpath.
+ * gnu/java/locale/LocaleInformation_nl.java: New file from
+ Classpath.
+ * gnu/java/locale/LocaleInformation_en.java: Likewise.
+ * gnu/java/locale/LocaleInformation_de.java: Likewise.
+ * gnu/java/locale/LocaleInformation.java: Likewise.
+ * natGregorianCalendar.cc: Removed.
+ * Makefile.in: Rebuilt.
+ * Makefile.am (nat_source_files): Removed
+ natGregorianCalendar.cc.
+
+2001-05-10 Tom Tromey <tromey@redhat.com>
+
+ * java/text/SimpleDateFormat.java (computeCenturyStart): New
+ method.
+ (defaultCenturyStart): Use it.
+ (readObject): Likewise.
+ (SimpleDateFormat): Clear the calendar. Set the grouping on the
+ number format.
+ (parse): Copy the calendar before modifying it. Correctly handle
+ the time zone.
+
+ * java/util/Calendar.java (clear): Set field value(s) to 0.
+
+2001-05-10 Jeff Sturm <jsturm@one-point.com>
+
+ * Calendar.java (get): Clear areFieldsSet if requested field
+ is not set.
+ (set): Unset fields that depend on new value.
+
2001-05-06 Bryce McKinlay <bryce@waitaki.otago.ac.nz>
* java/lang/Class.h (_Jv_Self): New union type.
diff --git a/libjava/Makefile.am b/libjava/Makefile.am
index 0a61a4f998f..d5644a1590d 100644
--- a/libjava/Makefile.am
+++ b/libjava/Makefile.am
@@ -1335,7 +1335,6 @@ java/net/natInetAddress.cc \
java/net/natPlainDatagramSocketImpl.cc \
java/net/natPlainSocketImpl.cc \
java/text/natCollator.cc \
-java/util/natGregorianCalendar.cc \
java/util/zip/natDeflater.cc \
java/util/zip/natInflater.cc
diff --git a/libjava/Makefile.in b/libjava/Makefile.in
index b191f8602e5..d4435b6d8d3 100644
--- a/libjava/Makefile.in
+++ b/libjava/Makefile.in
@@ -73,6 +73,7 @@ CXXCPP = @CXXCPP@
DIRLTDL = @DIRLTDL@
DIVIDESPEC = @DIVIDESPEC@
DLLTOOL = @DLLTOOL@
+EXCEPTIONSPEC = @EXCEPTIONSPEC@
EXEEXT = @EXEEXT@
GCDEPS = @GCDEPS@
GCINCS = @GCINCS@
@@ -119,29 +120,43 @@ here = @here@
libgcj_basedir = @libgcj_basedir@
AUTOMAKE_OPTIONS = foreign
-@TESTSUBDIR_TRUE@SUBDIRS = @TESTSUBDIR_TRUE@$(DIRLTDL) testsuite gcj include
-@TESTSUBDIR_FALSE@SUBDIRS = @TESTSUBDIR_FALSE@$(DIRLTDL) gcj include
-@USE_LIBDIR_TRUE@toolexeclibdir = @USE_LIBDIR_TRUE@$(libdir)$(MULTISUBDIR)
-@USE_LIBDIR_FALSE@toolexeclibdir = @USE_LIBDIR_FALSE@$(toolexecdir)/lib$(MULTISUBDIR)
-@USE_LIBDIR_FALSE@toolexecdir = @USE_LIBDIR_FALSE@$(exec_prefix)/$(target_alias)
-@XLIB_AWT_TRUE@cond_x_ltlibrary = @XLIB_AWT_TRUE@libgcjx.la
-@XLIB_AWT_FALSE@cond_x_ltlibrary =
+@TESTSUBDIR_TRUE@SUBDIRS = \
+@TESTSUBDIR_TRUE@$(DIRLTDL) testsuite gcj include
+@TESTSUBDIR_FALSE@SUBDIRS = \
+@TESTSUBDIR_FALSE@$(DIRLTDL) gcj include
+@USE_LIBDIR_TRUE@toolexeclibdir = \
+@USE_LIBDIR_TRUE@$(libdir)$(MULTISUBDIR)
+@USE_LIBDIR_FALSE@toolexeclibdir = \
+@USE_LIBDIR_FALSE@$(toolexecdir)/lib$(MULTISUBDIR)
+@USE_LIBDIR_FALSE@toolexecdir = \
+@USE_LIBDIR_FALSE@$(exec_prefix)/$(target_alias)
+@XLIB_AWT_TRUE@cond_x_ltlibrary = \
+@XLIB_AWT_TRUE@libgcjx.la
+@XLIB_AWT_FALSE@cond_x_ltlibrary = \
toolexeclib_LTLIBRARIES = libgcj.la $(cond_x_ltlibrary)
toolexeclib_DATA = libgcj.spec
data_DATA = libgcj.jar
-@NEEDS_DATA_START_TRUE@toolexeclib_LIBRARIES = @NEEDS_DATA_START_TRUE@libgcjdata.a
-@NEEDS_DATA_START_TRUE@libgcjdata_a_SOURCES = @NEEDS_DATA_START_TRUE@libgcjdata.c
+@NEEDS_DATA_START_TRUE@toolexeclib_LIBRARIES = \
+@NEEDS_DATA_START_TRUE@libgcjdata.a
+@NEEDS_DATA_START_TRUE@libgcjdata_a_SOURCES = \
+@NEEDS_DATA_START_TRUE@libgcjdata.c
-@NATIVE_TRUE@bin_PROGRAMS = @NATIVE_TRUE@jv-convert gij
+@NATIVE_TRUE@bin_PROGRAMS = \
+@NATIVE_TRUE@jv-convert gij
bin_SCRIPTS = addr2name.awk
-@CANADIAN_TRUE@@NULL_TARGET_TRUE@ZIP = @CANADIAN_TRUE@@NULL_TARGET_TRUE@$(MULTIBUILDTOP)../$(COMPPATH)/fastjar/fastjar$(EXEEXT)
-@CANADIAN_TRUE@@NULL_TARGET_FALSE@ZIP = @CANADIAN_TRUE@@NULL_TARGET_FALSE@fastjar
-@CANADIAN_FALSE@ZIP = @CANADIAN_FALSE@$(MULTIBUILDTOP)../$(COMPPATH)/fastjar/fastjar$(EXEEXT)
-@CANADIAN_TRUE@GCJH = @CANADIAN_TRUE@gcjh
-@CANADIAN_FALSE@GCJH = @CANADIAN_FALSE@$(MULTIBUILDTOP)../$(COMPPATH)/gcc/gcjh$(EXEEXT)
+@CANADIAN_TRUE@@NULL_TARGET_TRUE@ZIP = \
+@CANADIAN_TRUE@@NULL_TARGET_TRUE@$(MULTIBUILDTOP)../$(COMPPATH)/fastjar/fastjar$(EXEEXT)
+@CANADIAN_TRUE@@NULL_TARGET_FALSE@ZIP = \
+@CANADIAN_TRUE@@NULL_TARGET_FALSE@fastjar
+@CANADIAN_FALSE@ZIP = \
+@CANADIAN_FALSE@$(MULTIBUILDTOP)../$(COMPPATH)/fastjar/fastjar$(EXEEXT)
+@CANADIAN_TRUE@GCJH = \
+@CANADIAN_TRUE@gcjh
+@CANADIAN_FALSE@GCJH = \
+@CANADIAN_FALSE@$(MULTIBUILDTOP)../$(COMPPATH)/gcc/gcjh$(EXEEXT)
GCJ_WITH_FLAGS = $(GCJ) --encoding=UTF-8
@@ -160,8 +175,10 @@ AM_CXXFLAGS = -fno-rtti -fvtable-thunks -fnon-call-exceptions \
-fdollars-in-identifiers \
@LIBGCJ_CXXFLAGS@ @X_CFLAGS@ $(WARNINGS) -D_GNU_SOURCE
-@USING_GCC_TRUE@AM_CFLAGS = @USING_GCC_TRUE@@LIBGCJ_CFLAGS@ $(WARNINGS)
-@USING_GCC_FALSE@AM_CFLAGS = @USING_GCC_FALSE@@LIBGCJ_CFLAGS@
+@USING_GCC_TRUE@AM_CFLAGS = \
+@USING_GCC_TRUE@@LIBGCJ_CFLAGS@ $(WARNINGS)
+@USING_GCC_FALSE@AM_CFLAGS = \
+@USING_GCC_FALSE@@LIBGCJ_CFLAGS@
JCFLAGS = -g
JC1FLAGS = @LIBGCJ_JAVAFLAGS@ $(GCJFLAGS)
@@ -229,7 +246,8 @@ extra_headers = java/lang/Object.h java/lang/Class.h
NM = nm
-@NATIVE_TRUE@@MAINTAINER_MODE_TRUE@noinst_PROGRAMS = @NATIVE_TRUE@@MAINTAINER_MODE_TRUE@gen-from-JIS
+@NATIVE_TRUE@@MAINTAINER_MODE_TRUE@noinst_PROGRAMS = \
+@NATIVE_TRUE@@MAINTAINER_MODE_TRUE@gen-from-JIS
CONVERT_DIR = gnu/gcj/convert
@@ -1060,7 +1078,6 @@ java/net/natInetAddress.cc \
java/net/natPlainDatagramSocketImpl.cc \
java/net/natPlainSocketImpl.cc \
java/text/natCollator.cc \
-java/util/natGregorianCalendar.cc \
java/util/zip/natDeflater.cc \
java/util/zip/natInflater.cc
@@ -1212,8 +1229,7 @@ java/lang/reflect/natArray.lo java/lang/reflect/natConstructor.lo \
java/lang/reflect/natField.lo java/lang/reflect/natMethod.lo \
java/net/natInetAddress.lo java/net/natPlainDatagramSocketImpl.lo \
java/net/natPlainSocketImpl.lo java/text/natCollator.lo \
-java/util/natGregorianCalendar.lo java/util/zip/natDeflater.lo \
-java/util/zip/natInflater.lo
+java/util/zip/natDeflater.lo java/util/zip/natInflater.lo
libgcjx_la_OBJECTS = gnu/gcj/xlib/natClip.lo \
gnu/gcj/xlib/natColormap.lo gnu/gcj/xlib/natDisplay.lo \
gnu/gcj/xlib/natDrawable.lo gnu/gcj/xlib/natFont.lo \
@@ -1813,8 +1829,8 @@ DEP_FILES = .deps/$(srcdir)/$(CONVERT_DIR)/gen-from-JIS.P \
.deps/java/util/jar/JarEntry.P .deps/java/util/jar/JarException.P \
.deps/java/util/jar/JarFile.P .deps/java/util/jar/JarInputStream.P \
.deps/java/util/jar/JarOutputStream.P .deps/java/util/jar/Manifest.P \
-.deps/java/util/natGregorianCalendar.P .deps/java/util/zip/Adler32.P \
-.deps/java/util/zip/CRC32.P .deps/java/util/zip/CheckedInputStream.P \
+.deps/java/util/zip/Adler32.P .deps/java/util/zip/CRC32.P \
+.deps/java/util/zip/CheckedInputStream.P \
.deps/java/util/zip/CheckedOutputStream.P \
.deps/java/util/zip/Checksum.P \
.deps/java/util/zip/DataFormatException.P \
@@ -2199,7 +2215,7 @@ distdir: $(DISTFILES)
@for file in $(DISTFILES); do \
d=$(srcdir); \
if test -d $$d/$$file; then \
- cp -pr $$d/$$file $(distdir)/$$file; \
+ cp -pr $$/$$file $(distdir)/$$file; \
else \
test -f $(distdir)/$$file \
|| ln $$d/$$file $(distdir)/$$file 2> /dev/null \
diff --git a/libjava/gnu/java/locale/LocaleInformation.java b/libjava/gnu/java/locale/LocaleInformation.java
new file mode 100644
index 00000000000..452820a18f6
--- /dev/null
+++ b/libjava/gnu/java/locale/LocaleInformation.java
@@ -0,0 +1,37 @@
+/* LocaleInformation.java -- Default locale information
+ 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. */
+
+
+package gnu.java.locale;
+
+/**
+ * This is the resource bundle for the default locale, which right now is
+ * hardcoded to US English.
+ */
+public class LocaleInformation extends LocaleInformation_en
+{
+}
+
diff --git a/libjava/gnu/java/locale/LocaleInformation_de.java b/libjava/gnu/java/locale/LocaleInformation_de.java
new file mode 100644
index 00000000000..5eea9057cf4
--- /dev/null
+++ b/libjava/gnu/java/locale/LocaleInformation_de.java
@@ -0,0 +1,220 @@
+/* LocaleInformation_de.java -- German 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 the German locale
+ * @author Jochen Hoenicke
+ */
+public class LocaleInformation_de extends ListResourceBundle
+{
+
+/*
+ * This area is used for defining object values
+ */
+
+/**
+ * This is the set of collation rules used by java.text.RuleBasedCollator
+ * to sort strings properly. See the documentation of that class for the
+ * proper format.
+ */
+private static final String collation_rules =
+ "-<0,1<2<3<4<5<6<7<8<9<A,a<b,B<c,C<d,D<e,E<f,F<g,G<h,H<i,I<j,J<j,K" +
+ "<l,L<m,M<n,N<o,O<p,P<q,Q<r,R<s,S<t,T<u,U<v,V<w,W<x,X<y,Y,z<Z" +
+ "&ae,\u00e4&Ae,\u00c4&oe,\u00f6&Oe,\u00d6&ue,\u00fc&Ue,\u00dc&ss,\u00df";
+
+/**
+ * This is the list of months, fully spelled out
+ */
+private static final String[] months = { "Januar", "Februar", "M\u00e4rz",
+ "April", "Mai", "Juni", "Juli", "August", "September", "Oktober",
+ "November", "Dezember", null };
+
+/**
+ * This is the list of abbreviated month names
+ */
+private static final String[] shortMonths = {
+ "Jan", "Feb", "M\u00e4r", "Apr", "Mai",
+ "Jun", "Jul", "Aug", "Sep", "Okt", "Nov", "Dez", null
+};
+
+/**
+ * This is the list of weekdays, fully spelled out
+ */
+private static final String[] weekdays = {
+ null, "Sonntag", "Montag", "Dienstag",
+ "Mittwoch", "Donnerstag", "Freitag", "Samstag"
+};
+
+/**
+ * This is the list of abbreviated weekdays
+ */
+private static final String[] shortWeekdays = {
+ null, "So", "Mo", "Di", "Mi", "Do", "Fr", "Sa"
+};
+
+/**
+ * This is the list of era identifiers
+ */
+private static final String[] eras = { "v. Chr.", "n. Chr." };
+
+/**
+ * This is the list of timezone strings. The JDK appears to include a
+ * city name as the sixth element.
+ */
+private static final String[][] zoneStrings =
+{
+ // European time zones. The city names are a little bit random.
+ { "WET", "Westeurop\u00e4ische Zeit", "WEZ", "Westeurop\u00e4ische Sommerzeit", "WESZ", "London" },
+ { "CET", "Mitteleurop\u00e4ische Zeit", "MEZ", "Mitteleurop\u00e4ische Sommerzeit", "MESZ", "Berlin" },
+ { "EET", "Osteurop\u00e4ische Zeit", "OEZ", "Mitteleurop\u00e4ische Sommerzeit", "OESZ", "Istanbul" },
+};
+
+/**
+ * This is the DateFormat.SHORT date format
+ */
+private static final String shortDateFormat = "dd.MM.yy";
+
+/**
+ * This is the DateFormat.MEDIUM format
+ */
+private static final String mediumDateFormat = "d. MMM yy";
+
+/**
+ * This is the DateFormat.LONG format
+ */
+private static final String longDateFormat = "d. MMMM yyyy";
+
+/**
+ * This is the DateFormat.FULL format
+ */
+private static final String fullDateFormat = "EEEE, d. MMMM yyyy";
+
+/**
+ * This is the DateFormat.DEFAULT format
+ */
+private static final String defaultDateFormat = "dd.MM.yy";
+
+/**
+ * This is the DateFormat.SHORT format
+ */
+private static final String shortTimeFormat = "H:mm";
+
+/**
+ * This is the DateFormat.MEDIUM format
+ */
+private static final String mediumTimeFormat = "H:mm:ss";
+
+/**
+ * This is the DateFormat.LONG format
+ */
+private static final String longTimeFormat = "H:mm:ss z";
+
+/**
+ * This is the DateFormat.FULL format
+ */
+private static final String fullTimeFormat = "H:mm:ss 'Uhr' z";
+
+/**
+ * This is the DateFormat.DEFAULT format
+ */
+private static final String defaultTimeFormat = "H:mm:ss";
+
+/**
+ * This is the currency symbol
+ */
+private static final String currencySymbol = "DM";
+
+/**
+ * This is the international currency symbol.
+ */
+private static final String intlCurrencySymbol = "DEM";
+
+/**
+ * This is the decimal point.
+ */
+private static final String decimalSeparator = ",";
+
+/**
+ * This is the decimal separator in monetary values.
+ */
+private static final String monetarySeparator = ",";
+
+/*************************************************************************/
+
+/**
+ * This is the object array used to hold the keys and values
+ * for this bundle
+ */
+
+private static final Object[][] contents =
+{
+ // For RuleBasedCollator
+ { "collation_rules", collation_rules },
+ // For SimpleDateFormat/DateFormatSymbols
+ { "months", months },
+ { "shortMonths", shortMonths },
+ { "weekdays", weekdays },
+ { "shortWeekdays", shortWeekdays },
+ { "eras", eras },
+ { "zoneStrings", zoneStrings },
+ { "shortDateFormat", shortDateFormat },
+ { "mediumDateFormat", mediumDateFormat },
+ { "longDateFormat", longDateFormat },
+ { "fullDateFormat", fullDateFormat },
+ { "defaultDateFormat", defaultDateFormat },
+ { "shortTimeFormat", shortTimeFormat },
+ { "mediumTimeFormat", mediumTimeFormat },
+ { "longTimeFormat", longTimeFormat },
+ { "fullTimeFormat", fullTimeFormat },
+ { "defaultTimeFormat", defaultTimeFormat },
+ // For DecimalFormat/DecimalFormatSymbols
+ { "currencySymbol", currencySymbol },
+ { "intlCurrencySymbol", intlCurrencySymbol },
+ { "decimalSeparator", decimalSeparator },
+ { "monetarySeparator", monetarySeparator },
+};
+
+/*************************************************************************/
+
+/**
+ * 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);
+}
+
+} // class LocaleInformation_de
diff --git a/libjava/gnu/java/locale/LocaleInformation_en.java b/libjava/gnu/java/locale/LocaleInformation_en.java
new file mode 100644
index 00000000000..22e7371e52a
--- /dev/null
+++ b/libjava/gnu/java/locale/LocaleInformation_en.java
@@ -0,0 +1,332 @@
+/* LocaleInformation_en.java -- US English locale data
+ Copyright (C) 1998, 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;
+import java.util.Date;
+
+/**
+ * This class contains locale data for the US English locale
+ */
+
+public class LocaleInformation_en extends ListResourceBundle
+{
+
+/*
+ * This area is used for defining object values
+ */
+
+/**
+ * This is the set of collation rules used by java.text.RuleBasedCollator
+ * to sort strings properly. See the documentation of that class for the
+ * proper format.
+ */
+private static final String collation_rules =
+ "-<0,1<2<3<4<5<6<7<8<9A,a<b,B<c,C<d,D<e,E<f,F<g,G<h,H<i,I<j,J<j,K" +
+ "<l,L<m,M<n,N<o,O<p,P<q,Q<r,R<s,S<t,T<u,U<v,V<w,W<x,X<y,Y,z<Z";
+
+/*
+ * For the followings lists, strings that are subsets of other break strigns
+ * must be listed first. For example, if "\r" and "\r\n" are sequences,
+ * the "\r" must be first or it will never be used.
+ */
+
+/**
+ * This is the list of word separator characters used by
+ * java.text.BreakIterator
+ */
+private static final String[] word_breaks = { " ", "\t", "\r\n", "\n" };
+
+/**
+ * This is the list of sentence break sequences used by
+ * java.text.BreakIterator
+ */
+private static final String[] sentence_breaks = { ". " };
+
+/**
+ * This is the list of potential line break locations.
+ */
+private static final String[] line_breaks = { "\t", "-", "\r\n",
+ "\n", ". ", ". ", ".", "? ", "? ", "?", "! ", "! ", "!", ", ", " " };
+
+/**
+ * This is the list of months, fully spelled out
+ */
+private static final String[] months = { "January", "February", "March",
+ "April", "May", "June", "July", "August", "September", "October",
+ "November", "December", null };
+
+/**
+ * This is the list of abbreviated month names
+ */
+private static final String[] shortMonths = { "Jan", "Feb", "Mar", "Apr", "May",
+ "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", null };
+
+/**
+ * This is the list of weekdays, fully spelled out
+ */
+private static final String[] weekdays = { null, "Sunday", "Monday", "Tuesday",
+ "Wednesday", "Thursday", "Friday", "Saturday" };
+
+/**
+ * This is the list of abbreviated weekdays
+ */
+private static final String[] shortWeekdays = { null, "Sun", "Mon", "Tue", "Wed",
+ "Thu", "Fri", "Sat" };
+
+/**
+ * This is the list of AM/PM strings
+ */
+private static final String[] ampms = { "AM", "PM" };
+
+/**
+ * This is the list of era identifiers
+ */
+private static final String[] eras = { "BC", "AD" };
+
+/**
+ * This is the list of timezone strings. The JDK appears to include a
+ * city name as the sixth element.
+ */
+private static final String[][] zoneStrings =
+{
+ { "EST6EDT", "Eastern Standard Time", "EST", "Eastern Daylight Time", "EDT",
+ "New York" },
+ { "EST6", "Eastern Standard Time", "EST", "Eastern Standard Time", "EST",
+ "Indianapolis" },
+ { "CST6CDT", "Central Standard Time", "CST", "Central Daylight Time", "CDT",
+ "Chicago" },
+ { "MST6MDT", "Mountain Standard Time", "MST", "Mountain Daylight Time",
+ "MDT", "Denver" },
+ { "MST6", "Mountain Standard Time", "MST", "Mountain Standard Time", "MST",
+ "Phoenix" },
+ { "PST6PDT", "Pacific Standard Time", "PDT", "Pacific Daylight Time", "PDT",
+ "San Francisco" },
+ { "AST6ADT", "Alaska Standard Time", "AST", "Alaska Daylight Time", "ADT",
+ "Anchorage" },
+ { "HST6HDT", "Hawaii Standard Time", "HST", "Hawaii Daylight Time", "HDT",
+ "Honolulu" },
+ // European time zones. The city names are a little bit random.
+ { "WET", "Western European Time", "WET", "Western European Savings Time", "WEST", "London" },
+ { "CET", "Central European Time", "CET", "Central European Savings Time", "CEST", "Berlin" },
+ { "EET", "Eastern European Time", "EET", "Eastern European Savings Time", "EEST", "Istanbul" },
+};
+
+/**
+ * This is the list of pattern characters for formatting dates
+ */
+private static final String localPatternChars = "GyMdkHmsSEDFwWahKz"; // Not a mistake!
+
+/**
+ * This is the DateFormat.SHORT date format
+ */
+private static final String shortDateFormat = "M/d/yy";
+
+/**
+ * This is the DateFormat.MEDIUM format
+ */
+private static final String mediumDateFormat = "dd-MMM-yy";
+
+/**
+ * This is the DateFormat.LONG format
+ */
+private static final String longDateFormat = "MMMM d, yyyy";
+
+/**
+ * This is the DateFormat.FULL format
+ */
+private static final String fullDateFormat = "EEEE, MMMM d, yyyy";
+
+/**
+ * This is the DateFormat.DEFAULT format
+ */
+private static final String defaultDateFormat = "dd-MMM-yy";
+
+/**
+ * This is the DateFormat.SHORT format
+ */
+private static final String shortTimeFormat = "h:mm a";
+
+/**
+ * This is the DateFormat.MEDIUM format
+ */
+private static final String mediumTimeFormat = "h:mm:ss a";
+
+/**
+ * This is the DateFormat.LONG format
+ */
+private static final String longTimeFormat = "h:mm:ss a z";
+
+/**
+ * This is the DateFormat.FULL format
+ */
+private static final String fullTimeFormat = "h:mm:ss 'o''clock' a z";
+
+/**
+ * This is the DateFormat.DEFAULT format
+ */
+private static final String defaultTimeFormat = "h:mm:ss a";
+
+/**
+ * This is the currency symbol
+ */
+private static final String currencySymbol = "$";
+
+/**
+ * This is the international currency symbol.
+ */
+private static final String intlCurrencySymbol = "US$";
+
+/**
+ * This is the decimal point.
+ */
+private static final String decimalSeparator = ".";
+
+/**
+ * This is the exponential symbol
+ */
+private static final String exponential = "E";
+
+/**
+ * This is the char used for digits in format strings
+ */
+private static final String digit = "#";
+
+/**
+ * This is the grouping separator symbols
+ */
+private static final String groupingSeparator = ",";
+
+/**
+ * This is the symbols for infinity
+ */
+private static final String infinity = "\u221e";
+
+/**
+ * This is the symbol for the not a number value
+ */
+private static final String NaN = "\ufffd";
+
+/**
+ * This is the minus sign symbol.
+ */
+private static final String minusSign = "-";
+
+/**
+ * This is the decimal separator in monetary values.
+ */
+private static final String monetarySeparator = ".";
+
+/**
+ * This is the separator between positive and negative subpatterns.
+ */
+private static final String patternSeparator = ";";
+
+/**
+ * This is the percent sign
+ */
+private static final String percent = "%";
+
+/**
+ * This is the per mille sign
+ */
+private static final String perMill = "\u2030";
+
+/**
+ * This is the character for zero.
+ */
+private static final String zeroDigit = "0";
+
+/*************************************************************************/
+
+/**
+ * This is the object array used to hold the keys and values
+ * for this bundle
+ */
+
+private static final Object[][] contents =
+{
+ // For RuleBasedCollator
+ { "collation_rules", collation_rules },
+ // For BreakIterator
+ { "word_breaks", word_breaks },
+ { "sentence_breaks", sentence_breaks },
+ { "line_breaks", line_breaks },
+ // For SimpleDateFormat/DateFormatSymbols
+ { "months", months },
+ { "shortMonths", shortMonths },
+ { "weekdays", weekdays },
+ { "shortWeekdays", shortWeekdays },
+ { "ampms", ampms },
+ { "eras", eras },
+ { "zoneStrings", zoneStrings },
+ { "localPatternChars", localPatternChars },
+ { "shortDateFormat", shortDateFormat },
+ { "mediumDateFormat", mediumDateFormat },
+ { "longDateFormat", longDateFormat },
+ { "fullDateFormat", fullDateFormat },
+ { "defaultDateFormat", defaultDateFormat },
+ { "shortTimeFormat", shortTimeFormat },
+ { "mediumTimeFormat", mediumTimeFormat },
+ { "longTimeFormat", longTimeFormat },
+ { "fullTimeFormat", fullTimeFormat },
+ { "defaultTimeFormat", defaultTimeFormat },
+ // For DecimalFormat/DecimalFormatSymbols
+ { "currencySymbol", currencySymbol },
+ { "intlCurrencySymbol", intlCurrencySymbol },
+ { "decimalSeparator", decimalSeparator },
+ { "digit", digit },
+ { "exponential", exponential },
+ { "groupingSeparator", groupingSeparator },
+ { "infinity", infinity },
+ { "NaN", NaN },
+ { "minusSign", minusSign },
+ { "monetarySeparator", monetarySeparator },
+ { "patternSeparator", patternSeparator },
+ { "percent", percent },
+ { "perMill", perMill },
+ { "zeroDigit", zeroDigit },
+};
+
+/*************************************************************************/
+
+/**
+ * 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);
+}
+
+} // class LocaleInformation_en
+
diff --git a/libjava/gnu/java/locale/LocaleInformation_nl.java b/libjava/gnu/java/locale/LocaleInformation_nl.java
new file mode 100644
index 00000000000..8b74c5bc7dd
--- /dev/null
+++ b/libjava/gnu/java/locale/LocaleInformation_nl.java
@@ -0,0 +1,338 @@
+/* LocaleInformation_nl.java -- Dutch 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;
+import java.util.Date;
+
+/**
+ * This class contains locale data for the Dutch locale
+ */
+
+public class LocaleInformation_nl extends ListResourceBundle
+{
+
+/*
+ * This area is used for defining object values
+ */
+
+/**
+ * This is the set of collation rules used by java.text.RuleBasedCollator
+ * to sort strings properly. See the documentation of that class for the
+ * proper format.
+ * <p>
+ * This is the same rule as used in the English locale.
+ */
+private static final String collation_rules =
+ "-<0,1<2<3<4<5<6<7<8<9A,a<b,B<c,C<d,D<e,E<f,F<g,G<h,H<i,I<j,J<j,K" +
+ "<l,L<m,M<n,N<o,O<p,P<q,Q<r,R<s,S<t,T<u,U<v,V<w,W<x,X<y,Y,z<Z";
+
+/*
+ * For the followings lists, strings that are subsets of other break strings
+ * must be listed first. For example, if "\r" and "\r\n" are sequences,
+ * the "\r" must be first or it will never be used.
+ */
+
+/**
+ * This is the list of word separator characters used by
+ * java.text.BreakIterator
+ * <p>
+ * This is the same list as used in the English local
+ */
+private static final String[] word_breaks = { " ", "\t", "\r\n", "\n" };
+
+/**
+ * This is the list of sentence break sequences used by
+ * java.text.BreakIterator
+ * <p>
+ * This is the same list as used in the English local
+ */
+private static final String[] sentence_breaks = { ". " };
+
+/**
+ * This is the list of potential line break locations.
+ * <p>
+ * This is the same list as used in the English local
+ */
+private static final String[] line_breaks = { "\t", "-", "\r\n",
+ "\n", ". ", ". ", ".", "? ", "? ", "?", "! ", "! ", "!", ", ", " " };
+
+/**
+ * This is the list of months, fully spelled out
+ */
+private static final String[] months = { "januari", "februari", "maart",
+ "april", "mei", "juni", "juli", "augustus", "september", "october",
+ "november", "december", null };
+
+/**
+ * This is the list of abbreviated month names
+ */
+private static final String[] shortMonths = { "jan", "feb", "mrt", "apr", "mei",
+ "jun", "jul", "aug", "sep", "oct", "nov", "dec", null };
+
+/**
+ * This is the list of weekdays, fully spelled out
+ */
+private static final String[] weekdays = { null, "zondag", "maandag", "dinsdag",
+ "woensdag", "donderdag", "vrijdag", "zaterdag" };
+
+/**
+ * This is the list of abbreviated weekdays
+ */
+private static final String[] shortWeekdays = { null, "zo", "ma", "di", "wo",
+ "do", "vr", "za" };
+
+/**
+ * This is the list of AM/PM strings
+ * <p>
+ * Is there a real equivalent in Dutch? "Voormiddag"/"Namiddag"?
+ * Just using the Latin names for now.
+ */
+private static final String[] ampms = { "AM", "PM" };
+
+/**
+ * This is the list of era identifiers
+ * <p>
+ * Is there a real equivalent in Dutch? "voor Christus"/"na Christus"?
+ * Just use the Latin/English names for now.
+ */
+private static final String[] eras = { "BC", "AD" };
+
+/**
+ * This is the list of timezone strings. The JDK appears to include a
+ * city name as the sixth element.
+ * XXX - TODO - FIXME - Which timezones should be included here and how are
+ * they called?
+ */
+private static final String[][] zoneStrings =
+{
+ // European time zones. The city names are a little bit random.
+ { "WET", "West Europese Tijd", "WET", "West Europese Zomertijd", "WEST", "London" },
+ { "CET", "Centraal Europese Tijd", "CET", "Centraal Europese Zomertijd", "CEST", "Amsterdam" },
+ { "EET", "Oost Europese Tijd", "EET", "Oost Europese Zomertijd", "EEST", "Istanbul" },
+};
+
+/**
+ * This is the list of pattern characters for formatting dates
+ * <p>
+ * This is the same as the English locale uses: era (G), year (y), month (M),
+ * month (d), hour from 1-12 (h), hour 0-23 (H), minute (m), second (s),
+ * millisecond (S), date of week (E), date of year (D),
+ * day of week in month (F), week in year (w), week in month (W), am/pm (a),
+ * hour from 1-24 (k), hour from 0-11 (K), time zone (z).
+ * Why would you use others?
+ */
+private static final String localPatternChars = "GyMdhHmsSEDFwWakKz"; // Not a mistake!
+
+/**
+ * This is the DateFormat.SHORT date format
+ */
+private static final String shortDateFormat = "dd-MM-yy";
+
+/**
+ * This is the DateFormat.MEDIUM format
+ */
+private static final String mediumDateFormat = "dd-MMM-yy";
+
+/**
+ * This is the DateFormat.LONG format
+ */
+private static final String longDateFormat = "dd MMMM yyyy";
+
+/**
+ * This is the DateFormat.FULL format
+ */
+private static final String fullDateFormat = "EEEE dd MMMM yyyy";
+
+/**
+ * This is the DateFormat.DEFAULT format
+ */
+private static final String defaultDateFormat = mediumDateFormat;
+
+/**
+ * This is the TimeFormat.SHORT format
+ */
+private static final String shortTimeFormat = "HH:mm";
+
+/**
+ * This is the TimeFormat.MEDIUM format
+ */
+private static final String mediumTimeFormat = "HH:mm:ss";
+
+/**
+ * This is the TimeFormat.LONG format
+ */
+private static final String longTimeFormat = "HH:mm:ss";
+
+/**
+ * This is the TimeFormat.FULL format
+ */
+private static final String fullTimeFormat = "HH:mm:ss z";
+
+/**
+ * This is the TimeFormat.DEFAULT format
+ */
+private static final String defaultTimeFormat = shortTimeFormat;
+
+/**
+ * This is the currency symbol
+ */
+private static final String currencySymbol = "fl";
+
+/**
+ * This is the international currency symbol.
+ */
+private static final String intlCurrencySymbol = "NLG";
+
+/**
+ * This is the decimal point.
+ */
+private static final String decimalSeparator = ",";
+
+/**
+ * This is the exponential symbol
+ */
+private static final String exponential = "E";
+
+/**
+ * This is the char used for digits in format strings
+ */
+private static final String digit = "#";
+
+/**
+ * This is the grouping separator symbols
+ */
+private static final String groupingSeparator = ",";
+
+/**
+ * This is the symbols for infinity
+ */
+private static final String infinity = "\u221e";
+
+/**
+ * This is the symbol for the not a number value
+ */
+private static final String NaN = "\ufffd";
+
+/**
+ * This is the minus sign symbol.
+ */
+private static final String minusSign = "-";
+
+/**
+ * This is the decimal separator in monetary values.
+ */
+private static final String monetarySeparator = ",";
+
+/**
+ * This is the separator between positive and negative subpatterns.
+ */
+private static final String patternSeparator = ";";
+
+/**
+ * This is the percent sign
+ */
+private static final String percent = "%";
+
+/**
+ * This is the per mille sign
+ */
+private static final String perMill = "\u2030";
+
+/**
+ * This is the character for zero.
+ */
+private static final String zeroDigit = "0";
+
+/*************************************************************************/
+
+/**
+ * This is the object array used to hold the keys and values
+ * for this bundle
+ */
+
+private static final Object[][] contents =
+{
+ // For RuleBasedCollator
+ { "collation_rules", collation_rules },
+ // For BreakIterator
+ { "word_breaks", word_breaks },
+ { "sentence_breaks", sentence_breaks },
+ { "line_breaks", line_breaks },
+ // For SimpleDateFormat/DateFormatSymbols
+ { "months", months },
+ { "shortMonths", shortMonths },
+ { "weekdays", weekdays },
+ { "shortWeekdays", shortWeekdays },
+ { "ampms", ampms },
+ { "eras", eras },
+ { "zoneStrings", zoneStrings },
+ { "localPatternChars", localPatternChars },
+ { "shortDateFormat", shortDateFormat },
+ { "mediumDateFormat", mediumDateFormat },
+ { "longDateFormat", longDateFormat },
+ { "fullDateFormat", fullDateFormat },
+ { "defaultDateFormat", defaultDateFormat },
+ { "shortTimeFormat", shortTimeFormat },
+ { "mediumTimeFormat", mediumTimeFormat },
+ { "longTimeFormat", longTimeFormat },
+ { "fullTimeFormat", fullTimeFormat },
+ { "defaultTimeFormat", defaultTimeFormat },
+ // For DecimalFormat/DecimalFormatSymbols
+ { "currencySymbol", currencySymbol },
+ { "intlCurrencySymbol", intlCurrencySymbol },
+ { "decimalSeparator", decimalSeparator },
+ { "digit", digit },
+ { "exponential", exponential },
+ { "groupingSeparator", groupingSeparator },
+ { "infinity", infinity },
+ { "NaN", NaN },
+ { "minusSign", minusSign },
+ { "monetarySeparator", monetarySeparator },
+ { "patternSeparator", patternSeparator },
+ { "percent", percent },
+ { "perMill", perMill },
+ { "zeroDigit", zeroDigit },
+};
+
+/*************************************************************************/
+
+/**
+ * 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);
+}
+
+} // class LocaleInformation_nl
diff --git a/libjava/java/text/SimpleDateFormat.java b/libjava/java/text/SimpleDateFormat.java
index 527fcc87ada..f0976054c63 100644
--- a/libjava/java/text/SimpleDateFormat.java
+++ b/libjava/java/text/SimpleDateFormat.java
@@ -62,8 +62,7 @@ public class SimpleDateFormat extends DateFormat
private transient Vector tokens;
private DateFormatSymbols formatData; // formatData
- private Date defaultCenturyStart =
- new Date(System.currentTimeMillis() - (80*365*24*60*60*1000));
+ private Date defaultCenturyStart = computeCenturyStart ();
private String pattern;
private int serialVersionOnStream = 1; // 0 indicates JDK1.1.3 or earlier
private static final long serialVersionUID = 4774881970558875024L;
@@ -79,8 +78,7 @@ public class SimpleDateFormat extends DateFormat
stream.defaultReadObject();
if (serialVersionOnStream < 1)
{
- defaultCenturyStart =
- new Date(System.currentTimeMillis() - (80*365*24*60*60*1000));
+ defaultCenturyStart = computeCenturyStart ();
serialVersionOnStream = 1;
}
@@ -161,11 +159,14 @@ public class SimpleDateFormat extends DateFormat
super();
Locale locale = Locale.getDefault();
calendar = new GregorianCalendar(locale);
+ calendar.clear ();
tokens = new Vector();
formatData = new DateFormatSymbols(locale);
- pattern = formatData.dateFormats[DEFAULT]+' '+formatData.timeFormats[DEFAULT];
+ pattern = (formatData.dateFormats[DEFAULT] + ' '
+ + formatData.timeFormats[DEFAULT]);
compileFormat(pattern);
numberFormat = NumberFormat.getInstance(locale);
+ numberFormat.setGroupingUsed (false);
}
/**
@@ -185,20 +186,24 @@ public class SimpleDateFormat extends DateFormat
{
super();
calendar = new GregorianCalendar(locale);
+ calendar.clear ();
tokens = new Vector();
formatData = new DateFormatSymbols(locale);
compileFormat(pattern);
this.pattern = pattern;
numberFormat = NumberFormat.getInstance(locale);
+ numberFormat.setGroupingUsed (false);
}
/**
* Creates a date formatter using the specified pattern. The
* specified DateFormatSymbols will be used when formatting.
*/
- public SimpleDateFormat(String pattern, DateFormatSymbols formatData) {
+ public SimpleDateFormat(String pattern, DateFormatSymbols formatData)
+ {
super();
calendar = new GregorianCalendar();
+ calendar.clear ();
// FIXME: XXX: Is it really necessary to set the timezone?
// The Calendar constructor is supposed to take care of this.
calendar.setTimeZone(TimeZone.getDefault());
@@ -207,6 +212,7 @@ public class SimpleDateFormat extends DateFormat
compileFormat(pattern);
this.pattern = pattern;
numberFormat = NumberFormat.getInstance();
+ numberFormat.setGroupingUsed (false);
}
// What is the difference between localized and unlocalized? The
@@ -377,7 +383,8 @@ public class SimpleDateFormat extends DateFormat
* appending to the specified StringBuffer. The input StringBuffer
* is returned as output for convenience.
*/
- public StringBuffer format(Date date, StringBuffer buffer, FieldPosition pos) {
+ public StringBuffer format(Date date, StringBuffer buffer, FieldPosition pos)
+ {
String temp;
Calendar theCalendar = (Calendar) calendar.clone();
theCalendar.setTime(date);
@@ -507,7 +514,10 @@ public class SimpleDateFormat extends DateFormat
int fmt_index = 0;
int fmt_max = pattern.length();
- calendar.clear();
+ // We copy the Calendar because if we don't we will modify it and
+ // then this.equals() will no longer have the desired result.
+ Calendar theCalendar = (Calendar) calendar.clone ();
+ theCalendar.clear();
int quote_start = -1;
for (; fmt_index < fmt_max; ++fmt_index)
{
@@ -553,7 +563,6 @@ public class SimpleDateFormat extends DateFormat
boolean is_numeric = true;
String[] match = null;
int offset = 0;
- int zone_number = 0;
switch (ch)
{
case 'd':
@@ -626,6 +635,7 @@ public class SimpleDateFormat extends DateFormat
// We need a special case for the timezone, because it
// uses a different data structure than the other cases.
is_numeric = false;
+ // We don't actually use this; see below.
calendar_field = Calendar.DST_OFFSET;
String[][] zoneStrings = formatData.getZoneStrings();
int zoneCount = zoneStrings.length;
@@ -642,11 +652,11 @@ public class SimpleDateFormat extends DateFormat
}
if (k != strings.length)
{
- if (k > 2)
- ; // FIXME: dst.
- zone_number = 0; // FIXME: dst.
- // FIXME: raw offset to SimpleTimeZone const.
- calendar.setTimeZone(new SimpleTimeZone (1, strings[0]));
+ found_zone = true;
+ TimeZone tz = TimeZone.getTimeZone (strings[0]);
+ theCalendar.setTimeZone (tz);
+ theCalendar.clear (Calendar.DST_OFFSET);
+ theCalendar.clear (Calendar.ZONE_OFFSET);
pos.setIndex(index + strings[k].length());
break;
}
@@ -690,15 +700,16 @@ public class SimpleDateFormat extends DateFormat
value = i;
}
else
- value = zone_number;
+ value = 0;
// Assign the value and move on.
- calendar.set(calendar_field, value);
+ if (calendar_field != Calendar.DST_OFFSET)
+ theCalendar.set(calendar_field, value);
}
try
{
- return calendar.getTime();
+ return theCalendar.getTime();
}
catch (IllegalArgumentException x)
{
@@ -706,4 +717,21 @@ public class SimpleDateFormat extends DateFormat
return null;
}
}
+
+ // Compute the start of the current century as defined by
+ // get2DigitYearStart.
+ private Date computeCenturyStart ()
+ {
+ // Compute the current year. We assume a year has 365 days. Then
+ // compute 80 years ago, and finally reconstruct the number of
+ // milliseconds. We do this computation in this strange way
+ // because it lets us easily truncate the milliseconds, seconds,
+ // etc, which don't matter and which confuse
+ // SimpleDateFormat.equals().
+ long now = System.currentTimeMillis ();
+ now /= 365L * 24L * 60L * 60L * 1000L;
+ now -= 80;
+ now *= 365L * 24L * 60L * 60L * 1000L;
+ return new Date (now);
+ }
}
diff --git a/libjava/java/util/Calendar.java b/libjava/java/util/Calendar.java
index 05c3f633eb1..17f4c7756e5 100644
--- a/libjava/java/util/Calendar.java
+++ b/libjava/java/util/Calendar.java
@@ -1,5 +1,5 @@
/* java.util.Calendar
- Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
+ Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -54,7 +54,7 @@ import java.io.*;
*
* 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
+ * cases will handled in a calendar 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
@@ -356,7 +356,7 @@ public abstract class Calendar implements Serializable, Cloneable
private static final String bundleName = "gnu.java.locale.Calendar";
/**
- * Constructs a new Calender with the default time zone and the default
+ * Constructs a new Calendar with the default time zone and the default
* locale.
*/
protected Calendar()
@@ -365,7 +365,7 @@ public abstract class Calendar implements Serializable, Cloneable
}
/**
- * Constructs a new Calender with the given time zone and the given
+ * Constructs a new Calendar with the given time zone and the given
* locale.
* @param zone a time zone.
* @param locale a locale.
@@ -483,7 +483,7 @@ public abstract class Calendar implements Serializable, Cloneable
}
/**
- * Sets this Calender's time to the given Date. All time fields
+ * Sets this Calendar's time to the given Date. All time fields
* are invalidated by this method.
*/
public final void setTime(Date date)
@@ -503,7 +503,7 @@ public abstract class Calendar implements Serializable, Cloneable
}
/**
- * Sets this Calender's time to the given Time. All time fields
+ * Sets this Calendar's time to the given Time. All time fields
* are invalidated by this method.
* @param time the time in milliseconds since the epoch
*/
@@ -522,6 +522,9 @@ public abstract class Calendar implements Serializable, Cloneable
*/
public final int get(int field)
{
+ // If the requested field is invalid, force all fields to be recomputed.
+ if (!isSet[field])
+ areFieldsSet = false;
complete();
return fields[field];
}
@@ -551,6 +554,29 @@ public abstract class Calendar implements Serializable, Cloneable
isTimeSet = false;
fields[field] = value;
isSet[field] = true;
+ switch (field)
+ {
+ case YEAR:
+ case MONTH:
+ case DATE:
+ isSet[WEEK_OF_YEAR] = false;
+ isSet[DAY_OF_YEAR] = false;
+ isSet[WEEK_OF_MONTH] = false;
+ isSet[DAY_OF_WEEK] = false;
+ isSet[DAY_OF_WEEK_IN_MONTH] = false;
+ break;
+ case AM_PM:
+ isSet[HOUR_OF_DAY] = false;
+ break;
+ case HOUR_OF_DAY:
+ isSet[AM_PM] = false;
+ isSet[HOUR] = false;
+ break;
+ case HOUR:
+ isSet[AM_PM] = false;
+ isSet[HOUR_OF_DAY] = false;
+ break;
+ }
}
/**
@@ -568,6 +594,11 @@ public abstract class Calendar implements Serializable, Cloneable
fields[MONTH] = month;
fields[DATE] = date;
isSet[YEAR] = isSet[MONTH] = isSet[DATE] = true;
+ isSet[WEEK_OF_YEAR] = false;
+ isSet[DAY_OF_YEAR] = false;
+ isSet[WEEK_OF_MONTH] = false;
+ isSet[DAY_OF_WEEK] = false;
+ isSet[DAY_OF_WEEK_IN_MONTH] = false;
}
/**
@@ -584,6 +615,8 @@ public abstract class Calendar implements Serializable, Cloneable
fields[HOUR_OF_DAY] = hour;
fields[MINUTE] = minute;
isSet[HOUR_OF_DAY] = isSet[MINUTE] = true;
+ isSet[AM_PM] = false;
+ isSet[HOUR] = false;
}
/**
@@ -611,7 +644,10 @@ public abstract class Calendar implements Serializable, Cloneable
isTimeSet = false;
areFieldsSet = false;
for (int i = 0; i < FIELD_COUNT; i++)
- isSet[i] = false;
+ {
+ isSet[i] = false;
+ fields[i] = 0;
+ }
}
/**
@@ -623,6 +659,7 @@ public abstract class Calendar implements Serializable, Cloneable
isTimeSet = false;
areFieldsSet = false;
isSet[field] = false;
+ fields[field] = 0;
}
/**
@@ -647,7 +684,7 @@ public abstract class Calendar implements Serializable, Cloneable
}
/**
- * Compares the given calender with this.
+ * Compares the given calendar with this.
* @param o the object to that we should compare.
* @return true, if the given object is a calendar, that represents
* the same time (but doesn't neccessary have the same fields).
@@ -670,10 +707,10 @@ public abstract class Calendar implements Serializable, Cloneable
}
/**
- * Compares the given calender with this.
+ * Compares the given calendar with this.
* @param o the object to that we should compare.
* @return true, if the given object is a calendar, and this calendar
- * represents a smaller time than the calender o.
+ * represents a smaller time than the calendar o.
* @exception ClassCastException if o is not an calendar.
* @since JDK1.2 you don't need to override this method
*/
@@ -683,10 +720,10 @@ public abstract class Calendar implements Serializable, Cloneable
}
/**
- * Compares the given calender with this.
+ * Compares the given calendar with this.
* @param o the object to that we should compare.
* @return true, if the given object is a calendar, and this calendar
- * represents a bigger time than the calender o.
+ * represents a bigger time than the calendar o.
* @exception ClassCastException if o is not an calendar.
* @since JDK1.2 you don't need to override this method
*/
@@ -866,7 +903,7 @@ public abstract class Calendar implements Serializable, Cloneable
* @since jdk1.2
*/
// FIXME: XXX: Not abstract in JDK 1.2.
- // public abstract int getActualMinimum(int field);
+ public abstract int getActualMinimum(int field);
/**
* Gets the actual maximum value that is allowed for the specified field.
@@ -876,7 +913,7 @@ public abstract class Calendar implements Serializable, Cloneable
* @since jdk1.2
*/
// FIXME: XXX: Not abstract in JDK 1.2.
- // public abstract int getActualMaximum(int field);
+ public abstract int getActualMaximum(int field);
/**
* Return a clone of this object.
diff --git a/libjava/java/util/GregorianCalendar.java b/libjava/java/util/GregorianCalendar.java
index cc06c2919d2..912efdf7eb8 100644
--- a/libjava/java/util/GregorianCalendar.java
+++ b/libjava/java/util/GregorianCalendar.java
@@ -1,265 +1,1071 @@
-/* Copyright (C) 1998, 1999, 2000 Free Software Foundation
+/* java.util.GregorianCalendar
+ Copyright (C) 1998, 1999, 2001 Free Software Foundation, Inc.
- This file is part of libgcj.
+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 software is copyrighted work licensed under the terms of the
-Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
-details. */
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,
- * and "The Java Language Specification", ISBN 0-201-63451-1.
- * Status: "leniency" is not handled, and neither is roll-over in
- * add and roll. This is partly because of unclear specification.
- * hashCode has no spec.
+ * This class represents the Gregorian calendar, that is used in most
+ * countries all over the world. It does also handle the Julian calendar
+ * for dates smaller than the date of the change to the Gregorian calendar.
+ * This change date is different from country to country, you can set it with
+ * <code>setGregorianChange</code>
+ *
+ * The Gregorian calendar differs from the Julian calendar by a different
+ * leap year rule (no leap year every 100 years, except if year is divisible
+ * by 400). The non existing days that were omited when the change took
+ * place are interpreted as gregorian date
+ *
+ * There are to eras available for the Gregorian calendar, namely BC and AD.
+ *
+ * @see Calendar
+ * @see TimeZone
*/
-
-public class GregorianCalendar extends Calendar {
+public class GregorianCalendar extends Calendar
+{
+ /**
+ * Constant representing the era BC (before Christ).
+ */
public static final int BC = 0;
+
+ /**
+ * Constant representing the era AD (Anno Domini).
+ */
public static final int AD = 1;
- // The fields are as specified in Sun's "Serialized Form"
- // in the JDK 1.2 beta 4 API specification.
- // Value from a simple test program (getGregorianChange.getTime()).
- long gregorianCutover = -12219292800000L;
-
- private final static int[] mins = {
- 0 /* ERA */,
- 1 /* YEAR */,
- 0 /* MONTH */,
- 0 /* WEEK_OF_YEAR */,
- 0 /* WEEK_OF_MONTH */,
- 1 /* DATE */,
- 1 /* DAY_OF_YEAR */,
- 1 /* DAY_OF_WEEK */,
- -1 /* DAY_OF_WEEK_IN_MONTH */,
- 0 /* AM_PM */,
- 0 /* HOUR */,
- 0 /* HOUR_OF_DAY */,
- 0 /* MINUTE */,
- 0 /* SECOND */,
- 0 /* MILLISECOND */,
- -43200000 /* ZONE_OFFSET */,
- 0 /* DST_OFFSET */
- };
-
- private final static int[] maxs = {
- 1 /* ERA */,
- 5000000 /* YEAR */,
- 11 /* MONTH */,
- 54 /* WEEK_OF_YEAR */,
- 6 /* WEEK_OF_MONTH */,
- 31 /* DATE */,
- 366 /* DAY_OF_YEAR */,
- 7 /* DAY_OF_WEEK */,
- 6 /* DAY_OF_WEEK_IN_MONTH */,
- 1 /* AM_PM */,
- 12 /* HOUR */,
- 23 /* HOUR_OF_DAY */,
- 59 /* MINUTE */,
- 59 /* SECOND */,
- 999 /* MILLISECOND */,
- 43200000 /* ZONE_OFFSET */,
- 3600000 /* DST_OFFSET */
- };
-
- private final static int[] leastMaximums = {
- 1 /* ERA */,
- 5000000 /* YEAR */,
- 11 /* MONTH */,
- 53 /* WEEK_OF_YEAR */,
- 6 /* WEEK_OF_MONTH */,
- 28 /* DATE */,
- 365 /* DAY_OF_YEAR */,
- 7 /* DAY_OF_WEEK */,
- 4 /* DAY_OF_WEEK_IN_MONTH */,
- 1 /* AM_PM */,
- 11 /* HOUR */,
- 23 /* HOUR_OF_DAY */,
- 59 /* MINUTE */,
- 59 /* SECOND */,
- 999 /* MILLISECOND */,
- 43200000 /* ZONE_OFFSET */,
- 3600000 /* DST_OFFSET */
- };
-
- private static final long serialVersionUID = -8125100834729963327L;
-
- public GregorianCalendar ()
+ /**
+ * The point at which the Gregorian calendar rules were used.
+ * This is locale dependent; the default for most catholic
+ * countries is midnight (UTC) on October 5, 1582 (Julian),
+ * or October 15, 1582 (Gregorian).
+ */
+ private long gregorianCutover;
+
+ static final long serialVersionUID = -8125100834729963327L;
+
+ /**
+ * The name of the resource bundle.
+ */
+ private static final String bundleName = "gnu.java.locale.Calendar";
+
+ /**
+ * Constructs a new GregorianCalender representing the current
+ * time, using the default time zone and the default locale.
+ */
+ public GregorianCalendar()
+ {
+ this(TimeZone.getDefault(), Locale.getDefault());
+ }
+
+ /**
+ * Constructs a new GregorianCalender representing the current
+ * time, using the specified time zone and the default locale.
+ * @param zone a time zone.
+ */
+ public GregorianCalendar(TimeZone zone)
+ {
+ this(zone, Locale.getDefault());
+ }
+
+ /**
+ * Constructs a new GregorianCalender representing the current
+ * time, using the default time zone and the specified locale.
+ * @param locale a locale.
+ */
+ public GregorianCalendar(Locale locale)
+ {
+ this(TimeZone.getDefault(), locale);
+ }
+
+ /**
+ * Constructs a new GregorianCalender representing the current
+ * time with the given time zone and the given locale.
+ * @param zone a time zone.
+ * @param locale a locale.
+ */
+ public GregorianCalendar(TimeZone zone, Locale locale)
+ {
+ super(zone, locale);
+ ResourceBundle rb = ResourceBundle.getBundle(bundleName, locale);
+ gregorianCutover = ((Date) rb.getObject("gregorianCutOver")).getTime();
+ time = System.currentTimeMillis();
+ isTimeSet = true;
+ areFieldsSet = false;
+ }
+
+ /**
+ * Constructs a new GregorianCalendar representing midnight on the
+ * given date with the default time zone and locale.
+ * @param year corresponds to the YEAR time field.
+ * @param month corresponds to the MONTH time field.
+ * @param day corresponds to the DAY time field.
+ */
+ public GregorianCalendar(int year, int month, int day)
+ {
+ super();
+ set(year, month, day);
+ }
+
+ /**
+ * Constructs a new GregorianCalendar representing midnight on the
+ * given date with the default time zone and locale.
+ * @param year corresponds to the YEAR time field.
+ * @param month corresponds to the MONTH time field.
+ * @param day corresponds to the DAY time field.
+ * @param hour corresponds to the HOUR_OF_DAY time field.
+ * @param minute corresponds to the MINUTE time field.
+ */
+ public GregorianCalendar(int year, int month, int day, int hour, int minute)
{
- this(TimeZone.getDefault (), Locale.getDefault ());
+ super();
+ set(year, month, day, hour, minute);
}
- public GregorianCalendar (TimeZone zone)
+ /**
+ * Constructs a new GregorianCalendar representing midnight on the
+ * given date with the default time zone and locale.
+ * @param year corresponds to the YEAR time field.
+ * @param month corresponds to the MONTH time field.
+ * @param day corresponds to the DAY time field.
+ * @param hour corresponds to the HOUR_OF_DAY time field.
+ * @param minute corresponds to the MINUTE time field.
+ * @param second corresponds to the SECOND time field.
+ */
+ public GregorianCalendar(int year, int month, int day,
+ int hour, int minute, int second)
{
- this (zone, Locale.getDefault ());
+ super();
+ set(year, month, day, hour, minute, second);
}
- public GregorianCalendar (Locale locale)
+ /**
+ * Sets the date of the switch from Julian dates to Gregorian dates.
+ * You can use <code>new Date(Long.MAX_VALUE)</code> to use a pure
+ * Julian calendar, or <code>Long.MIN_VALUE</code> for a pure Gregorian
+ * calendar.
+ * @param date the date of the change.
+ */
+ public void setGregorianChange(Date date)
{
- this (TimeZone.getDefault (), locale);
+ gregorianCutover = date.getTime();
}
- public GregorianCalendar (TimeZone zone, Locale locale)
+ /**
+ * Gets the date of the switch from Julian dates to Gregorian dates.
+ * @return the date of the change.
+ */
+ public final Date getGregorianChange(Date date)
{
- super (zone, locale);
- setDefaultTime ();
+ return new Date(gregorianCutover);
}
- public GregorianCalendar (int year, int month, int date)
+ /**
+ * Determines if the given year is a leap year. The result is
+ * undefined if the gregorian change took place in 1800, so that
+ * the end of february is skiped and you give that year
+ * (well...).<br>
+ *
+ * The year should be positive and you can't give an ERA. But
+ * remember that before 4 BC there wasn't a consistent leap year
+ * rule, so who cares.
+ *
+ * @param year a year use nonnegative value for BC.
+ * @return true, if the given year is a leap year, false otherwise. */
+ public boolean isLeapYear(int year)
{
- this();
- set (year, month, date, 0, 0, 0);
+ if ((year & 3) != 0)
+ // Only years divisible by 4 can be leap years
+ return false;
+
+ // compute the linear day of the 29. February of that year.
+ // The 13 is the number of days, that were omitted in the Gregorian
+ // Calender until the epoch.
+ int julianDay = (((year-1) * (365*4+1)) >> 2) + (31+29 -
+ (((1970-1) * (365*4+1)) / 4 + 1 - 13));
+
+ // If that day is smaller than the gregorianChange the julian
+ // rule applies: This is a leap year since it is divisible by 4.
+ if (julianDay * (24 * 60 * 60 * 1000L) < gregorianCutover)
+ return true;
+
+ return ((year % 100) != 0 || (year % 400) == 0);
+ }
+
+ /**
+ * Get the linear time in milliseconds since the epoch. If you
+ * specify a nonpositive year it is interpreted as BC as
+ * following: 0 is 1 BC, -1 is 2 BC and so on. The date is
+ * interpreted as gregorian if the change occured before that date.
+ *
+ * @param year the year of the date.
+ * @param dayOfYear the day of year of the date; 1 based.
+ * @param millis the millisecond in that day.
+ * @return the days since the epoch, may be negative. */
+ private long getLinearTime(int year, int dayOfYear, int millis)
+ {
+ // The 13 is the number of days, that were omitted in the Gregorian
+ // Calender until the epoch.
+ // We shift right by 2 instead of dividing by 4, to get correct
+ // results for negative years (and this is even more efficient).
+ int julianDay = ((year * (365 * 4 + 1)) >> 2) + dayOfYear -
+ ((1970 * (365 * 4 + 1)) / 4 + 1 - 13);
+ long time = julianDay * (24 * 60 * 60 * 1000L) + millis;
+
+ if (time >= gregorianCutover)
+ {
+ // subtract the days that are missing in gregorian calendar
+ // with respect to julian calendar.
+ //
+ // Okay, here we rely on the fact that the gregorian
+ // calendar was introduced in the AD era. This doesn't work
+ // with negative years.
+ //
+ // The additional leap year factor accounts for the fact that
+ // a leap day is not seen on Jan 1 of the leap year.
+ int gregOffset = (year / 400) - (year / 100) + 2;
+ if (isLeapYear (year, true) && dayOfYear < 31 + 29)
+ --gregOffset;
+ time += gregOffset * (24 * 60 * 60 * 1000L);
+ }
+ return time;
}
- public GregorianCalendar (int year, int month, int date,
- int hour, int minute)
+ private int getWeekDay(int year, int dayOfYear)
{
- this();
- set (year, month, date, hour, minute, 0);
+ int day =
+ (int) (getLinearTime(year, dayOfYear, 0) / (24 * 60 * 60 * 1000L));
+
+ // The epoch was a thursday.
+ int weekday = (day + THURSDAY) % 7;
+ if (weekday <= 0)
+ weekday += 7;
+ return weekday;
}
- public GregorianCalendar (int year, int month, int date,
- int hour, int minute, int second)
+ /**
+ * Calculate the dayOfYear from the fields array.
+ * The relativeDays is used, to account for weeks that begin before
+ * the gregorian change and end after it.<br>
+ *
+ * We return two values, the first is used to determine, if we
+ * should use Gregorian calendar or Julian calendar, in case of
+ * the change year, the second is a relative day after the given
+ * day. This is necessary for week calculation in the year in
+ * which gregorian change occurs. <br>
+ *
+ * @param year the year, negative for BC.
+ * @return an array of two int values, the first containing a reference
+ * day of current year, the second a relative count since this reference
+ * day. */
+ private int[] getDayOfYear(int year)
{
- this();
- set (year, month, date, hour, minute, second);
+ if (isSet[MONTH])
+ {
+ int dayOfYear;
+ if (fields[MONTH] > FEBRUARY)
+ {
+
+ // The months after February are regular:
+ // 9 is an offset found by try and error.
+ dayOfYear = (fields[MONTH] * (31 + 30 + 31 + 30 + 31) - 9) / 5;
+ if (isLeapYear(year))
+ dayOfYear++;
+ }
+ else
+ dayOfYear = 31 * fields[MONTH];
+
+ if (isSet[DAY_OF_MONTH])
+ {
+ return new int[]
+ {
+ dayOfYear + fields[DAY_OF_MONTH], 0};
+ }
+ if (isSet[WEEK_OF_MONTH] && isSet[DAY_OF_WEEK])
+ {
+ // the weekday of the first day in that month is:
+ int weekday = getWeekDay(year, ++dayOfYear);
+
+ return new int[]
+ {
+ dayOfYear,
+ // the day of week in the first week
+ // (weeks starting on sunday) is:
+ fields[DAY_OF_WEEK] - weekday +
+ // Now jump to the right week and correct the possible
+ // error made by assuming sunday is the first week day.
+ 7 * (fields[WEEK_OF_MONTH]
+ + (fields[DAY_OF_WEEK] < getFirstDayOfWeek()? 0 : -1)
+ + (weekday < getFirstDayOfWeek()? -1 : 0))};
+ }
+ if (isSet[DAY_OF_WEEK] && isSet[DAY_OF_WEEK_IN_MONTH])
+ {
+ // the weekday of the first day in that month is:
+ int weekday = getWeekDay(year, ++dayOfYear);
+ return new int[] {
+ dayOfYear,
+ fields[DAY_OF_WEEK] - weekday +
+ 7 * (fields[DAY_OF_WEEK_IN_MONTH]
+ + (fields[DAY_OF_WEEK] < weekday ? 0 : -1))};
+ }
+ }
+
+ // MONTH + something did not succeed.
+ if (isSet[DAY_OF_YEAR])
+ {
+ return new int[] {0, fields[DAY_OF_YEAR]};
+ }
+
+ if (isSet[DAY_OF_WEEK] && isSet[WEEK_OF_YEAR])
+ {
+ int dayOfYear = getMinimalDaysInFirstWeek();
+ // the weekday of the day, that begins the first week
+ // in that year is:
+ int weekday = getWeekDay(year, dayOfYear);
+
+ return new int[] {
+ dayOfYear,
+ // the day of week in the first week
+ // (weeks starting on sunday) is:
+ fields[DAY_OF_WEEK] - weekday
+ // Now jump to the right week and correct the possible
+ // error made by assuming sunday is the first week day.
+ + 7 * (fields[WEEK_OF_YEAR]
+ + (fields[DAY_OF_WEEK] < getFirstDayOfWeek()? 0 : -1)
+ + (weekday < getFirstDayOfWeek()? -1 : 0))};
+ }
+
+ // As last resort return Jan, 1st.
+ return new int[] {1, 0};
}
- private final void setDefaultTime ()
+ /**
+ * Converts the time field values (<code>fields</code>) to
+ * milliseconds since the epoch UTC (<code>time</code>).
+ */
+ protected synchronized void computeTime()
{
- setTimeInMillis (System.currentTimeMillis());
+ int era = isSet[ERA] ? fields[ERA] : AD;
+ int year = isSet[YEAR] ? fields[YEAR] : 1970;
+ if (era == BC)
+ year = 1 - year;
+
+ int[] daysOfYear = getDayOfYear(year);
+ int hour = isSet[HOUR_OF_DAY] ? fields[HOUR_OF_DAY]
+ : (isSet[HOUR] && isSet[AM_PM]
+ ? fields[AM_PM] * 12 + (fields[HOUR] % 12) : 0);
+ int minute = isSet[MINUTE] ? fields[MINUTE] : 0;
+ int second = isSet[SECOND] ? fields[SECOND] : 0;
+ int millis = isSet[MILLISECOND] ? fields[MILLISECOND] : 0;
+ int millisInDay;
+
+ if (isLenient())
+ {
+ // prevent overflow
+ long allMillis = (((hour * 60L) + minute) * 60L + second) * 1000L
+ + millis;
+ daysOfYear[1] += allMillis / (24 * 60 * 60 * 1000L);
+ millisInDay = (int) (allMillis % (24 * 60 * 60 * 1000L));
+ }
+ else
+ {
+ if (hour < 0 || hour >= 24 || minute < 0 || minute > 59
+ || second < 0 || second > 59 || millis < 0 || millis >= 1000)
+ throw new IllegalArgumentException();
+ millisInDay = (((hour * 60) + minute) * 60 + second) * 1000 + millis;
+ }
+ time = getLinearTime(year, daysOfYear[0], millisInDay);
+
+ // Add the relative days after calculating the linear time, to
+ // get right behaviour when jumping over the gregorianCutover.
+ time += daysOfYear[1] * (24 * 60 * 60 * 1000L);
+
+
+ TimeZone zone = getTimeZone();
+ int rawOffset = isSet[ZONE_OFFSET]
+ ? fields[ZONE_OFFSET] : getTimeZone().getRawOffset();
+
+ int dayOfYear = daysOfYear[0] + daysOfYear[1];
+ int month = (dayOfYear * 5 + 3) / (31 + 30 + 31 + 30 + 31);
+ int day = (6 + (dayOfYear * 5 + 3) % (31 + 30 + 31 + 30 + 31)) / 5;
+ int weekday = ((int) (time / (24 * 60 * 60 * 1000L)) + THURSDAY) % 7;
+ if (weekday <= 0)
+ weekday += 7;
+ int dstOffset = isSet[DST_OFFSET]
+ ? fields[DST_OFFSET] : (zone.getOffset((year < 0) ? BC : AD,
+ (year < 0) ? 1 - year : year,
+ month, day, weekday, millisInDay)
+ - zone.getRawOffset());
+ time -= rawOffset + dstOffset;
+ isTimeSet = true;
}
- public int getMinimum(int calfield) { return mins[calfield]; }
- public int getGreatestMinimum(int calfield) { return mins[calfield]; }
- public int getMaximum(int calfield) { return maxs[calfield]; }
- public int getLeastMaximum(int calfield) { return leastMaximums[calfield]; }
+ /**
+ * Determines if the given year is a leap year.
+ *
+ * The year should be positive and you can't give an ERA. But
+ * remember that before 4 BC there wasn't a consistent leap year
+ * rule, so who cares.
+ *
+ * @param year a year use nonnegative value for BC.
+ * @param gregorian if true, use gregorian leap year rule.
+ * @return true, if the given year is a leap year, false otherwise. */
+ private boolean isLeapYear(int year, boolean gregorian)
+ {
+ if ((year & 3) != 0)
+ // Only years divisible by 4 can be leap years
+ return false;
- protected native void computeFields();
+ if (!gregorian)
+ return true;
- protected native void computeTime();
+ // We rely on AD area here.
+ return ((year % 100) != 0 || (year % 400) == 0);
+ }
- public void add (int fld, int amount)
+ /**
+ * Get the linear day in days since the epoch, using the
+ * Julian or Gregorian calendar as specified. If you specify a
+ * nonpositive year it is interpreted as BC as following: 0 is 1
+ * BC, -1 is 2 BC and so on.
+ *
+ * @param year the year of the date.
+ * @param dayOfYear the day of year of the date; 1 based.
+ * @param gregorian True, if we should use Gregorian rules.
+ * @return the days since the epoch, may be negative. */
+ private int getLinearDay(int year, int dayOfYear, boolean gregorian)
{
- if (fld >= ZONE_OFFSET)
- throw new IllegalArgumentException("bad field to add");
- fields[fld] += amount;
- adjust(fld);
+ // The 13 is the number of days, that were omitted in the Gregorian
+ // Calender until the epoch.
+ // We shift right by 2 instead of dividing by 4, to get correct
+ // results for negative years (and this is even more efficient).
+ int julianDay = ((year * (365 * 4 + 1)) >> 2) + dayOfYear -
+ ((1970 * (365 * 4 + 1)) / 4 + 1 - 13);
+
+ if (gregorian)
+ {
+ // subtract the days that are missing in gregorian calendar
+ // with respect to julian calendar.
+ //
+ // Okay, here we rely on the fact that the gregorian
+ // calendar was introduced in the AD era. This doesn't work
+ // with negative years.
+ //
+ // The additional leap year factor accounts for the fact that
+ // a leap day is not seen on Jan 1 of the leap year.
+ int gregOffset = (year / 400) - (year / 100) + 2;
+ if (isLeapYear (year, true) && dayOfYear < 31 + 29)
+ --gregOffset;
+ julianDay += gregOffset;
+ }
+ return julianDay;
}
- public void roll (int fld, boolean up)
+ /**
+ * Converts the given linear day into era, year, month,
+ * day_of_year, day_of_month, day_of_week, and writes the result
+ * into the fields array.
+ * @param day the linear day.
+ */
+ private void calculateDay(int day, boolean gregorian)
{
- if (fld >= ZONE_OFFSET)
- throw new IllegalArgumentException("bad field to roll");
+ // the epoch is a Thursday.
+ int weekday = (day + THURSDAY) % 7;
+ if (weekday <= 0)
+ weekday += 7;
+ fields[DAY_OF_WEEK] = weekday;
+
+ // get a first approximation of the year. This may be one
+ // year to big.
+ int year = 1970 + (gregorian
+ ? ((day - 100) * 400) / (365 * 400 + 100 - 4 + 1)
+ : ((day - 100) * 4) / (365 * 4 + 1));
+ if (day >= 0)
+ year++;
+
+ int firstDayOfYear = getLinearDay(year, 1, gregorian);
+
+ // Now look in which year day really lies.
+ if (day < firstDayOfYear)
+ {
+ year--;
+ firstDayOfYear = getLinearDay(year, 1, gregorian);
+ }
+
+ day -= firstDayOfYear - 1; // day of year, one based.
- int old = fields[fld];
- if (up)
+ fields[DAY_OF_YEAR] = day;
+ if (year <= 0)
{
- fields[fld] = old == getMaximum(fld) ? getMinimum(fld)
- : old + 1;
+ fields[ERA] = BC;
+ fields[YEAR] = 1 - year;
}
else
{
- fields[fld] = old == getMinimum(fld) ? getMaximum(fld)
- : old - 1;
+ fields[ERA] = AD;
+ fields[YEAR] = year;
+ }
+
+ int leapday = isLeapYear(year, gregorian) ? 1 : 0;
+ if (day <= 31 + 28 + leapday)
+ {
+ fields[MONTH] = day / 32; // 31->JANUARY, 32->FEBRUARY
+ fields[DAY_OF_MONTH] = day - 31 * fields[MONTH];
+ }
+ else
+ {
+ // A few more magic formulas
+ int scaledDay = (day - leapday) * 5 + 8;
+ fields[MONTH] = scaledDay / (31 + 30 + 31 + 30 + 31);
+ fields[DAY_OF_MONTH] = (scaledDay % (31 + 30 + 31 + 30 + 31)) / 5 + 1;
}
}
- private void adjust (int fld)
+ /**
+ * Converts the milliseconds since the epoch UTC
+ * (<code>time</code>) to time fields
+ * (<code>fields</code>).
+ */
+ protected synchronized void computeFields()
{
- int value = fields[fld];
- int radix = maxs[fld] + 1;
- switch (fld)
+ boolean gregorian = (time >= gregorianCutover);
+
+ TimeZone zone = getTimeZone();
+ fields[ZONE_OFFSET] = zone.getRawOffset();
+ long localTime = time + fields[ZONE_OFFSET];
+
+ int day = (int) (localTime / (24 * 60 * 60 * 1000L));
+ int millisInDay = (int) (localTime % (24 * 60 * 60 * 1000L));
+ if (millisInDay < 0)
{
+ millisInDay += (24 * 60 * 60 * 1000);
+ day--;
+ }
+
+ calculateDay(day, gregorian);
+ fields[DST_OFFSET] =
+ zone.getOffset(fields[ERA], fields[YEAR], fields[MONTH],
+ fields[DAY_OF_MONTH], fields[DAY_OF_WEEK],
+ millisInDay) - fields[ZONE_OFFSET];
+
+ millisInDay += fields[DST_OFFSET];
+ if (millisInDay >= 24 * 60 * 60 * 1000)
+ {
+ millisInDay -= 24 * 60 * 60 * 1000;
+ calculateDay(++day, gregorian);
+ }
+
+ fields[DAY_OF_WEEK_IN_MONTH] = (fields[DAY_OF_MONTH] + 6) / 7;
+
+ // which day of the week are we (0..6), relative to getFirstDayOfWeek
+ int relativeWeekday = (7 + fields[DAY_OF_WEEK] - getFirstDayOfWeek()) % 7;
+
+ fields[WEEK_OF_MONTH] = (fields[DAY_OF_MONTH] - relativeWeekday + 6) / 7;
+
+ int weekOfYear = (fields[DAY_OF_YEAR] - relativeWeekday + 6) / 7;
+
+ // Do the Correction: getMinimalDaysInFirstWeek() is always in the
+ // first week.
+ int minDays = getMinimalDaysInFirstWeek();
+ int firstWeekday =
+ (7 + getWeekDay(fields[YEAR], minDays) - getFirstDayOfWeek()) % 7;
+ if (minDays - firstWeekday < 1)
+ weekOfYear++;
+ fields[WEEK_OF_YEAR] = weekOfYear;
+
+
+ int hourOfDay = millisInDay / (60 * 60 * 1000);
+ fields[AM_PM] = (hourOfDay < 12) ? AM : PM;
+ int hour = hourOfDay % 12;
+ fields[HOUR] = (hour == 0) ? 12 : hour;
+ fields[HOUR_OF_DAY] = hourOfDay;
+ millisInDay %= (60 * 60 * 1000);
+ fields[MINUTE] = millisInDay / (60 * 1000);
+ millisInDay %= (60 * 1000);
+ fields[SECOND] = millisInDay / (1000);
+ fields[MILLISECOND] = millisInDay % 1000;
+
+
+ areFieldsSet = isSet[ERA] = isSet[YEAR] = isSet[MONTH] =
+ isSet[WEEK_OF_YEAR] = isSet[WEEK_OF_MONTH] =
+ isSet[DAY_OF_MONTH] = isSet[DAY_OF_YEAR] = isSet[DAY_OF_WEEK] =
+ isSet[DAY_OF_WEEK_IN_MONTH] = isSet[AM_PM] = isSet[HOUR] =
+ isSet[HOUR_OF_DAY] = isSet[MINUTE] = isSet[SECOND] =
+ isSet[MILLISECOND] = isSet[ZONE_OFFSET] = isSet[DST_OFFSET] = true;
+
+ }
+
+ /**
+ * 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).
+ * @XXX Should we check if time zones, locale, cutover etc. are equal?
+ */
+ public boolean equals(Object o)
+ {
+ if (!(o instanceof GregorianCalendar))
+ return false;
+
+ GregorianCalendar cal = (GregorianCalendar) o;
+ return (cal.getTimeInMillis() == getTimeInMillis());
+ }
+
+// /**
+// * Compares the given calender with this.
+// * @param o the object to that we should compare.
+// * @return true, if the given object is a calendar, and this calendar
+// * represents a smaller time than the calender o.
+// */
+// public boolean before(Object o) {
+// if (!(o instanceof GregorianCalendar))
+// return false;
+
+// GregorianCalendar cal = (GregorianCalendar) o;
+// return (cal.getTimeInMillis() < getTimeInMillis());
+// }
+
+// /**
+// * Compares the given calender with this.
+// * @param o the object to that we should compare.
+// * @return true, if the given object is a calendar, and this calendar
+// * represents a bigger time than the calender o.
+// */
+// public boolean after(Object o) {
+// if (!(o instanceof GregorianCalendar))
+// return false;
+
+// GregorianCalendar cal = (GregorianCalendar) o;
+// return (cal.getTimeInMillis() > getTimeInMillis());
+// }
+
+ /**
+ * Adds the specified amount of time to the given time field. The
+ * amount may be negative to subtract the time. If the field overflows
+ * it does what you expect: Jan, 25 + 10 Days is Feb, 4.
+ * @param field the time field. One of the time field constants.
+ * @param amount the amount of time.
+ */
+ public void add(int field, int amount)
+ {
+ switch (field)
+ {
+ case YEAR:
+ complete();
+ fields[YEAR] += amount;
+ isTimeSet = false;
+ break;
case MONTH:
- case SECOND:
- case MILLISECOND:
- if (value >= radix)
+ complete();
+ int months = fields[MONTH] + amount;
+ fields[YEAR] += months / 12;
+ fields[MONTH] = months % 12;
+ if (fields[MONTH] < 0)
{
- int next = value / radix;
- fields[fld] = value - radix * next;
- fields[fld - 1] += next;
- adjust(fld - 1);
+ fields[MONTH] += 12;
+ fields[YEAR]--;
}
- else if (value < 0) // min[fld]
+ isTimeSet = false;
+ int maxDay = getActualMaximum(DAY_OF_MONTH);
+ if (fields[DAY_OF_MONTH] > maxDay)
{
- int next = (value - radix - 1) / radix;
- fields[fld] = value - radix * next;
- fields[fld - 1] += next;
- adjust(fld - 1);
+ fields[DAY_OF_MONTH] = maxDay;
+ isTimeSet = false;
}
break;
+ case DAY_OF_MONTH:
+ case DAY_OF_YEAR:
+ case DAY_OF_WEEK:
+ if (!isTimeSet)
+ computeTime();
+ time += amount * (24 * 60 * 60 * 1000L);
+ areFieldsSet = false;
+ break;
+ case WEEK_OF_YEAR:
+ case WEEK_OF_MONTH:
+ case DAY_OF_WEEK_IN_MONTH:
+ if (!isTimeSet)
+ computeTime();
+ time += amount * (7 * 24 * 60 * 60 * 1000L);
+ areFieldsSet = false;
+ break;
+ case AM_PM:
+ if (!isTimeSet)
+ computeTime();
+ time += amount * (12 * 60 * 60 * 1000L);
+ areFieldsSet = false;
+ break;
+ case HOUR:
+ case HOUR_OF_DAY:
+ if (!isTimeSet)
+ computeTime();
+ time += amount * (60 * 60 * 1000L);
+ areFieldsSet = false;
+ break;
+ case MINUTE:
+ if (!isTimeSet)
+ computeTime();
+ time += amount * (60 * 1000L);
+ areFieldsSet = false;
+ break;
+ case SECOND:
+ if (!isTimeSet)
+ computeTime();
+ time += amount * (1000L);
+ areFieldsSet = false;
+ break;
+ case MILLISECOND:
+ if (!isTimeSet)
+ computeTime();
+ time += amount;
+ areFieldsSet = false;
+ break;
+ case ZONE_OFFSET:
+ complete();
+ fields[ZONE_OFFSET] += amount;
+ time -= amount;
+ break;
+ case DST_OFFSET:
+ complete();
+ fields[DST_OFFSET] += amount;
+ isTimeSet = false;
+ break;
+ default:
+ throw new IllegalArgumentException
+ ("Unknown Calendar field: " + field);
}
}
- public final Date getGregorianChange() { return new Date(gregorianCutover); }
- public void setGregorianChange (Date date)
- { gregorianCutover = date.getTime(); }
- public boolean isLeapYear(int year)
+ /**
+ * 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.
+ *
+ * <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.
+ * This requires lenient settings.
+ *
+ * @param field the time field. One of the time field constants.
+ * @param up the direction, true for up, false for down.
+ */
+ public void roll(int field, boolean up)
{
- if ((year % 4) != 0)
- return false;
- if ((year % 100) != 0 || (year % 400) == 0)
- return true;
- // year divisible by 100 but not 400.
- GregorianCalendar date = new GregorianCalendar(year, FEBRUARY, 28);
- return gregorianCutover < date.getTimeInMillis();
+ roll(field, up ? 1 : -1);
}
- public boolean after (Object cal)
+ private void cleanUpAfterRoll(int field, int delta)
{
- return cal instanceof Calendar
- && getTimeInMillis() > ((Calendar) cal).getTimeInMillis();
+ switch (field)
+ {
+ case ERA:
+ case YEAR:
+ case MONTH:
+ // check that day of month is still in correct range
+ if (fields[DAY_OF_MONTH] > getActualMaximum(DAY_OF_MONTH))
+ fields[DAY_OF_MONTH] = getActualMaximum(DAY_OF_MONTH);
+ isTimeSet = false;
+ isSet[WEEK_OF_MONTH] = false;
+ isSet[DAY_OF_WEEK] = false;
+ isSet[DAY_OF_WEEK_IN_MONTH] = false;
+ isSet[DAY_OF_YEAR] = false;
+ isSet[WEEK_OF_YEAR] = false;
+ break;
+
+ case DAY_OF_MONTH:
+ isSet[WEEK_OF_MONTH] = false;
+ isSet[DAY_OF_WEEK] = false;
+ isSet[DAY_OF_WEEK_IN_MONTH] = false;
+ isSet[DAY_OF_YEAR] = false;
+ isSet[WEEK_OF_YEAR] = false;
+ time += delta * (24 * 60 * 60 * 1000L);
+ break;
+
+ case WEEK_OF_MONTH:
+ isSet[DAY_OF_MONTH] = false;
+ isSet[DAY_OF_WEEK_IN_MONTH] = false;
+ isSet[DAY_OF_YEAR] = false;
+ isSet[WEEK_OF_YEAR] = false;
+ time += delta * (7 * 24 * 60 * 60 * 1000L);
+ break;
+ case DAY_OF_WEEK_IN_MONTH:
+ isSet[DAY_OF_MONTH] = false;
+ isSet[WEEK_OF_MONTH] = false;
+ isSet[DAY_OF_YEAR] = false;
+ isSet[WEEK_OF_YEAR] = false;
+ time += delta * (7 * 24 * 60 * 60 * 1000L);
+ break;
+ case DAY_OF_YEAR:
+ isSet[MONTH] = false;
+ isSet[DAY_OF_MONTH] = false;
+ isSet[WEEK_OF_MONTH] = false;
+ isSet[DAY_OF_WEEK_IN_MONTH] = false;
+ isSet[DAY_OF_WEEK] = false;
+ isSet[WEEK_OF_YEAR] = false;
+ time += delta * (24 * 60 * 60 * 1000L);
+ break;
+ case WEEK_OF_YEAR:
+ isSet[MONTH] = false;
+ isSet[DAY_OF_MONTH] = false;
+ isSet[WEEK_OF_MONTH] = false;
+ isSet[DAY_OF_WEEK_IN_MONTH] = false;
+ isSet[DAY_OF_YEAR] = false;
+ time += delta * (7 * 24 * 60 * 60 * 1000L);
+ break;
+
+ case AM_PM:
+ isSet[HOUR_OF_DAY] = false;
+ time += delta * (12 * 60 * 60 * 1000L);
+ break;
+ case HOUR:
+ isSet[HOUR_OF_DAY] = false;
+ time += delta * (60 * 60 * 1000L);
+ break;
+ case HOUR_OF_DAY:
+ isSet[HOUR] = false;
+ isSet[AM_PM] = false;
+ time += delta * (60 * 60 * 1000L);
+ break;
+
+ case MINUTE:
+ time += delta * (60 * 1000L);
+ break;
+ case SECOND:
+ time += delta * (1000L);
+ break;
+ case MILLISECOND:
+ time += delta;
+ break;
+ }
}
- public boolean before (Object cal)
+ /**
+ * Rolls the specified time field by the given amount. This means
+ * add amount 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 and vice versa for negative amounts.
+ *
+ * <strong>Note:</strong> There may be situation, where the other
+ * fields must be changed, e.g rolling the month on May, 31.
+ * The date June, 31 is automatically corrected to June, 30.
+ *
+ * @param field the time field. One of the time field constants.
+ * @param amount the amount by which we should roll.
+ */
+ public void roll(int field, int amount)
{
- return cal instanceof Calendar
- && getTimeInMillis() < ((Calendar) cal).getTimeInMillis();
+ switch (field)
+ {
+ case DAY_OF_WEEK:
+ // day of week is special: it rolls automatically
+ add(field, amount);
+ return;
+ case ZONE_OFFSET:
+ case DST_OFFSET:
+ throw new IllegalArgumentException("Can't roll time zone");
+ }
+ complete();
+ int min = getActualMinimum(field);
+ int range = getActualMaximum(field) - min + 1;
+ int oldval = fields[field];
+ int newval = (oldval - min + range + amount) % range + min;
+ if (newval < min)
+ newval += range;
+ fields[field] = newval;
+ cleanUpAfterRoll(field, newval - oldval);
}
- public boolean equals (Object obj)
+ private static final int[] minimums =
+ { BC, 1, 1, 0, 1, 1, 1, SUNDAY, 1,
+ AM, 1, 0, 1, 1, 1, -(12*60*60*1000), 0 };
+
+ private static final int[] maximums =
+ { AD, 5000000, 12, 53, 5, 31, 366, SATURDAY, 5,
+ PM, 12, 23, 59, 59, 999, +(12*60*60*1000), (12*60*60*1000) };
+
+ /**
+ * Gets the smallest value that is allowed for the specified field.
+ * @param field the time field. One of the time field constants.
+ * @return the smallest value.
+ */
+ public int getMinimum(int field)
{
- if (obj == null || ! (obj instanceof GregorianCalendar))
- return false;
- GregorianCalendar other = (GregorianCalendar) obj;
+ return minimums[field];
+ }
- for (int i = FIELD_COUNT; --i >= 0; )
+ /**
+ * 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 int getMaximum(int field)
+ {
+ return maximums[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 int getGreatestMinimum(int field)
+ {
+ if (field == WEEK_OF_YEAR)
+ return 1;
+ return minimums[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.
+ * @since jdk1.2
+ */
+ public int getLeastMaximum(int field)
+ {
+ switch (field)
{
- boolean set = isSet[i];
- if (set != other.isSet[i]
- || (set && fields[i] != other.fields[i]))
- return false;
+ case WEEK_OF_YEAR:
+ return 52;
+ case DAY_OF_MONTH:
+ return 28;
+ case DAY_OF_YEAR:
+ return 365;
+ case DAY_OF_WEEK_IN_MONTH:
+ case WEEK_OF_MONTH:
+ return 4;
+ default:
+ return maximums[field];
}
- if (areFieldsSet != other.areFieldsSet
- || isTimeSet != other.isTimeSet
- || (isTimeSet && time != other.time)
- || getFirstDayOfWeek() != other.getFirstDayOfWeek()
- || getMinimalDaysInFirstWeek() != other.getMinimalDaysInFirstWeek()
- || isLenient() != other.isLenient()
- || ! getTimeZone().equals(other.getTimeZone()))
- return false;
- return true;
}
- public int hashCode ()
+ /**
+ * Gets the actual minimum value that is allowed for the specified field.
+ * This value is dependant on the values of the other fields. Note that
+ * this calls <code>complete()</code> if not enough fields are set. This
+ * can have ugly side effects.
+ * @param field the time field. One of the time field constants.
+ * @return the actual minimum value.
+ * @since jdk1.2
+ */
+ public int getActualMinimum(int field)
+ {
+ if (field == WEEK_OF_YEAR)
+ {
+ int min = getMinimalDaysInFirstWeek();
+ if (min == 0)
+ return 1;
+ if (!areFieldsSet || !isSet[ERA] || !isSet[YEAR])
+ complete();
+
+ int year = fields[ERA] == AD ? fields[YEAR] : 1 - fields[YEAR];
+ int weekday = getWeekDay(year, min);
+ if ((7 + weekday - getFirstDayOfWeek()) % 7 >= min - 1)
+ return 1;
+ return 0;
+ }
+ return minimums[field];
+ }
+
+ /**
+ * Gets the actual maximum value that is allowed for the specified field.
+ * This value is dependant on the values of the other fields. Note that
+ * this calls <code>complete()</code> if not enough fields are set. This
+ * can have ugly side effects.
+ * @param field the time field. One of the time field constants.
+ * @return the actual maximum value.
+ */
+ public int getActualMaximum(int field)
{
- int hashcode = 0;
- for (int i = FIELD_COUNT; --i >= 0; )
+ switch (field)
{
- if (isSet[i])
- hashcode += 37 * fields[i];
+ case WEEK_OF_YEAR:
+ {
+ if (!areFieldsSet || !isSet[ERA] || !isSet[YEAR])
+ complete();
+ // This is wrong for the year that contains the gregorian change.
+ // I.e it gives the weeks in the julian year or in the gregorian
+ // year in that case.
+ int year = fields[ERA] == AD ? fields[YEAR] : 1 - fields[YEAR];
+ int lastDay = isLeapYear(year) ? 366 : 365;
+ int weekday = getWeekDay(year, lastDay);
+ int week = (lastDay + 6
+ - (7 + weekday - getFirstDayOfWeek()) % 7) / 7;
+
+ int minimalDays = getMinimalDaysInFirstWeek();
+ int firstWeekday = getWeekDay(year, minimalDays);
+ if (minimalDays - (7 + firstWeekday - getFirstDayOfWeek()) % 7 < 1)
+ return week + 1;
+ }
+ case DAY_OF_MONTH:
+ {
+ if (!areFieldsSet || !isSet[MONTH])
+ complete();
+ int month = fields[MONTH];
+ // If you change this, you should also change
+ // SimpleTimeZone.getDaysInMonth();
+ if (month == FEBRUARY)
+ {
+ if (!isSet[YEAR] || !isSet[ERA])
+ complete();
+ int year = fields[ERA] == AD ? fields[YEAR] : 1 - fields[YEAR];
+ return isLeapYear(year) ? 29 : 28;
+ }
+ else if (month < AUGUST)
+ return 31 - (month & 1);
+ else
+ return 30 + (month & 1);
+ }
+ case DAY_OF_YEAR:
+ {
+ if (!areFieldsSet || !isSet[ERA] || !isSet[YEAR])
+ complete();
+ int year = fields[ERA] == AD ? fields[YEAR] : 1 - fields[YEAR];
+ return isLeapYear(year) ? 366 : 365;
+ }
+ case DAY_OF_WEEK_IN_MONTH:
+ {
+ // This is wrong for the month that contains the gregorian change.
+ int daysInMonth = getActualMaximum(DAY_OF_MONTH);
+ // That's black magic, I know
+ return (daysInMonth - (fields[DAY_OF_MONTH] - 1) % 7 + 6) / 7;
+ }
+ case WEEK_OF_MONTH:
+ {
+ int daysInMonth = getActualMaximum(DAY_OF_MONTH);
+ int weekday = (daysInMonth - fields[DAY_OF_MONTH]
+ + fields[DAY_OF_WEEK] - SUNDAY) % 7 + SUNDAY;
+ return (daysInMonth + 6
+ - (7 + weekday - getFirstDayOfWeek()) % 7) / 7;
+ }
+ default:
+ return maximums[field];
}
- if (isTimeSet)
- hashcode += 89 * time;
- return hashcode;
}
}
diff --git a/libjava/java/util/natGregorianCalendar.cc b/libjava/java/util/natGregorianCalendar.cc
deleted file mode 100644
index 34b49969b45..00000000000
--- a/libjava/java/util/natGregorianCalendar.cc
+++ /dev/null
@@ -1,159 +0,0 @@
-/* Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation
-
- 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. */
-
-#include <config.h>
-
-#ifdef ECOS
-#include <string.h>
-#endif
-
-#include <gcj/cni.h>
-#include <java/util/TimeZone.h>
-#include <java/util/GregorianCalendar.h>
-#include <java/lang/IllegalArgumentException.h>
-#include <time.h>
-
-void
-java::util::GregorianCalendar::computeTime ()
-{
- struct tm tim;
- tim.tm_sec = elements(fields)[SECOND];
- tim.tm_min = elements(fields)[MINUTE];
- tim.tm_hour = elements(fields)[HOUR_OF_DAY];
- tim.tm_mday = elements(fields)[DATE];
- tim.tm_mon = elements(fields)[MONTH];
- tim.tm_year = elements(fields)[YEAR] - 1900;
- tim.tm_isdst = 0;
-#ifndef ECOS
- // FIXME: None of the standard C library access to the ECOS calendar
- // is yet available.
- time_t t = mktime (&tim);
-
- if (!isLenient ())
- {
- // mktime will correct for any time leniencies (e.g. 31-Apr becomes
- // 1-May).
- // Daylight savings time is a special case since times in hour 23
- // will compute to hour 0 of the next day.
- if (tim.tm_isdst == 0 || elements(fields)[HOUR_OF_DAY] != 23)
- {
- if (tim.tm_sec != elements(fields)[SECOND] ||
- tim.tm_min != elements(fields)[MINUTE] ||
- tim.tm_hour != elements(fields)[HOUR_OF_DAY] +
- (tim.tm_isdst > 0 ? 1 : 0) ||
- tim.tm_mday != elements(fields)[DATE] ||
- tim.tm_mon != elements(fields)[MONTH] ||
- tim.tm_year != elements(fields)[YEAR] - 1900)
- throw new java::lang::IllegalArgumentException ();
- }
- else
- {
- // The easiest thing to do is to temporarily shift the clock
- // back from the 23th hour so mktime doesn't cause the extra
- // hour for DST to roll the date to the next day.
- struct tm tmp_tim;
- tmp_tim.tm_sec = elements(fields)[SECOND];
- tmp_tim.tm_min = elements(fields)[MINUTE];
- tmp_tim.tm_hour = elements(fields)[HOUR_OF_DAY] - 1;
- tmp_tim.tm_mday = elements(fields)[DATE];
- tmp_tim.tm_mon = elements(fields)[MONTH];
- tmp_tim.tm_year = elements(fields)[YEAR] - 1900;
- tmp_tim.tm_isdst = 0;
- mktime (&tmp_tim);
- if (tmp_tim.tm_sec != elements(fields)[SECOND] ||
- tmp_tim.tm_min != elements(fields)[MINUTE] ||
- tmp_tim.tm_hour != elements(fields)[HOUR_OF_DAY] ||
- tmp_tim.tm_mday != elements(fields)[DATE] ||
- tmp_tim.tm_mon != elements(fields)[MONTH] ||
- tmp_tim.tm_year != elements(fields)[YEAR] - 1900)
- throw new java::lang::IllegalArgumentException ();
- }
- }
-#else
- time_t t = 0;
-#endif
-
- // Adjust for local timezone (introduced by mktime) and our
- // timezone.
-#if defined (STRUCT_TM_HAS_GMTOFF)
- t -= tim.tm_gmtoff;
-#elif defined (HAVE_TIMEZONE)
- t += timezone;
-#endif
- // Adjust for milliseconds.
- time = t * (jlong) 1000 + elements(fields)[MILLISECOND];
-
- // Now adjust for the real timezone, i.e. our timezone, which is in millis.
- java::util::TimeZone *zone = getTimeZone ();
- time += zone->getRawOffset();
-
- isTimeSet = true;
-}
-
-void
-java::util::GregorianCalendar::computeFields ()
-{
- time_t t = time / 1000;
- int millis = time % 1000;
- if (t < 0 && millis != 0)
- {
- t--;
- millis = t - 1000 * t;
- }
- elements(fields)[MILLISECOND] = millis;
- struct tm tim;
- java::util::TimeZone *zone = getTimeZone ();
-
- // FIXME: None of the standard C library access to the ECOS calendar
- // is yet available.
-#ifdef ECOS
- memset (&tim, 0, sizeof tim);
-#else
- if (zone->getRawOffset() == 0 || ! zone->useDaylightTime())
- {
-#if defined(__JV_POSIX_THREADS__) && defined(HAVE_GMTIME_R)
- gmtime_r (&t, &tim);
-#else
- // Get global lock (because gmtime uses a global buffer). FIXME
- tim = *(struct tm*) gmtime (&t);
- // Release global lock. FIXME
-#endif
- }
- else
- {
-#if defined(__JV_POSIX_THREADS__) && defined(HAVE_LOCALTIME_R)
- localtime_r (&t, &tim);
-#else
- // Get global lock (because localtime uses a global buffer). FIXME
- tim = *(struct tm*) localtime (&t);
- // Release global lock. FIXME
-#endif
- }
-#endif /* ECOS */
- elements(fields)[SECOND] = tim.tm_sec;
- elements(fields)[MINUTE] = tim.tm_min;
- elements(fields)[HOUR_OF_DAY] = tim.tm_hour;
- elements(fields)[AM_PM] = tim.tm_hour < 12 ? AM : PM;
- elements(fields)[HOUR] = tim.tm_hour % 12;
- elements(fields)[DATE] = tim.tm_mday;
- elements(fields)[MONTH] = tim.tm_mon;
- elements(fields)[YEAR] = 1900 + tim.tm_year;
- elements(fields)[DAY_OF_WEEK] = tim.tm_wday + 1;
- elements(fields)[DAY_OF_WEEK_IN_MONTH] = ((tim.tm_mday - 1) / 7) + 1;
- elements(fields)[DAY_OF_YEAR] = tim.tm_yday + 1;
- elements(fields)[WEEK_OF_MONTH]
- = (tim.tm_mday + 6 + (5 - tim.tm_wday + getFirstDayOfWeek()) % 7) / 7;
- elements(fields)[WEEK_OF_YEAR]
- = (tim.tm_yday + 7 + (5 - tim.tm_wday + getFirstDayOfWeek()) % 7) / 7;
- elements(fields)[ERA] = AD;
- 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;
-}