Commit a22add72 by Warren Levy Committed by Warren Levy

Makefile.am: Added natTimeZone.cc.

	* Makefile.am: Added natTimeZone.cc.
	* Makefile.in: Rebuilt.
	* gnu/gcj/text/LocaleData_en.java: Added DateFormat entries.
	* java/text/DateFormatSymbols.java (ampms): Made package private.
	(eras): Made package private.
	(months): Made package private.
	(shortMonths): Made package private.
	(shortWeekdays): Made package private.
	(weekdays): Made package private.
	(formatPrefixes): New private field.
	(localPatternCharsDefault): Made private.
	(dateFormats): New package private field.
	(timeFormats): New package private field.
	(formatsForKey): New private method.
	(DateFormatSymbols(Locale)): Set dateFormats and timeFormats.
	(DateFormatSymbols(DateFormatSymbols)): Ditto.
	* java/text/SimpleDateFormat.java: Merged with Classpath.
	* java/util/TimeZone.java: Merged with Classpath.
	* java/util/natTimeZone.cc: New file.

From-SVN: r37808
parent 9734e80c
2000-11-27 Warren Levy <warrenl@cygnus.com>
* Makefile.am: Added natTimeZone.cc.
* Makefile.in: Rebuilt.
* gnu/gcj/text/LocaleData_en.java: Added DateFormat entries.
* java/text/DateFormatSymbols.java (ampms): Made package private.
(eras): Made package private.
(months): Made package private.
(shortMonths): Made package private.
(shortWeekdays): Made package private.
(weekdays): Made package private.
(formatPrefixes): New private field.
(localPatternCharsDefault): Made private.
(dateFormats): New package private field.
(timeFormats): New package private field.
(formatsForKey): New private method.
(DateFormatSymbols(Locale)): Set dateFormats and timeFormats.
(DateFormatSymbols(DateFormatSymbols)): Ditto.
* java/text/SimpleDateFormat.java: Merged with Classpath.
* java/util/TimeZone.java: Merged with Classpath.
* java/util/natTimeZone.cc: New file.
2000-11-27 Bryce McKinlay <bryce@albatross.co.nz>
* java/util/Vector.java (ensureCapacity): Don't increment modCount.
......
......@@ -1229,6 +1229,7 @@ java/net/natPlainDatagramSocketImpl.cc \
java/net/natPlainSocketImpl.cc \
java/text/natCollator.cc \
java/util/natGregorianCalendar.cc \
java/util/natTimeZone.cc \
java/util/zip/natDeflater.cc \
java/util/zip/natInflater.cc
......
......@@ -991,6 +991,7 @@ java/net/natPlainDatagramSocketImpl.cc \
java/net/natPlainSocketImpl.cc \
java/text/natCollator.cc \
java/util/natGregorianCalendar.cc \
java/util/natTimeZone.cc \
java/util/zip/natDeflater.cc \
java/util/zip/natInflater.cc
......@@ -1142,8 +1143,8 @@ 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/natGregorianCalendar.lo java/util/natTimeZone.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 \
......@@ -1684,8 +1685,9 @@ DEP_FILES = .deps/$(srcdir)/$(CONVERT_DIR)/gen-from-JIS.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/natGregorianCalendar.P .deps/java/util/natTimeZone.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 \
......
......@@ -68,6 +68,16 @@ public final class LocaleData_en extends ListResourceBundle
{ "shortWeekdays", shortWeekdaysDefault },
{ "weekdays", weekdaysDefault },
// These are for DateFormat.
{ "shortDateFormat", "M/d/yy" }, // Java's Y2K bug.
{ "mediumDateFormat", "d-MMM-yy" },
{ "longDateFormat", "MMMM d, yyyy" },
{ "fullDateFormat", "EEEE MMMM d, yyyy G" },
{ "shortTimeFormat", "h:mm a" },
{ "mediumTimeFormat", "h:mm:ss a" },
{ "longTimeFormat", "h:mm:ss a z" },
{ "fullTimeFormat", "h:mm:ss;S 'o''clock' a z" },
// For RuleBasedCollator.
// FIXME: this is nowhere near complete.
// In particular we must mark accents as ignorable,
......
......@@ -24,21 +24,29 @@ import java.util.ResourceBundle;
public class DateFormatSymbols extends Object
implements java.io.Serializable, Cloneable
{
private String[] ampms;
private String[] eras;
String[] ampms;
String[] eras;
private String localPatternChars;
private String[] months;
private String[] shortMonths;
private String[] shortWeekdays;
private String[] weekdays;
String[] months;
String[] shortMonths;
String[] shortWeekdays;
String[] weekdays;
private String[][] zoneStrings;
private static final long serialVersionUID = -5987973545549424702L;
// The order of these prefixes must be the same as in DateFormat
// FIXME: XXX: Note that this differs from the Classpath implemention
// in that there is no "default" entry; that is due to differing
// implementations where DateFormat.DEFAULT is MEDIUM here but 4 in
// Classpath (the JCL says it should be MEDIUM). That will need to be
// resolved in the merge.
private static final String[] formatPrefixes = { "full", "long", "medium", "short" };
private static final String[] ampmsDefault = {"AM", "PM" };
private static final String[] erasDefault = {"BC", "AD" };
// localPatternCharsDefault is used by SimpleDateFormat.
protected static final String localPatternCharsDefault
private static final String localPatternCharsDefault
= "GyMdkHmsSEDFwWahKz";
private static final String[] monthsDefault = {
"January", "February", "March", "April", "May", "June",
......@@ -77,6 +85,24 @@ public class DateFormatSymbols extends Object
/**/ "Alaska Daylight Time", "ADT", "Anchorage" }
};
// These are each arrays with a value for SHORT, MEDIUM, LONG, FULL,
// and DEFAULT (constants defined in java.text.DateFormat). While
// not part of the official spec, we need a way to get at locale-specific
// default formatting patterns. They are declared package scope so
// as to be easily accessible where needed (DateFormat, SimpleDateFormat).
transient String[] dateFormats;
transient String[] timeFormats;
private String[] formatsForKey(ResourceBundle res, String key)
{
String[] values = new String [formatPrefixes.length];
for (int i = 0; i < formatPrefixes.length; i++)
{
values[i] = res.getString(formatPrefixes[i]+key);
}
return values;
}
private final Object safeGetResource (ResourceBundle res,
String key, Object def)
{
......@@ -116,6 +142,9 @@ public class DateFormatSymbols extends Object
weekdays = (String[]) safeGetResource (res, "weekdays", weekdaysDefault);
zoneStrings = (String[][]) safeGetResource (res, "zoneStrings",
zoneStringsDefault);
dateFormats = formatsForKey(res, "DateFormat");
timeFormats = formatsForKey(res, "TimeFormat");
}
public DateFormatSymbols ()
......@@ -134,6 +163,8 @@ public class DateFormatSymbols extends Object
shortWeekdays = old.shortWeekdays;
weekdays = old.weekdays;
zoneStrings = old.zoneStrings;
dateFormats = old.dateFormats;
timeFormats = old.timeFormats;
}
public String[] getAmPmStrings()
......
/* Copyright (C) 1998, 1999, 2000 Free Software Foundation
/* SimpleDateFormat.java -- A class for parsing/formating simple
date constructs
Copyright (C) 1998, 1999, 2000 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.text;
import java.util.*;
import java.util.Calendar;
import java.util.Date;
import java.util.Enumeration;
import java.util.GregorianCalendar;
import java.util.Locale;
import java.util.TimeZone;
import java.util.SimpleTimeZone;
import java.util.Vector;
import java.io.ObjectInputStream;
import java.io.IOException;
/**
* @author Per Bothner <bothner@cygnus.com>
* @date October 25, 1998.
*/
/* Written using "Java Class Libraries", 2nd edition, plus online
* API docs for JDK 1.2 beta from http://www.javasoft.com.
* Status: Believed complete and correct to 1.2.
* SimpleDateFormat provides convenient methods for parsing and formatting
* dates using Gregorian calendars (see java.util.GregorianCalendar).
*/
public class SimpleDateFormat extends DateFormat
{
// Serialization fields.
private Date defaultCenturyStart = new Date();
private DateFormatSymbols formatData;
/** A pair class used by SimpleDateFormat as a compiled representation
* of a format string.
*/
private class FieldSizePair
{
public int field;
public int size;
/** Constructs a pair with the given field and size values */
public FieldSizePair(int f, int s) {
field = f;
size = s;
}
}
private transient Vector tokens;
private DateFormatSymbols formatData; // formatData
private Date defaultCenturyStart =
new Date(System.currentTimeMillis() - (80*365*24*60*60*1000));
private String pattern;
private int serialVersionOnStream = 1;
private int serialVersionOnStream = 1; // 0 indicates JDK1.1.3 or earlier
private static final long serialVersionUID = 4774881970558875024L;
// Serialization method.
// This string is specified in the JCL. We set it here rather than
// do a DateFormatSymbols(Locale.US).getLocalPatternChars() since
// someone could theoretically change those values (though unlikely).
private static final String standardChars = "GyMdkHmsSEDFwWahKz";
private void readObject(ObjectInputStream stream)
throws IOException, ClassNotFoundException
{
stream.defaultReadObject();
if (serialVersionOnStream < 1)
{
defaultCenturyStart = new Date();
defaultCenturyStart =
new Date(System.currentTimeMillis() - (80*365*24*60*60*1000));
serialVersionOnStream = 1;
}
// Set up items normally taken care of by the constructor.
tokens = new Vector();
compileFormat(pattern);
}
public SimpleDateFormat ()
private void compileFormat(String pattern)
{
this("dd/MM/yy HH:mm", Locale.getDefault());
// Any alphabetical characters are treated as pattern characters
// unless enclosed in single quotes.
char thisChar;
int pos;
int field;
FieldSizePair current = null;
for (int i=0; i<pattern.length(); i++) {
thisChar = pattern.charAt(i);
field = formatData.getLocalPatternChars().indexOf(thisChar);
if (field == -1) {
current = null;
if (Character.isLetter(thisChar)) {
// Not a valid letter
tokens.addElement(new FieldSizePair(-1,0));
} else if (thisChar == '\'') {
// Quoted text section; skip to next single quote
pos = pattern.indexOf('\'',i+1);
if (pos == -1) {
// This ought to be an exception, but spec does not
// let us throw one.
tokens.addElement(new FieldSizePair(-1,0));
}
if ((pos+1 < pattern.length()) && (pattern.charAt(pos+1) == '\'')) {
tokens.addElement(pattern.substring(i+1,pos+1));
} else {
tokens.addElement(pattern.substring(i+1,pos));
}
i = pos;
} else {
// A special character
tokens.addElement(new Character(thisChar));
}
} else {
// A valid field
if ((current != null) && (field == current.field)) {
current.size++;
} else {
current = new FieldSizePair(field,1);
tokens.addElement(current);
}
}
}
}
public SimpleDateFormat (String pattern)
public String toString()
{
this(pattern, Locale.getDefault());
StringBuffer output = new StringBuffer();
Enumeration e = tokens.elements();
while (e.hasMoreElements()) {
output.append(e.nextElement().toString());
}
return output.toString();
}
public SimpleDateFormat (String pattern, Locale locale)
/**
* Constructs a SimpleDateFormat using the default pattern for
* the default locale.
*/
public SimpleDateFormat()
{
this.pattern = pattern;
this.calendar = Calendar.getInstance(locale);
this.numberFormat = NumberFormat.getInstance(locale);
numberFormat.setGroupingUsed(false);
this.formatData = new DateFormatSymbols (locale);
/*
* There does not appear to be a standard API for determining
* what the default pattern for a locale is, so use package-scope
* variables in DateFormatSymbols to encapsulate this.
*/
super();
Locale locale = Locale.getDefault();
calendar = new GregorianCalendar(locale);
tokens = new Vector();
formatData = new DateFormatSymbols(locale);
pattern = formatData.dateFormats[DEFAULT]+' '+formatData.timeFormats[DEFAULT];
compileFormat(pattern);
numberFormat = NumberFormat.getInstance(locale);
}
public SimpleDateFormat (String pattern, DateFormatSymbols formatData)
/**
* Creates a date formatter using the specified pattern, with the default
* DateFormatSymbols for the default locale.
*/
public SimpleDateFormat(String pattern)
{
this.pattern = pattern;
this.formatData = formatData;
this.calendar = Calendar.getInstance();
this.numberFormat = NumberFormat.getInstance();
numberFormat.setGroupingUsed(false);
this(pattern, Locale.getDefault());
}
public Date get2DigitYearStart()
/**
* Creates a date formatter using the specified pattern, with the default
* DateFormatSymbols for the given locale.
*/
public SimpleDateFormat(String pattern, Locale locale)
{
return defaultCenturyStart;
super();
calendar = new GregorianCalendar(locale);
tokens = new Vector();
formatData = new DateFormatSymbols(locale);
compileFormat(pattern);
this.pattern = pattern;
numberFormat = NumberFormat.getInstance(locale);
}
public void set2DigitYearStart(Date startDate)
{
defaultCenturyStart = startDate;
/**
* Creates a date formatter using the specified pattern. The
* specified DateFormatSymbols will be used when formatting.
*/
public SimpleDateFormat(String pattern, DateFormatSymbols formatData) {
super();
calendar = new GregorianCalendar();
// FIXME: XXX: Is it really necessary to set the timezone?
// The Calendar constructor is supposed to take care of this.
calendar.setTimeZone(TimeZone.getDefault());
tokens = new Vector();
this.formatData = formatData;
compileFormat(pattern);
this.pattern = pattern;
numberFormat = NumberFormat.getInstance();
}
public DateFormatSymbols getDateFormatSymbols ()
// What is the difference between localized and unlocalized? The
// docs don't say.
/**
* This method returns a string with the formatting pattern being used
* by this object. This string is unlocalized.
*
* @return The format string.
*/
public String toPattern()
{
return formatData;
return pattern;
}
public void setDateFormatSymbols (DateFormatSymbols value)
/**
* This method returns a string with the formatting pattern being used
* by this object. This string is localized.
*
* @return The format string.
*/
public String toLocalizedPattern()
{
formatData = value;
String localChars = formatData.getLocalPatternChars();
return applyLocalizedPattern (pattern, standardChars, localChars);
}
public String toPattern ()
/**
* This method sets the formatting pattern that should be used by this
* object. This string is not localized.
*
* @param pattern The new format pattern.
*/
public void applyPattern(String pattern)
{
return pattern;
tokens = new Vector();
compileFormat(pattern);
this.pattern = pattern;
}
public void applyPattern (String pattern)
/**
* This method sets the formatting pattern that should be used by this
* object. This string is localized.
*
* @param pattern The new format pattern.
*/
public void applyLocalizedPattern(String pattern)
{
this.pattern = pattern;
String localChars = formatData.getLocalPatternChars();
pattern = applyLocalizedPattern (pattern, localChars, standardChars);
applyPattern(pattern);
}
private String applyLocalizedPattern (String pattern,
private String applyLocalizedPattern(String pattern,
String oldChars, String newChars)
{
int len = pattern.length();
......@@ -122,424 +283,874 @@ public class SimpleDateFormat extends DateFormat
return buf.toString();
}
public void applyLocalizedPattern (String pattern)
/**
* Returns the start of the century used for two digit years.
*
* @return A <code>Date</code> representing the start of the century
* for two digit years.
*/
public Date get2DigitYearStart()
{
String localChars = formatData.getLocalPatternChars();
String standardChars = DateFormatSymbols.localPatternCharsDefault;
pattern = applyLocalizedPattern (pattern, localChars, standardChars);
applyPattern(pattern);
return defaultCenturyStart;
}
public String toLocalizedPattern ()
/**
* Sets the start of the century used for two digit years.
*
* @param date A <code>Date</code> representing the start of the century for
* two digit years.
*/
public void set2DigitYearStart(Date date)
{
String localChars = formatData.getLocalPatternChars();
String standardChars = DateFormatSymbols.localPatternCharsDefault;
return applyLocalizedPattern (pattern, standardChars, localChars);
defaultCenturyStart = date;
}
private final void append (StringBuffer buf, int value, int numDigits)
/**
* This method returns the format symbol information used for parsing
* and formatting dates.
*
* @return The date format symbols.
*/
public DateFormatSymbols getDateFormatSymbols()
{
numberFormat.setMinimumIntegerDigits(numDigits);
numberFormat.format(value, buf, null);
return formatData;
}
public StringBuffer format (Date date, StringBuffer buf, FieldPosition pos)
{
Calendar calendar = (Calendar) this.calendar.clone();
calendar.setTime(date);
int len = pattern.length();
int quoteStart = -1;
for (int i = 0; i < len; i++)
{
char ch = pattern.charAt(i);
if (ch == '\'')
/**
* This method sets the format symbols information used for parsing
* and formatting dates.
*
* @param formatData The date format symbols.
*/
public void setDateFormatSymbols(DateFormatSymbols formatData)
{
// We must do a little lookahead to see if we have two
// single quotes embedded in quoted text.
if (i < len - 1 && pattern.charAt(i + 1) == '\'')
this.formatData = formatData;
}
/**
* This methods tests whether the specified object is equal to this
* object. This will be true if and only if the specified object:
* <p>
* <ul>
* <li>Is not <code>null</code>.
* <li>Is an instance of <code>SimpleDateFormat</code>.
* <li>Is equal to this object at the superclass (i.e., <code>DateFormat</code>)
* level.
* <li>Has the same formatting pattern.
* <li>Is using the same formatting symbols.
* <li>Is using the same century for two digit years.
* </ul>
*
* @param obj The object to compare for equality against.
*
* @return <code>true</code> if the specified object is equal to this object,
* <code>false</code> otherwise.
*/
public boolean equals(Object o)
{
++i;
buf.append(ch);
if (o == null)
return false;
if (!super.equals(o))
return false;
if (!(o instanceof SimpleDateFormat))
return false;
SimpleDateFormat sdf = (SimpleDateFormat)o;
if (!toPattern().equals(sdf.toPattern()))
return false;
if (!get2DigitYearStart().equals(sdf.get2DigitYearStart()))
return false;
if (!getDateFormatSymbols().equals(sdf.getDateFormatSymbols()))
return false;
return true;
}
/**
* Formats the date input according to the format string in use,
* appending to the specified StringBuffer. The input StringBuffer
* is returned as output for convenience.
*/
public StringBuffer format(Date date, StringBuffer buffer, FieldPosition pos) {
String temp;
Calendar theCalendar = (Calendar) calendar.clone();
theCalendar.setTime(date);
// go through vector, filling in fields where applicable, else toString
Enumeration e = tokens.elements();
while (e.hasMoreElements()) {
Object o = e.nextElement();
if (o instanceof FieldSizePair) {
FieldSizePair p = (FieldSizePair) o;
int beginIndex = buffer.length();
switch (p.field) {
case ERA_FIELD:
buffer.append(formatData.eras[theCalendar.get(Calendar.ERA)]);
break;
case YEAR_FIELD:
temp = String.valueOf(theCalendar.get(Calendar.YEAR));
if (p.size < 4)
buffer.append(temp.substring(temp.length()-2));
else
quoteStart = quoteStart < 0 ? i : -1;
}
// From JCL: any characters in the pattern that are not in
// the ranges of [a..z] and [A..Z] are treated as quoted
// text.
else if (quoteStart != -1
|| ((ch < 'a' || ch > 'z')
&& (ch < 'A' || ch > 'Z')))
buf.append(ch);
else
{
int first = i;
int value;
while (++i < len && pattern.charAt(i) == ch) ;
int count = i - first; // Number of repetions of ch in pattern.
int beginIndex = buf.length();
int field;
i--; // Skip all but last instance of ch in pattern.
switch (ch)
{
case 'd':
append(buf, calendar.get(Calendar.DATE), count);
field = DateFormat.DATE_FIELD;
break;
case 'D':
append(buf, calendar.get(Calendar.DAY_OF_YEAR), count);
field = DateFormat.DAY_OF_YEAR_FIELD;
break;
case 'F':
append(buf, calendar.get(Calendar.DAY_OF_WEEK_IN_MONTH),count);
field = DateFormat.DAY_OF_WEEK_IN_MONTH_FIELD;
break;
case 'E':
value = calendar.get(calendar.DAY_OF_WEEK);
buf.append(count <= 3 ? formatData.getShortWeekdays()[value]
: formatData.getWeekdays()[value]);
field = DateFormat.DAY_OF_WEEK_FIELD;
break;
case 'w':
append(buf, calendar.get(Calendar.WEEK_OF_YEAR), count);
field = DateFormat.WEEK_OF_YEAR_FIELD;
break;
case 'W':
append(buf, calendar.get(Calendar.WEEK_OF_MONTH), count);
field = DateFormat.WEEK_OF_MONTH_FIELD;
break;
case 'M':
value = calendar.get(Calendar.MONTH);
if (count <= 2)
append(buf, value + 1, count);
buffer.append(temp);
break;
case MONTH_FIELD:
if (p.size < 3)
withLeadingZeros(theCalendar.get(Calendar.MONTH)+1,p.size,buffer);
else if (p.size < 4)
buffer.append(formatData.shortMonths[theCalendar.get(Calendar.MONTH)]);
else
buf.append(count <= 3 ? formatData.getShortMonths()[value]
: formatData.getMonths()[value]);
field = DateFormat.MONTH_FIELD;
buffer.append(formatData.months[theCalendar.get(Calendar.MONTH)]);
break;
case 'y':
value = calendar.get(Calendar.YEAR);
append(buf, count <= 2 ? value % 100 : value, count);
field = DateFormat.YEAR_FIELD;
case DATE_FIELD:
withLeadingZeros(theCalendar.get(Calendar.DATE),p.size,buffer);
break;
case 'K':
append(buf, calendar.get(Calendar.HOUR), count);
field = DateFormat.HOUR0_FIELD;
case HOUR_OF_DAY1_FIELD: // 1-12
withLeadingZeros(theCalendar.get(Calendar.HOUR),p.size,buffer);
break;
case 'h':
value = ((calendar.get(Calendar.HOUR) + 11) % 12) + 1;
append(buf, value, count);
field = DateFormat.HOUR1_FIELD;
case HOUR_OF_DAY0_FIELD: // 0-23
withLeadingZeros(theCalendar.get(Calendar.HOUR_OF_DAY),p.size,buffer);
break;
case 'H':
append(buf, calendar.get(Calendar.HOUR_OF_DAY), count);
field = DateFormat.HOUR_OF_DAY0_FIELD;
case MINUTE_FIELD:
withLeadingZeros(theCalendar.get(Calendar.MINUTE),p.size,buffer);
break;
case 'k':
value = ((calendar.get(Calendar.HOUR_OF_DAY) + 23) % 24) + 1;
append(buf, value, count);
field = DateFormat.HOUR_OF_DAY1_FIELD;
case SECOND_FIELD:
withLeadingZeros(theCalendar.get(Calendar.SECOND),p.size,buffer);
break;
case 'm':
append(buf, calendar.get(Calendar.MINUTE), count);
field = DateFormat.MINUTE_FIELD;
case MILLISECOND_FIELD:
withLeadingZeros(theCalendar.get(Calendar.MILLISECOND),p.size,buffer);
break;
case 's':
append(buf, calendar.get(Calendar.SECOND), count);
field = DateFormat.SECOND_FIELD;
case DAY_OF_WEEK_FIELD:
if (p.size < 4)
buffer.append(formatData.shortWeekdays[theCalendar.get(Calendar.DAY_OF_WEEK)]);
else
buffer.append(formatData.weekdays[theCalendar.get(Calendar.DAY_OF_WEEK)]);
break;
case 'S':
append(buf, calendar.get(Calendar.MILLISECOND), count);
field = DateFormat.MILLISECOND_FIELD;
case DAY_OF_YEAR_FIELD:
withLeadingZeros(theCalendar.get(Calendar.DAY_OF_YEAR),p.size,buffer);
break;
case 'a':
value = calendar.get(calendar.AM_PM);
buf.append(formatData.getAmPmStrings()[value]);
field = DateFormat.AM_PM_FIELD;
case DAY_OF_WEEK_IN_MONTH_FIELD:
withLeadingZeros(theCalendar.get(Calendar.DAY_OF_WEEK_IN_MONTH),p.size,buffer);
break;
case 'z':
String zoneID = calendar.getTimeZone().getID();
String[][] zoneStrings = formatData.getZoneStrings();
int zoneCount = zoneStrings.length;
for (int j = 0; j < zoneCount; j++)
{
String[] strings = zoneStrings[j];
if (zoneID.equals(strings[0]))
{
j = count > 3 ? 2 : 1;
if (calendar.get(Calendar.DST_OFFSET) != 0)
j+=2;
zoneID = strings[j];
case WEEK_OF_YEAR_FIELD:
withLeadingZeros(theCalendar.get(Calendar.WEEK_OF_YEAR),p.size,buffer);
break;
}
}
buf.append(zoneID);
field = DateFormat.TIMEZONE_FIELD;
case WEEK_OF_MONTH_FIELD:
withLeadingZeros(theCalendar.get(Calendar.WEEK_OF_MONTH),p.size,buffer);
break;
case AM_PM_FIELD:
buffer.append(formatData.ampms[theCalendar.get(Calendar.AM_PM)]);
break;
case HOUR1_FIELD: // 1-24
withLeadingZeros(theCalendar.get(Calendar.HOUR_OF_DAY)+1,p.size,buffer);
break;
case HOUR0_FIELD: // 0-11
withLeadingZeros(theCalendar.get(Calendar.HOUR)-1,p.size,buffer);
break;
case TIMEZONE_FIELD:
// TODO
break;
default:
// Note that the JCL is actually somewhat
// contradictory here. It defines the pattern letters
// to be a particular list, but also says that a
// pattern containing an invalid pattern letter must
// throw an exception. It doesn't describe what an
// invalid pattern letter might be, so we just assume
// it is any letter in [a-zA-Z] not explicitly covered
// above.
throw new RuntimeException("bad format string");
}
if (pos != null && field == pos.getField())
throw new IllegalArgumentException("Illegal pattern character");
}
if (pos != null && p.field == pos.getField())
{
pos.setBeginIndex(beginIndex);
pos.setEndIndex(buf.length());
pos.setEndIndex(buffer.length());
}
} else {
buffer.append(o.toString());
}
}
return buffer;
}
return buf;
private void withLeadingZeros(int value, int length, StringBuffer buffer) {
String valStr = String.valueOf(value);
for (length -= valStr.length(); length > 0; length--)
buffer.append('0');
buffer.append(valStr);
}
private final boolean expect (String source, ParsePosition pos,
char ch)
private int indexInArray(String dateStr, int index, String[] values) {
int l1 = dateStr.length()-index;
int l2;
for (int i=0; i < values.length; i++) {
if (values[i] == null)
continue;
l2 = values[i].length();
//System.err.println(values[i] + " " + dateStr.substring(index,index+l2));
if ((l1 >= l2) && (dateStr.substring(index,index+l2).equals(values[i])))
return i;
}
return -1;
}
/*
* Get the actual year value, converting two digit years if necessary.
*/
private int processYear(int val)
{
int x = pos.getIndex();
boolean r = x < source.length() && source.charAt(x) == ch;
if (r)
pos.setIndex(x + 1);
else
pos.setErrorIndex(x);
return r;
if (val > 100)
return val;
Date d = get2DigitYearStart();
Calendar c = Calendar.getInstance();
c.setTime(d);
int y = c.get(YEAR_FIELD);
return ((y / 100) * 100) + val;
}
public Date parse (String source, ParsePosition pos)
/*
* Ok, we ignore the format string and just try to parse what we can
* out of the string. We need, month, day, year at a minimum. The real
* killer is stuff like XX/XX/XX. How do we interpret that? Is is the
* US style MM/DD/YY or the European style DD/MM/YY. Or is it YYYY/MM/DD?
* I'm an American, so I guess you know which one I'm choosing....
*/
private Date parseLenient(String dateStr, ParsePosition pos)
{
int fmt_index = 0;
int fmt_max = pattern.length();
int month = -1;
int day = -1;
int year = -1;
int era = -1;
int hour = -1;
int hour24 = -1;
int minute = -1;
int second = -1;
int millis = -1;
int ampm = -1;
int last = -1;
TimeZone tz = null;
char lastsep = ' ';
char nextchar = ' ';
Calendar cal = (Calendar)calendar.clone();
cal.clear();
cal.setTime(new Date(0));
int index = pos.getIndex();
String buf = dateStr.substring(index, dateStr.length());
calendar.clear();
int quote_start = -1;
for (; fmt_index < fmt_max; ++fmt_index)
top:
for(;;)
{
char ch = pattern.charAt(fmt_index);
if (ch == '\'')
// Are we at the end of the string? If so, make sure we have
// enough data and return. // FIXME: Also detect sufficient data
// and return by setting buf to "" on an unparsible string.
if (buf.equals(""))
{
int index = pos.getIndex();
if (fmt_index < fmt_max - 1
&& pattern.charAt(fmt_index + 1) == '\'')
pos.setIndex(index);
// This is the minimum we need
if ((month == -1) || (day == -1) || (year == -1))
{
if (! expect (source, pos, ch))
pos.setErrorIndex(index);
return null;
++fmt_index;
}
if (tz != null)
cal.setTimeZone(tz);
cal.set(Calendar.YEAR, year);
cal.set(Calendar.MONTH, month - 1);
cal.set(Calendar.DATE, day);
if (ampm == 0)
cal.set(Calendar.AM_PM, Calendar.AM);
else if (ampm == 1)
cal.set(Calendar.AM_PM, Calendar.PM);
// If am/pm not set, we assume 24 hour day
if (hour != -1)
{
if (ampm == -1)
cal.set(Calendar.HOUR_OF_DAY, hour);
else
quote_start = quote_start < 0 ? fmt_index : -1;
continue;
{
if (ampm == 0)
{
if (hour == 12)
hour = 0;
}
else
{
if (hour != 12)
hour += 12;
}
if (quote_start != -1
|| ((ch < 'a' || ch > 'z')
&& (ch < 'A' || ch > 'Z')))
cal.set(Calendar.HOUR_OF_DAY, hour);
}
}
if (minute != -1)
cal.set(Calendar.MINUTE, minute);
if (second != -1)
cal.set(Calendar.SECOND, second);
if (millis != -1)
cal.set(Calendar.MILLISECOND, millis);
if (era == 0)
cal.set(Calendar.ERA, GregorianCalendar.BC);
else if (era == 1)
cal.set(Calendar.ERA, GregorianCalendar.AD);
return cal.getTime();
}
// Skip over whitespace and expected punctuation
char c = buf.charAt(0);
boolean comma_found = false;
while(Character.isWhitespace(c) || (c == ':') ||
(c == ',') || (c == '.') || (c == '/'))
{
if (! expect (source, pos, ch))
return null;
lastsep = c;
if (c == ',') // This is a total and utter crock
comma_found = true;
buf = buf.substring(1);
if (buf.equals(""))
continue;
c = buf.charAt(0);
}
// We've arrived at a potential pattern character in the
// pattern.
int first = fmt_index;
while (++fmt_index < fmt_max && pattern.charAt(fmt_index) == ch)
;
int count = fmt_index - first;
--fmt_index;
// We can handle most fields automatically: most either are
// numeric or are looked up in a string vector. In some cases
// we need an offset. When numeric, `offset' is added to the
// resulting value. When doing a string lookup, offset is the
// initial index into the string array.
int calendar_field;
boolean is_numeric = true;
String[] match = null;
int offset = 0;
int zone_number = 0;
switch (ch)
{
case 'd':
calendar_field = Calendar.DATE;
break;
case 'D':
calendar_field = Calendar.DAY_OF_YEAR;
break;
case 'F':
calendar_field = Calendar.DAY_OF_WEEK_IN_MONTH;
break;
case 'E':
is_numeric = false;
offset = 1;
calendar_field = Calendar.DAY_OF_WEEK;
match = (count <= 3
? formatData.getShortWeekdays()
: formatData.getWeekdays());
break;
case 'w':
calendar_field = Calendar.WEEK_OF_YEAR;
break;
case 'W':
calendar_field = Calendar.WEEK_OF_MONTH;
break;
case 'M':
calendar_field = Calendar.MONTH;
if (count <= 2)
;
else
if (comma_found == true)
lastsep = ',';
// Is it a month name?
for (int i = 0; i < formatData.months.length; i++)
if ((formatData.months[i] != null)
&& buf.startsWith(formatData.months[i]))
{
is_numeric = false;
match = (count <= 3
? formatData.getShortMonths()
: formatData.getMonths());
month = i + 1;
buf = buf.substring(formatData.months[i].length());
index += formatData.months[i].length();
last = MONTH_FIELD;
continue top;
}
break;
case 'y':
calendar_field = Calendar.YEAR;
if (count <= 2)
offset = 1900;
break;
case 'K':
calendar_field = Calendar.HOUR;
break;
case 'h':
calendar_field = Calendar.HOUR;
offset = -1;
break;
case 'H':
calendar_field = Calendar.HOUR_OF_DAY;
break;
case 'k':
calendar_field = Calendar.HOUR_OF_DAY;
offset = -1;
break;
case 'm':
calendar_field = Calendar.MINUTE;
break;
case 's':
calendar_field = Calendar.SECOND;
break;
case 'S':
calendar_field = Calendar.MILLISECOND;
break;
case 'a':
is_numeric = false;
calendar_field = Calendar.AM_PM;
match = formatData.getAmPmStrings();
break;
case 'z':
// We need a special case for the timezone, because it
// uses a different data structure than the other cases.
is_numeric = false;
calendar_field = Calendar.DST_OFFSET;
String[][] zoneStrings = formatData.getZoneStrings();
int zoneCount = zoneStrings.length;
int index = pos.getIndex();
boolean found_zone = false;
for (int j = 0; j < zoneCount; j++)
// Is it a short month name?
for (int i = 0; i < formatData.shortMonths.length; i++)
if ((formatData.shortMonths[i] != null)
&& buf.startsWith(formatData.shortMonths[i]))
{
month = i + 1;
buf = buf.substring(formatData.shortMonths[i].length());
index += formatData.shortMonths[i].length();
last = MONTH_FIELD;
continue top;
}
// Is it a weekday name?
for (int i = 0; i < formatData.weekdays.length; i++)
if ((formatData.weekdays[i] != null)
&& buf.startsWith(formatData.weekdays[i]))
{
buf = buf.substring(formatData.weekdays[i].length());
index += formatData.weekdays[i].length();
last = DAY_OF_WEEK_FIELD;
continue top;
}
// Is it a short weekday name?
for (int i = 0; i < formatData.shortWeekdays.length; i++)
if ((formatData.shortWeekdays[i] != null)
&& buf.startsWith(formatData.shortWeekdays[i]))
{
buf = buf.substring(formatData.shortWeekdays[i].length());
index += formatData.shortWeekdays[i].length();
last = DAY_OF_WEEK_FIELD;
continue top;
}
// Is this an am/pm string?
for (int i = 0; i < formatData.ampms.length; i++) {
if ((formatData.ampms[i] != null)
&& buf.toLowerCase().startsWith(formatData.ampms[i].toLowerCase()))
{
String[] strings = zoneStrings[j];
int k;
for (k = 1; k < strings.length; ++k)
ampm = i;
buf = buf.substring(formatData.ampms[i].length());
index += formatData.ampms[i].length();
last = AM_PM_FIELD;
continue top;
}
}
// See if we have a number
c = buf.charAt(0);
String nbrstr = "";
while (Character.isDigit(c))
{
if (source.startsWith(strings[k], index))
nbrstr = nbrstr + c;
buf = buf.substring(1);
if (buf.equals(""))
break;
c = buf.charAt(0);
}
if (k != strings.length)
// If we didn't get a number, try for a timezone, otherwise set buf
// to "" and loop to see if we are done.
if (nbrstr.equals(""))
{
// Ok, try for a timezone name
while(!Character.isWhitespace(c) && (c != ',') && (c != '.') &&
(c != ':') && (c != '/'))
{
if (k > 2)
; // FIXME: dst.
zone_number = 0; // FIXME: dst.
// FIXME: raw offset to SimpleTimeZone const.
calendar.setTimeZone(new SimpleTimeZone (1, strings[0]));
pos.setIndex(index + strings[k].length());
nbrstr = nbrstr + c;
buf = buf.substring(1);
if (buf.equals(""))
break;
c = buf.charAt(0);
}
TimeZone tmptz = TimeZone.getTimeZone(nbrstr);
// We get GMT on failure, so be sure we asked for it.
if (tmptz.getID().equals("GMT"))
{
if (!nbrstr.equals("GMT"))
{
buf = "";
continue top;
}
}
if (! found_zone)
tz = tmptz;
last = TIMEZONE_FIELD;
index += nbrstr.length();
continue top;
}
// Convert to integer
int val = 0;
try
{
pos.setErrorIndex(pos.getIndex());
return null;
val = Integer.parseInt(nbrstr);
}
break;
default:
pos.setErrorIndex(pos.getIndex());
return null;
catch(Exception e)
{
return null; // Shouldn't happen
}
// Compute the value we should assign to the field.
int value;
if (is_numeric)
if (!buf.equals(""))
nextchar = buf.charAt(0);
else
nextchar = ' ';
// Figure out which value to assign to
// I make bad US assumptions about MM/DD/YYYY
if (last == DAY_OF_WEEK_FIELD)
{
numberFormat.setMinimumIntegerDigits(count);
Number n = numberFormat.parse(source, pos);
if (pos == null || ! (n instanceof Long))
return null;
value = n.intValue() + offset;
day = val;
last = DATE_FIELD;
}
else if ((last == MONTH_FIELD) && (day != -1))
{
year = processYear(val);
last = YEAR_FIELD;
}
else if (last == MONTH_FIELD)
{
day = val;
last = DATE_FIELD;
}
else if (last == -1)
{
// Assume month
if ((val < 13) && (val > 0))
{
month = val;
last = MONTH_FIELD;
}
// Assume year. This only works for two digit years that aren't
// between 01 and 12
else
{
year = processYear(val);
last = YEAR_FIELD;
}
}
else if ((last == YEAR_FIELD) && ((nextchar == '/') ||
(nextchar == '.')))
{
month = val;
last = MONTH_FIELD;
}
else if (last == YEAR_FIELD)
{
hour = val;
last = HOUR0_FIELD;
}
else if ((last == DATE_FIELD) && ((nextchar == '/') ||
(nextchar == '.') || buf.equals("")))
{
year = processYear(val);
last = YEAR_FIELD;
}
else if ((last == DATE_FIELD) && ((lastsep == '/') ||
(lastsep == '.') || (lastsep == ',')))
{
year = processYear(val);
last = YEAR_FIELD;
}
else if (last == DATE_FIELD)
{
hour = val;
last = HOUR0_FIELD;
}
else if (match != null)
else if (last == HOUR0_FIELD)
{
minute = val;
last = MINUTE_FIELD;
}
else if (last == MINUTE_FIELD)
{
second = val;
last = SECOND_FIELD;
}
else if (lastsep == '.')
{
; // This is milliseconds or something. Ignore it
last = WEEK_OF_YEAR_FIELD; // Just a random value
}
else // It is year. I have spoken!
{
year = processYear(val);
last = YEAR_FIELD;
}
}
}
private int parseLeadingZeros(String dateStr, ParsePosition pos,
FieldSizePair p)
{
int value;
int index = pos.getIndex();
int i;
for (i = offset; i < match.length; ++i)
String buf = null;
if (p.size == 1)
{
if (source.startsWith(match[i], index))
break;
char c = dateStr.charAt(index+1);
if ((dateStr.charAt(index) == '1') &&
Character.isDigit(dateStr.charAt(index+1)))
buf = dateStr.substring(index, index+2);
else
buf = dateStr.substring(index, index+1);
pos.setIndex(index + buf.length());
}
else if (p.size == 2)
{
buf = dateStr.substring(index, index+2);
pos.setIndex(index+2);
}
else if (p.size == 3)
{
buf = dateStr.substring(index, index+3);
pos.setIndex(index+3);
}
else
{
buf = dateStr.substring(index, index+4);
pos.setIndex(index+4);
}
if (i == match.length)
try
{
value = Integer.parseInt(buf);
}
catch(NumberFormatException nfe)
{
pos.setIndex(index);
pos.setErrorIndex(index);
return -1;
}
return value;
}
/*
* Note that this method doesn't properly protect against
* StringIndexOutOfBoundsException. FIXME
*/
private Date parseStrict(String dateStr, ParsePosition pos)
{
// start looking at position pos.index
Enumeration e = tokens.elements();
Calendar theCalendar = (Calendar) calendar.clone();
theCalendar.clear();
theCalendar.setTime(new Date(0));
int value, index, hour = -1;
String buf;
while (pos.getIndex() < dateStr.length()) {
Object o = e.nextElement();
if (o instanceof FieldSizePair) {
FieldSizePair p = (FieldSizePair) o;
switch (p.field) {
case ERA_FIELD:
value = indexInArray(dateStr,pos.getIndex(),formatData.eras);
if (value == -1) {
pos.setErrorIndex(pos.getIndex());
return null;
}
pos.setIndex(index + match[i].length());
value = i;
pos.setIndex(pos.getIndex() + formatData.eras[value].length());
theCalendar.set(Calendar.ERA,value);
break;
case YEAR_FIELD:
String y;
if (p.size < 4)
y = dateStr.substring(pos.getIndex(), pos.getIndex() + 2);
else
y = dateStr.substring(pos.getIndex(), pos.getIndex() + 4);
int year;
try
{
year = Integer.parseInt(y);
}
catch(NumberFormatException nfe)
{
pos.setErrorIndex(pos.getIndex());
return null;
}
if (p.size < 4)
year += get2DigitYearStart().getYear();
theCalendar.set(Calendar.YEAR, year);
if (p.size < 4)
pos.setIndex(pos.getIndex()+2);
else
pos.setIndex(pos.getIndex()+4);
break;
case MONTH_FIELD:
if (p.size > 2)
{
index = pos.getIndex();
value = indexInArray(dateStr,pos.getIndex(),
(p.size == 3) ? formatData.shortMonths : formatData.months);
if (value == -1)
{
pos.setErrorIndex(pos.getIndex());
return null;
}
if (p.size == 3)
pos.setIndex(index + formatData.shortMonths[value].length());
else
value = zone_number;
pos.setIndex(index + formatData.months[value].length());
theCalendar.set(Calendar.MONTH, value);
break;
}
value = parseLeadingZeros(dateStr, pos, p);
if (value == -1)
return null;
theCalendar.set(Calendar.MONTH, value);
break;
// Assign the value and move on.
case DATE_FIELD:
value = parseLeadingZeros(dateStr, pos, p);
if (value == -1)
return null;
theCalendar.set(Calendar.DATE, value);
break;
case HOUR_OF_DAY1_FIELD:
case HOUR_OF_DAY0_FIELD:
index = pos.getIndex();
buf = dateStr.substring(index, index+2);
try
{
calendar.set(calendar_field, value);
value = Integer.parseInt(buf);
}
// FIXME: what exception is thrown on an invalid
// non-lenient set?
catch (IllegalArgumentException x)
catch(NumberFormatException nfe)
{
return null;
}
if (p.field == HOUR_OF_DAY0_FIELD)
// theCalendar.set(Calendar.HOUR_OF_DAY, value);
hour = value + 1;
else
// theCalendar.set(Calendar.HOUR_OF_DAY, value-1);
hour = value;
pos.setIndex(index+2);
break;
case MINUTE_FIELD:
value = parseLeadingZeros(dateStr, pos, p);
if (value == -1)
return null;
theCalendar.set(Calendar.MINUTE, value);
break;
case SECOND_FIELD:
value = parseLeadingZeros(dateStr, pos, p);
if (value == -1)
return null;
theCalendar.set(Calendar.SECOND, value);
break;
case MILLISECOND_FIELD:
value = parseLeadingZeros(dateStr, pos, p);
if (value == -1)
return null;
theCalendar.set(Calendar.MILLISECOND, value);
break;
case DAY_OF_WEEK_FIELD:
value = indexInArray(dateStr,pos.getIndex(),(p.size < 4) ? formatData.shortWeekdays : formatData.weekdays);
if (value == -1) {
pos.setErrorIndex(pos.getIndex());
return null;
}
pos.setIndex(pos.getIndex() + ((p.size < 4) ? formatData.shortWeekdays[value].length()
: formatData.weekdays[value].length()));
// Note: Calendar.set(Calendar.DAY_OF_WEEK,value) does not work
// as implemented in jdk1.1.5 (possibly DAY_OF_WEEK is meant to
// be read-only). Instead, calculate number of days offset.
theCalendar.add(Calendar.DATE,value
- theCalendar.get(Calendar.DAY_OF_WEEK));
// in JDK, this seems to clear the hours, so we'll do the same.
theCalendar.set(Calendar.HOUR_OF_DAY,0);
break;
case DAY_OF_YEAR_FIELD:
value = parseLeadingZeros(dateStr, pos, p);
if (value == -1)
return null;
theCalendar.set(Calendar.DAY_OF_YEAR, value);
break;
// Just parse and ignore
case DAY_OF_WEEK_IN_MONTH_FIELD:
value = parseLeadingZeros(dateStr, pos, p);
if (value == -1)
return null;
break;
// Just parse and ignore
case WEEK_OF_YEAR_FIELD:
value = parseLeadingZeros(dateStr, pos, p);
if (value == -1)
return null;
break;
// Just parse and ignore
case WEEK_OF_MONTH_FIELD:
value = parseLeadingZeros(dateStr, pos, p);
if (value == -1)
return null;
break;
case AM_PM_FIELD:
value = indexInArray(dateStr,pos.getIndex(),formatData.ampms);
if (value == -1) {
pos.setErrorIndex(pos.getIndex());
return null;
}
pos.setIndex(pos.getIndex() + formatData.ampms[value].length());
theCalendar.set(Calendar.AM_PM,value);
break;
case HOUR1_FIELD:
case HOUR0_FIELD:
value = parseLeadingZeros(dateStr, pos, p);
if (value == -1)
return null;
if (p.field == HOUR1_FIELD)
theCalendar.set(Calendar.HOUR, value);
if (p.field == HOUR0_FIELD)
theCalendar.set(Calendar.HOUR, value+1);
break;
/*
case TIMEZONE_FIELD:
// TODO
break;
*/
return calendar.getTime();
default:
throw new IllegalArgumentException("Illegal pattern character: " +
p.field);
} // end switch
} else if (o instanceof String) {
String ostr = (String) o;
if (dateStr.substring(pos.getIndex(),pos.getIndex()+ostr.length()).equals(ostr)) {
pos.setIndex(pos.getIndex() + ostr.length());
} else {
pos.setErrorIndex(pos.getIndex());
return null;
}
} else if (o instanceof Character) {
Character ochar = (Character) o;
if (dateStr.charAt(pos.getIndex()) == ochar.charValue()) {
pos.setIndex(pos.getIndex() + 1);
} else {
pos.setErrorIndex(pos.getIndex());
return null;
}
}
}
public boolean equals (Object obj)
if (hour != -1)
{
if (! (obj instanceof SimpleDateFormat) || ! super.equals(obj) )
return false;
SimpleDateFormat other = (SimpleDateFormat) obj;
return (DateFormatSymbols.equals(pattern, other.pattern)
&& DateFormatSymbols.equals(formatData, other.formatData)
&& DateFormatSymbols.equals(defaultCenturyStart,
other.defaultCenturyStart));
if (theCalendar.get(Calendar.AM_PM) == Calendar.PM)
{
if (hour == 12)
theCalendar.set(Calendar.HOUR_OF_DAY, 12);
else
theCalendar.set(Calendar.HOUR_OF_DAY, hour + 12);
}
public Object clone ()
else
{
// We know the superclass just call's Object's generic cloner.
return super.clone ();
if (hour == 12)
theCalendar.set(Calendar.HOUR_OF_DAY, 0);
else
theCalendar.set(Calendar.HOUR_OF_DAY, hour);
}
}
public int hashCode ()
{
int hash = super.hashCode();
if (pattern != null)
hash ^= pattern.hashCode();
return hash;
return theCalendar.getTime();
}
/**
* This method parses the specified string into a date.
*
* @param dateStr The date string to parse.
* @param pos The input and output parse position
*
* @return The parsed date, or <code>null</code> if the string cannot be
* parsed.
*/
public Date parse(String dateStr, ParsePosition pos) {
if (isLenient())
return parseLenient(dateStr, pos);
else
return parseStrict(dateStr, pos);
}
}
/* Copyright (C) 1998, 1999, 2000 Free Software Foundation
/* java.util.TimeZone
Copyright (C) 1998, 1999, 2000 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;
import java.text.DateFormatSymbols;
/**
* @author Per Bothner <bothner@cygnus.com>
* @date October 24, 1998.
* This class represents a time zone offset and handles daylight savings.
*
* You can get the default time zone with <code>getDefault</code>.
* This represents the time zone where program is running.
*
* Another way to create a time zone is <code>getTimeZone</code>, where
* you can give an identifier as parameter. For instance, the identifier
* of the Central European Time zone is "CET".
*
* With the <code>getAvailableIDs</code> method, you can get all the
* supported time zone identifiers.
*
* @see Calendar
* @see SimpleTimeZone
* @author Jochen Hoenicke
*/
/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3.
* Status: getAvailableIDs, getDefault, getTimeZone only know about GMT.
*/
public abstract class TimeZone implements java.io.Serializable, Cloneable
{
/**
* Constant used to indicate that a short timezone abbreviation should
* be returned, such as "EST"
*/
public static final int SHORT = 0;
public static final int LONG = 1;
// The fields are as specified in Sun's "Serialized Form"
// in the JDK 1.2 beta 4 API specification.
String ID;
/**
* Constant used to indicate that a long timezone name should be
* returned, such as "Eastern Standard Time".
*/
public static final int LONG = 1;
static final TimeZone zoneGMT = new SimpleTimeZone(0, "GMT");
/**
* The time zone identifier, e.g. PST.
*/
private String ID;
private static TimeZone zoneDefault;
/**
* The default time zone, as returned by getDefault.
*/
private static TimeZone defaultZone;
private static final long serialVersionUID = 3581463369166924961L;
public TimeZone ()
/**
* Hashtable for timezones by ID.
*/
private static final Hashtable timezones = new Hashtable();
static
{
TimeZone tz;
// Automatically generated by scripts/timezones.pl
// XXX - Should we read this data from a file?
tz = new SimpleTimeZone(-11000 * 3600, "Pacific/Niue");
timezones.put("Pacific/Niue", tz);
timezones.put("Pacific/Apia", tz);
timezones.put("Pacific/Midway", tz);
timezones.put("Pacific/Pago_Pago", tz);
tz = new SimpleTimeZone
(-10000 * 3600, "America/Adak",
Calendar.APRIL, 1, Calendar.SUNDAY, 2000 * 3600,
Calendar.OCTOBER, -1, Calendar.SUNDAY, 2000 * 3600);
timezones.put("America/Adak", tz);
tz = new SimpleTimeZone(-10000 * 3600, "HST");
timezones.put("HST", tz);
timezones.put("Pacific/Fakaofo", tz);
timezones.put("Pacific/Honolulu", tz);
timezones.put("Pacific/Johnston", tz);
timezones.put("Pacific/Rarotonga", tz);
timezones.put("Pacific/Tahiti", tz);
tz = new SimpleTimeZone
(-9000 * 3600, "America/Juneau",
Calendar.APRIL, 1, Calendar.SUNDAY, 2000 * 3600,
Calendar.OCTOBER, -1, Calendar.SUNDAY, 2000 * 3600);
timezones.put("America/Juneau", tz);
timezones.put("America/Anchorage", tz);
timezones.put("America/Nome", tz);
timezones.put("America/Yakutat", tz);
tz = new SimpleTimeZone(-9000 * 3600, "Pacific/Gambier");
timezones.put("Pacific/Gambier", tz);
tz = new SimpleTimeZone(-8500 * 3600, "Pacific/Marquesas");
timezones.put("Pacific/Marquesas", tz);
tz = new SimpleTimeZone
(-8000 * 3600, "PST8PDT",
Calendar.APRIL, 1, Calendar.SUNDAY, 2000 * 3600,
Calendar.OCTOBER, -1, Calendar.SUNDAY, 2000 * 3600);
timezones.put("PST8PDT", tz);
timezones.put("America/Dawson", tz);
timezones.put("America/Los_Angeles", tz);
timezones.put("America/Tijuana", tz);
timezones.put("America/Vancouver", tz);
timezones.put("America/Whitehorse", tz);
timezones.put("US/Pacific-New", tz);
tz = new SimpleTimeZone(-8000 * 3600, "Pacific/Pitcairn");
timezones.put("Pacific/Pitcairn", tz);
tz = new SimpleTimeZone(-7000 * 3600, "MST");
timezones.put("MST", tz);
timezones.put("America/Dawson_Creek", tz);
timezones.put("America/Phoenix", tz);
tz = new SimpleTimeZone
(-7000 * 3600, "MST7MDT",
Calendar.APRIL, 1, Calendar.SUNDAY, 2000 * 3600,
Calendar.OCTOBER, -1, Calendar.SUNDAY, 2000 * 3600);
timezones.put("MST7MDT", tz);
timezones.put("America/Boise", tz);
timezones.put("America/Chihuahua", tz);
timezones.put("America/Denver", tz);
timezones.put("America/Edmonton", tz);
timezones.put("America/Inuvik", tz);
timezones.put("America/Mazatlan", tz);
timezones.put("America/Shiprock", tz);
timezones.put("America/Yellowknife", tz);
tz = new SimpleTimeZone(-6000 * 3600, "America/Regina");
timezones.put("America/Regina", tz);
timezones.put("America/Belize", tz);
timezones.put("America/Costa_Rica", tz);
timezones.put("America/El_Salvador", tz);
timezones.put("America/Guatemala", tz);
timezones.put("America/Managua", tz);
timezones.put("America/Swift_Current", tz);
timezones.put("America/Tegucigalpa", tz);
timezones.put("Pacific/Galapagos", tz);
tz = new SimpleTimeZone
(-6000 * 3600, "CST6CDT",
Calendar.APRIL, 1, Calendar.SUNDAY, 2000 * 3600,
Calendar.OCTOBER, -1, Calendar.SUNDAY, 2000 * 3600);
timezones.put("CST6CDT", tz);
timezones.put("America/Cambridge_Bay", tz);
timezones.put("America/Cancun", tz);
timezones.put("America/Chicago", tz);
timezones.put("America/Iqaluit", tz);
timezones.put("America/Menominee", tz);
timezones.put("America/Mexico_City", tz);
timezones.put("America/Pangnirtung", tz);
timezones.put("America/Rainy_River", tz);
timezones.put("America/Rankin_Inlet", tz);
timezones.put("America/Winnipeg", tz);
tz = new SimpleTimeZone
(-6000 * 3600, "Pacific/Easter",
Calendar.OCTOBER, 9, -Calendar.SUNDAY, 0 * 3600,
Calendar.MARCH, 9, -Calendar.SUNDAY, 0 * 3600);
timezones.put("Pacific/Easter", tz);
tz = new SimpleTimeZone
(-5000 * 3600, "America/Grand_Turk",
Calendar.APRIL, 1, Calendar.SUNDAY, 0 * 3600,
Calendar.OCTOBER, -1, Calendar.SUNDAY, 0 * 3600);
timezones.put("America/Grand_Turk", tz);
tz = new SimpleTimeZone
(-5000 * 3600, "America/Havana",
Calendar.APRIL, 1, 0, 0 * 3600,
Calendar.OCTOBER, -1, Calendar.SUNDAY, 0 * 3600);
timezones.put("America/Havana", tz);
tz = new SimpleTimeZone(-5000 * 3600, "EST");
timezones.put("EST", tz);
timezones.put("America/Bogota", tz);
timezones.put("America/Cayman", tz);
timezones.put("America/Guayaquil", tz);
timezones.put("America/Indiana/Indianapolis", tz);
timezones.put("America/Indiana/Knox", tz);
timezones.put("America/Indiana/Marengo", tz);
timezones.put("America/Indiana/Vevay", tz);
timezones.put("America/Indianapolis", tz);
timezones.put("America/Jamaica", tz);
timezones.put("America/Lima", tz);
timezones.put("America/Panama", tz);
timezones.put("America/Port-au-Prince", tz);
timezones.put("America/Porto_Acre", tz);
tz = new SimpleTimeZone
(-5000 * 3600, "EST5EDT",
Calendar.APRIL, 1, Calendar.SUNDAY, 2000 * 3600,
Calendar.OCTOBER, -1, Calendar.SUNDAY, 2000 * 3600);
timezones.put("EST5EDT", tz);
timezones.put("America/Detroit", tz);
timezones.put("America/Louisville", tz);
timezones.put("America/Montreal", tz);
timezones.put("America/Nassau", tz);
timezones.put("America/New_York", tz);
timezones.put("America/Nipigon", tz);
timezones.put("America/Thunder_Bay", tz);
tz = new SimpleTimeZone(-4000 * 3600, "America/Anguilla");
timezones.put("America/Anguilla", tz);
timezones.put("America/Antigua", tz);
timezones.put("America/Aruba", tz);
timezones.put("America/Barbados", tz);
timezones.put("America/Caracas", tz);
timezones.put("America/Curacao", tz);
timezones.put("America/Dominica", tz);
timezones.put("America/Grenada", tz);
timezones.put("America/Guadeloupe", tz);
timezones.put("America/Guyana", tz);
timezones.put("America/La_Paz", tz);
timezones.put("America/Manaus", tz);
timezones.put("America/Martinique", tz);
timezones.put("America/Montserrat", tz);
timezones.put("America/Port_of_Spain", tz);
timezones.put("America/Porto_Velho", tz);
timezones.put("America/Puerto_Rico", tz);
timezones.put("America/Santo_Domingo", tz);
timezones.put("America/St_Kitts", tz);
timezones.put("America/St_Lucia", tz);
timezones.put("America/St_Thomas", tz);
timezones.put("America/St_Vincent", tz);
timezones.put("America/Tortola", tz);
tz = new SimpleTimeZone
(-4000 * 3600, "America/Cuiaba",
Calendar.OCTOBER, 1, Calendar.SUNDAY, 0 * 3600,
Calendar.FEBRUARY, -1, Calendar.SUNDAY, 0 * 3600);
timezones.put("America/Cuiaba", tz);
timezones.put("America/Asuncion", tz);
timezones.put("America/Boa_Vista", tz);
tz = new SimpleTimeZone
(-4000 * 3600, "America/Thule",
Calendar.APRIL, 1, Calendar.SUNDAY, 2000 * 3600,
Calendar.OCTOBER, -1, Calendar.SUNDAY, 2000 * 3600);
timezones.put("America/Thule", tz);
timezones.put("America/Glace_Bay", tz);
timezones.put("America/Goose_Bay", tz);
timezones.put("America/Halifax", tz);
timezones.put("Atlantic/Bermuda", tz);
tz = new SimpleTimeZone
(-4000 * 3600, "Antarctica/Palmer",
Calendar.OCTOBER, 9, -Calendar.SUNDAY, 0 * 3600,
Calendar.MARCH, 9, -Calendar.SUNDAY, 0 * 3600);
timezones.put("Antarctica/Palmer", tz);
timezones.put("America/Santiago", tz);
tz = new SimpleTimeZone
(-4000 * 3600, "Atlantic/Stanley",
Calendar.SEPTEMBER, 2, Calendar.SUNDAY, 0 * 3600,
Calendar.APRIL, 16, -Calendar.SUNDAY, 0 * 3600);
timezones.put("Atlantic/Stanley", tz);
tz = new SimpleTimeZone(-3000 * 3600, "America/Buenos_Aires");
timezones.put("America/Buenos_Aires", tz);
timezones.put("America/Belem", tz);
timezones.put("America/Catamarca", tz);
timezones.put("America/Cayenne", tz);
timezones.put("America/Cordoba", tz);
timezones.put("America/Jujuy", tz);
timezones.put("America/Mendoza", tz);
timezones.put("America/Montevideo", tz);
timezones.put("America/Paramaribo", tz);
timezones.put("America/Rosario", tz);
tz = new SimpleTimeZone
(-3000 * 3600, "America/Fortaleza",
Calendar.OCTOBER, 1, Calendar.SUNDAY, 0 * 3600,
Calendar.FEBRUARY, -1, Calendar.SUNDAY, 0 * 3600);
timezones.put("America/Fortaleza", tz);
timezones.put("America/Araguaina", tz);
timezones.put("America/Maceio", tz);
timezones.put("America/Sao_Paulo", tz);
tz = new SimpleTimeZone
(-3000 * 3600, "America/Godthab",
Calendar.MARCH, 30, -Calendar.SATURDAY, 22000 * 3600,
Calendar.OCTOBER, 30, -Calendar.SATURDAY, 22000 * 3600);
timezones.put("America/Godthab", tz);
tz = new SimpleTimeZone
(-3000 * 3600, "America/Miquelon",
Calendar.APRIL, 1, Calendar.SUNDAY, 2000 * 3600,
Calendar.OCTOBER, -1, Calendar.SUNDAY, 2000 * 3600);
timezones.put("America/Miquelon", tz);
tz = new SimpleTimeZone
(-2500 * 3600, "America/St_Johns",
Calendar.APRIL, 1, Calendar.SUNDAY, 2000 * 3600,
Calendar.OCTOBER, -1, Calendar.SUNDAY, 2000 * 3600);
timezones.put("America/St_Johns", tz);
tz = new SimpleTimeZone(-2000 * 3600, "America/Noronha");
timezones.put("America/Noronha", tz);
timezones.put("Atlantic/South_Georgia", tz);
tz = new SimpleTimeZone
(-1000 * 3600, "America/Scoresbysund",
Calendar.MARCH, -1, Calendar.SUNDAY, 0 * 3600,
Calendar.OCTOBER, -1, Calendar.SUNDAY, 0 * 3600);
timezones.put("America/Scoresbysund", tz);
timezones.put("Atlantic/Azores", tz);
tz = new SimpleTimeZone(-1000 * 3600, "Atlantic/Cape_Verde");
timezones.put("Atlantic/Cape_Verde", tz);
timezones.put("Atlantic/Jan_Mayen", tz);
tz = new SimpleTimeZone(0 * 3600, "GMT");
timezones.put("GMT", tz);
timezones.put("Africa/Abidjan", tz);
timezones.put("Africa/Accra", tz);
timezones.put("Africa/Bamako", tz);
timezones.put("Africa/Banjul", tz);
timezones.put("Africa/Bissau", tz);
timezones.put("Africa/Casablanca", tz);
timezones.put("Africa/Conakry", tz);
timezones.put("Africa/Dakar", tz);
timezones.put("Africa/El_Aaiun", tz);
timezones.put("Africa/Freetown", tz);
timezones.put("Africa/Lome", tz);
timezones.put("Africa/Monrovia", tz);
timezones.put("Africa/Nouakchott", tz);
timezones.put("Africa/Ouagadougou", tz);
timezones.put("Africa/Sao_Tome", tz);
timezones.put("Africa/Timbuktu", tz);
timezones.put("Atlantic/Reykjavik", tz);
timezones.put("Atlantic/St_Helena", tz);
timezones.put("Europe/Belfast", tz);
timezones.put("Europe/Dublin", tz);
timezones.put("Europe/London", tz);
timezones.put("UTC", tz);
tz = new SimpleTimeZone
(0 * 3600, "WET",
Calendar.MARCH, -1, Calendar.SUNDAY, 1000 * 3600,
Calendar.OCTOBER, -1, Calendar.SUNDAY, 1000 * 3600);
timezones.put("WET", tz);
timezones.put("Atlantic/Canary", tz);
timezones.put("Atlantic/Faeroe", tz);
timezones.put("Atlantic/Madeira", tz);
timezones.put("Europe/Lisbon", tz);
tz = new SimpleTimeZone(1000 * 3600, "Africa/Algiers");
timezones.put("Africa/Algiers", tz);
timezones.put("Africa/Bangui", tz);
timezones.put("Africa/Brazzaville", tz);
timezones.put("Africa/Douala", tz);
timezones.put("Africa/Kinshasa", tz);
timezones.put("Africa/Lagos", tz);
timezones.put("Africa/Libreville", tz);
timezones.put("Africa/Luanda", tz);
timezones.put("Africa/Malabo", tz);
timezones.put("Africa/Ndjamena", tz);
timezones.put("Africa/Niamey", tz);
timezones.put("Africa/Porto-Novo", tz);
timezones.put("Africa/Tunis", tz);
tz = new SimpleTimeZone
(1000 * 3600, "Africa/Windhoek",
Calendar.SEPTEMBER, 1, Calendar.SUNDAY, 2000 * 3600,
Calendar.APRIL, 1, Calendar.SUNDAY, 2000 * 3600);
timezones.put("Africa/Windhoek", tz);
tz = new SimpleTimeZone
(1000 * 3600, "CET",
Calendar.MARCH, -1, Calendar.SUNDAY, 2000 * 3600,
Calendar.OCTOBER, -1, Calendar.SUNDAY, 2000 * 3600);
timezones.put("CET", tz);
timezones.put("Africa/Ceuta", tz);
timezones.put("Arctic/Longyearbyen", tz);
timezones.put("Europe/Amsterdam", tz);
timezones.put("Europe/Andorra", tz);
timezones.put("Europe/Belgrade", tz);
timezones.put("Europe/Berlin", tz);
timezones.put("Europe/Bratislava", tz);
timezones.put("Europe/Brussels", tz);
timezones.put("Europe/Budapest", tz);
timezones.put("Europe/Copenhagen", tz);
timezones.put("Europe/Gibraltar", tz);
timezones.put("Europe/Ljubljana", tz);
timezones.put("Europe/Luxembourg", tz);
timezones.put("Europe/Madrid", tz);
timezones.put("Europe/Malta", tz);
timezones.put("Europe/Monaco", tz);
timezones.put("Europe/Oslo", tz);
timezones.put("Europe/Paris", tz);
timezones.put("Europe/Prague", tz);
timezones.put("Europe/Rome", tz);
timezones.put("Europe/San_Marino", tz);
timezones.put("Europe/Sarajevo", tz);
timezones.put("Europe/Skopje", tz);
timezones.put("Europe/Stockholm", tz);
timezones.put("Europe/Tirane", tz);
timezones.put("Europe/Vaduz", tz);
timezones.put("Europe/Vatican", tz);
timezones.put("Europe/Vienna", tz);
timezones.put("Europe/Warsaw", tz);
timezones.put("Europe/Zagreb", tz);
timezones.put("Europe/Zurich", tz);
timezones.put("MET", tz);
tz = new SimpleTimeZone
(2000 * 3600, "Africa/Cairo",
Calendar.APRIL, -1, Calendar.FRIDAY, 0 * 3600,
Calendar.SEPTEMBER, -1, Calendar.THURSDAY, 23000 * 3600);
timezones.put("Africa/Cairo", tz);
tz = new SimpleTimeZone(2000 * 3600, "Africa/Gaborone");
timezones.put("Africa/Gaborone", tz);
timezones.put("Africa/Blantyre", tz);
timezones.put("Africa/Bujumbura", tz);
timezones.put("Africa/Harare", tz);
timezones.put("Africa/Johannesburg", tz);
timezones.put("Africa/Khartoum", tz);
timezones.put("Africa/Kigali", tz);
timezones.put("Africa/Lubumbashi", tz);
timezones.put("Africa/Lusaka", tz);
timezones.put("Africa/Maputo", tz);
timezones.put("Africa/Maseru", tz);
timezones.put("Africa/Mbabane", tz);
timezones.put("Africa/Tripoli", tz);
timezones.put("Europe/Tallinn", tz);
tz = new SimpleTimeZone
(2000 * 3600, "Asia/Amman",
Calendar.APRIL, 1, 0, 0 * 3600, Calendar.OCTOBER, 1, 0, 0 * 3600);
timezones.put("Asia/Amman", tz);
timezones.put("Asia/Damascus", tz);
tz = new SimpleTimeZone
(2000 * 3600, "Asia/Beirut",
Calendar.MARCH, -1, Calendar.SUNDAY, 0 * 3600,
Calendar.OCTOBER, -1, Calendar.SUNDAY, 0 * 3600);
timezones.put("Asia/Beirut", tz);
tz = new SimpleTimeZone
(2000 * 3600, "Asia/Gaza",
Calendar.APRIL, 3, Calendar.FRIDAY, 0 * 3600,
Calendar.OCTOBER, 3, Calendar.FRIDAY, 0 * 3600);
timezones.put("Asia/Gaza", tz);
tz = new SimpleTimeZone
(2000 * 3600, "Asia/Jerusalem",
Calendar.APRIL, 1, Calendar.FRIDAY, 2000 * 3600,
Calendar.SEPTEMBER, 1, Calendar.FRIDAY, 2000 * 3600);
timezones.put("Asia/Jerusalem", tz);
tz = new SimpleTimeZone
(2000 * 3600, "EET",
Calendar.MARCH, -1, Calendar.SUNDAY, 3000 * 3600,
Calendar.OCTOBER, -1, Calendar.SUNDAY, 3000 * 3600);
timezones.put("EET", tz);
timezones.put("Asia/Istanbul", tz);
timezones.put("Asia/Nicosia", tz);
timezones.put("Europe/Athens", tz);
timezones.put("Europe/Bucharest", tz);
timezones.put("Europe/Chisinau", tz);
timezones.put("Europe/Helsinki", tz);
timezones.put("Europe/Istanbul", tz);
timezones.put("Europe/Kiev", tz);
timezones.put("Europe/Riga", tz);
timezones.put("Europe/Simferopol", tz);
timezones.put("Europe/Sofia", tz);
timezones.put("Europe/Uzhgorod", tz);
timezones.put("Europe/Vilnius", tz);
timezones.put("Europe/Zaporozhye", tz);
tz = new SimpleTimeZone
(2000 * 3600, "Europe/Minsk",
Calendar.MARCH, -1, Calendar.SUNDAY, 2000 * 3600,
Calendar.OCTOBER, -1, Calendar.SUNDAY, 2000 * 3600);
timezones.put("Europe/Minsk", tz);
timezones.put("Europe/Kaliningrad", tz);
tz = new SimpleTimeZone
(3000 * 3600, "Asia/Baghdad",
Calendar.APRIL, 1, 0, 3000 * 3600,
Calendar.OCTOBER, 1, 0, 3000 * 3600);
timezones.put("Asia/Baghdad", tz);
tz = new SimpleTimeZone
(3000 * 3600, "Europe/Tiraspol",
Calendar.MARCH, -1, Calendar.SUNDAY, 2000 * 3600,
Calendar.OCTOBER, -1, Calendar.SUNDAY, 2000 * 3600);
timezones.put("Europe/Tiraspol", tz);
timezones.put("Europe/Moscow", tz);
tz = new SimpleTimeZone(3000 * 3600, "Indian/Comoro");
timezones.put("Indian/Comoro", tz);
timezones.put("Africa/Addis_Ababa", tz);
timezones.put("Africa/Asmera", tz);
timezones.put("Africa/Dar_es_Salaam", tz);
timezones.put("Africa/Djibouti", tz);
timezones.put("Africa/Kampala", tz);
timezones.put("Africa/Mogadishu", tz);
timezones.put("Africa/Nairobi", tz);
timezones.put("Antarctica/Syowa", tz);
timezones.put("Asia/Aden", tz);
timezones.put("Asia/Bahrain", tz);
timezones.put("Asia/Kuwait", tz);
timezones.put("Asia/Qatar", tz);
timezones.put("Asia/Riyadh", tz);
timezones.put("Indian/Antananarivo", tz);
timezones.put("Indian/Mayotte", tz);
tz = new SimpleTimeZone(3500 * 3600, "Asia/Tehran");
timezones.put("Asia/Tehran", tz);
tz = new SimpleTimeZone
(4000 * 3600, "Asia/Baku",
Calendar.MARCH, -1, Calendar.SUNDAY, 1000 * 3600,
Calendar.OCTOBER, -1, Calendar.SUNDAY, 1000 * 3600);
timezones.put("Asia/Baku", tz);
tz = new SimpleTimeZone
(4000 * 3600, "Asia/Tbilisi",
Calendar.MARCH, -1, Calendar.SUNDAY, 0 * 3600,
Calendar.OCTOBER, -1, Calendar.SUNDAY, 0 * 3600);
timezones.put("Asia/Tbilisi", tz);
timezones.put("Asia/Aqtau", tz);
tz = new SimpleTimeZone
(4000 * 3600, "Asia/Yerevan",
Calendar.MARCH, -1, Calendar.SUNDAY, 2000 * 3600,
Calendar.OCTOBER, -1, Calendar.SUNDAY, 2000 * 3600);
timezones.put("Asia/Yerevan", tz);
timezones.put("Europe/Samara", tz);
tz = new SimpleTimeZone(4000 * 3600, "Indian/Mauritius");
timezones.put("Indian/Mauritius", tz);
timezones.put("Asia/Dubai", tz);
timezones.put("Asia/Muscat", tz);
timezones.put("Indian/Mahe", tz);
timezones.put("Indian/Reunion", tz);
tz = new SimpleTimeZone(4500 * 3600, "Asia/Kabul");
timezones.put("Asia/Kabul", tz);
tz = new SimpleTimeZone
(5000 * 3600, "Asia/Aqtobe",
Calendar.MARCH, -1, Calendar.SUNDAY, 0 * 3600,
Calendar.OCTOBER, -1, Calendar.SUNDAY, 0 * 3600);
timezones.put("Asia/Aqtobe", tz);
tz = new SimpleTimeZone
(5000 * 3600, "Asia/Bishkek",
Calendar.MARCH, -1, Calendar.SUNDAY, 2500 * 3600,
Calendar.OCTOBER, -1, Calendar.SUNDAY, 2500 * 3600);
timezones.put("Asia/Bishkek", tz);
tz = new SimpleTimeZone
(5000 * 3600, "Asia/Yekaterinburg",
Calendar.MARCH, -1, Calendar.SUNDAY, 2000 * 3600,
Calendar.OCTOBER, -1, Calendar.SUNDAY, 2000 * 3600);
timezones.put("Asia/Yekaterinburg", tz);
tz = new SimpleTimeZone(5000 * 3600, "Indian/Kerguelen");
timezones.put("Indian/Kerguelen", tz);
timezones.put("Asia/Ashkhabad", tz);
timezones.put("Asia/Dushanbe", tz);
timezones.put("Asia/Karachi", tz);
timezones.put("Asia/Samarkand", tz);
timezones.put("Asia/Tashkent", tz);
timezones.put("Indian/Chagos", tz);
timezones.put("Indian/Maldives", tz);
tz = new SimpleTimeZone(5500 * 3600, "Asia/Calcutta");
timezones.put("Asia/Calcutta", tz);
tz = new SimpleTimeZone(5750 * 3600, "Asia/Katmandu");
timezones.put("Asia/Katmandu", tz);
tz = new SimpleTimeZone(6000 * 3600, "Antarctica/Mawson");
timezones.put("Antarctica/Mawson", tz);
timezones.put("Asia/Colombo", tz);
timezones.put("Asia/Dacca", tz);
timezones.put("Asia/Thimbu", tz);
tz = new SimpleTimeZone
(6000 * 3600, "Asia/Almaty",
Calendar.MARCH, -1, Calendar.SUNDAY, 0 * 3600,
Calendar.OCTOBER, -1, Calendar.SUNDAY, 0 * 3600);
timezones.put("Asia/Almaty", tz);
tz = new SimpleTimeZone
(6000 * 3600, "Asia/Omsk",
Calendar.MARCH, -1, Calendar.SUNDAY, 2000 * 3600,
Calendar.OCTOBER, -1, Calendar.SUNDAY, 2000 * 3600);
timezones.put("Asia/Omsk", tz);
timezones.put("Asia/Novosibirsk", tz);
tz = new SimpleTimeZone(6500 * 3600, "Asia/Rangoon");
timezones.put("Asia/Rangoon", tz);
timezones.put("Indian/Cocos", tz);
tz = new SimpleTimeZone(7000 * 3600, "Antarctica/Davis");
timezones.put("Antarctica/Davis", tz);
timezones.put("Asia/Bangkok", tz);
timezones.put("Asia/Jakarta", tz);
timezones.put("Asia/Phnom_Penh", tz);
timezones.put("Asia/Saigon", tz);
timezones.put("Asia/Vientiane", tz);
timezones.put("Indian/Christmas", tz);
tz = new SimpleTimeZone
(7000 * 3600, "Asia/Krasnoyarsk",
Calendar.MARCH, -1, Calendar.SUNDAY, 2000 * 3600,
Calendar.OCTOBER, -1, Calendar.SUNDAY, 2000 * 3600);
timezones.put("Asia/Krasnoyarsk", tz);
tz = new SimpleTimeZone(8000 * 3600, "Antarctica/Casey");
timezones.put("Antarctica/Casey", tz);
timezones.put("Asia/Brunei", tz);
timezones.put("Asia/Chungking", tz);
timezones.put("Asia/Dili", tz);
timezones.put("Asia/Harbin", tz);
timezones.put("Asia/Hong_Kong", tz);
timezones.put("Asia/Kashgar", tz);
timezones.put("Asia/Kuala_Lumpur", tz);
timezones.put("Asia/Kuching", tz);
timezones.put("Asia/Macao", tz);
timezones.put("Asia/Manila", tz);
timezones.put("Asia/Shanghai", tz);
timezones.put("Asia/Singapore", tz);
timezones.put("Asia/Taipei", tz);
timezones.put("Asia/Ujung_Pandang", tz);
timezones.put("Asia/Urumqi", tz);
timezones.put("Australia/Perth", tz);
tz = new SimpleTimeZone
(8000 * 3600, "Asia/Irkutsk",
Calendar.MARCH, -1, Calendar.SUNDAY, 2000 * 3600,
Calendar.OCTOBER, -1, Calendar.SUNDAY, 2000 * 3600);
timezones.put("Asia/Irkutsk", tz);
tz = new SimpleTimeZone
(8000 * 3600, "Asia/Ulan_Bator",
Calendar.MARCH, -1, Calendar.SUNDAY, 0 * 3600,
Calendar.SEPTEMBER, -1, Calendar.SUNDAY, 0 * 3600);
timezones.put("Asia/Ulan_Bator", tz);
tz = new SimpleTimeZone(9000 * 3600, "Asia/Jayapura");
timezones.put("Asia/Jayapura", tz);
timezones.put("Asia/Pyongyang", tz);
timezones.put("Asia/Seoul", tz);
timezones.put("Asia/Tokyo", tz);
timezones.put("Pacific/Palau", tz);
tz = new SimpleTimeZone
(9000 * 3600, "Asia/Yakutsk",
Calendar.MARCH, -1, Calendar.SUNDAY, 2000 * 3600,
Calendar.OCTOBER, -1, Calendar.SUNDAY, 2000 * 3600);
timezones.put("Asia/Yakutsk", tz);
tz = new SimpleTimeZone
(9500 * 3600, "Australia/Adelaide",
Calendar.OCTOBER, -1, Calendar.SUNDAY, 2000 * 3600,
Calendar.MARCH, -1, Calendar.SUNDAY, 2000 * 3600);
timezones.put("Australia/Adelaide", tz);
timezones.put("Australia/Broken_Hill", tz);
tz = new SimpleTimeZone(9500 * 3600, "Australia/Darwin");
timezones.put("Australia/Darwin", tz);
tz = new SimpleTimeZone(10000 * 3600, "Antarctica/DumontDUrville");
timezones.put("Antarctica/DumontDUrville", tz);
timezones.put("Australia/Brisbane", tz);
timezones.put("Australia/Lindeman", tz);
timezones.put("Pacific/Guam", tz);
timezones.put("Pacific/Port_Moresby", tz);
timezones.put("Pacific/Saipan", tz);
timezones.put("Pacific/Truk", tz);
timezones.put("Pacific/Yap", tz);
tz = new SimpleTimeZone
(10000 * 3600, "Asia/Vladivostok",
Calendar.MARCH, -1, Calendar.SUNDAY, 2000 * 3600,
Calendar.OCTOBER, -1, Calendar.SUNDAY, 2000 * 3600);
timezones.put("Asia/Vladivostok", tz);
tz = new SimpleTimeZone
(10000 * 3600, "Australia/Hobart",
Calendar.OCTOBER, 1, Calendar.SUNDAY, 2000 * 3600,
Calendar.MARCH, -1, Calendar.SUNDAY, 2000 * 3600);
timezones.put("Australia/Hobart", tz);
tz = new SimpleTimeZone
(10000 * 3600, "Australia/Melbourne",
Calendar.OCTOBER, -1, Calendar.SUNDAY, 2000 * 3600,
Calendar.MARCH, -1, Calendar.SUNDAY, 2000 * 3600);
timezones.put("Australia/Melbourne", tz);
timezones.put("Australia/Sydney", tz);
/******************************************************************
* FIXME: XXX: Not yet available in libgcj. Need new jdk 1.2
* SimpleTimeZone constructor.
tz = new SimpleTimeZone
(10500 * 3600, "Australia/Lord_Howe",
Calendar.OCTOBER, -1, Calendar.SUNDAY, 2000 * 3600,
Calendar.MARCH, -1, Calendar.SUNDAY, 2000 * 3600, 500 * 3600);
timezones.put("Australia/Lord_Howe", tz);
******************************************************************/
tz = new SimpleTimeZone
(11000 * 3600, "Asia/Magadan",
Calendar.MARCH, -1, Calendar.SUNDAY, 2000 * 3600,
Calendar.OCTOBER, -1, Calendar.SUNDAY, 2000 * 3600);
timezones.put("Asia/Magadan", tz);
tz = new SimpleTimeZone(11000 * 3600, "Pacific/Ponape");
timezones.put("Pacific/Ponape", tz);
timezones.put("Pacific/Efate", tz);
timezones.put("Pacific/Guadalcanal", tz);
timezones.put("Pacific/Kosrae", tz);
timezones.put("Pacific/Noumea", tz);
tz = new SimpleTimeZone(11500 * 3600, "Pacific/Norfolk");
timezones.put("Pacific/Norfolk", tz);
tz = new SimpleTimeZone
(12000 * 3600, "Antarctica/McMurdo",
Calendar.OCTOBER, 1, Calendar.SUNDAY, 2000 * 3600,
Calendar.MARCH, 3, Calendar.SUNDAY, 2000 * 3600);
timezones.put("Antarctica/McMurdo", tz);
timezones.put("Antarctica/South_Pole", tz);
timezones.put("Pacific/Auckland", tz);
tz = new SimpleTimeZone
(12000 * 3600, "Asia/Kamchatka",
Calendar.MARCH, -1, Calendar.SUNDAY, 2000 * 3600,
Calendar.OCTOBER, -1, Calendar.SUNDAY, 2000 * 3600);
timezones.put("Asia/Kamchatka", tz);
timezones.put("Asia/Anadyr", tz);
tz = new SimpleTimeZone
(12000 * 3600, "Pacific/Fiji",
Calendar.NOVEMBER, 1, Calendar.SUNDAY, 2000 * 3600,
Calendar.FEBRUARY, -1, Calendar.SUNDAY, 3000 * 3600);
timezones.put("Pacific/Fiji", tz);
tz = new SimpleTimeZone(12000 * 3600, "Pacific/Tarawa");
timezones.put("Pacific/Tarawa", tz);
timezones.put("Pacific/Funafuti", tz);
timezones.put("Pacific/Kwajalein", tz);
timezones.put("Pacific/Majuro", tz);
timezones.put("Pacific/Nauru", tz);
timezones.put("Pacific/Wake", tz);
timezones.put("Pacific/Wallis", tz);
tz = new SimpleTimeZone
(12750 * 3600, "Pacific/Chatham",
Calendar.OCTOBER, 1, Calendar.SUNDAY, 2750 * 3600,
Calendar.MARCH, 3, Calendar.SUNDAY, 2750 * 3600);
timezones.put("Pacific/Chatham", tz);
tz = new SimpleTimeZone(13000 * 3600, "Pacific/Enderbury");
timezones.put("Pacific/Enderbury", tz);
tz = new SimpleTimeZone
(13000 * 3600, "Pacific/Tongatapu",
Calendar.OCTOBER, 1, Calendar.SATURDAY, 2000 * 3600,
Calendar.APRIL, 16, -Calendar.SUNDAY, 2000 * 3600);
timezones.put("Pacific/Tongatapu", tz);
tz = new SimpleTimeZone(14000 * 3600, "Pacific/Kiritimati");
timezones.put("Pacific/Kiritimati", tz);
}
public abstract int getOffset (int era, int year, int month,
int day, int dayOfWeek, int milliseconds);
public abstract void setRawOffset (int offsetMillis);
/* Look up default timezone */
static
{
// System.loadLibrary("javautil");
public abstract int getRawOffset ();
String tzid = System.getProperty("user.timezone");
public String getID () { return ID; }
if (tzid == null)
tzid = getDefaultTimeZoneId();
public void setID (String ID) { this.ID = ID; }
if (tzid == null)
tzid = "GMT";
public final String getDisplayName()
defaultZone = getTimeZone(tzid);
}
/* This method returns us a time zone id string which is in the
form <standard zone name><GMT offset><daylight time zone name>.
The GMT offset is in seconds, except where it is evenly divisible
by 3600, then it is in hours. If the zone does not observe
daylight time, then the daylight zone name is omitted. Examples:
in Chicago, the timezone would be CST6CDT. In Indianapolis
(which does not have Daylight Savings Time) the string would
be EST5
*/
private static native String getDefaultTimeZoneId();
/**
* Gets the time zone offset, for current date, modified in case of
* daylight savings. This is the offset to add to UTC to get the local
* time.
* @param era the era of the given date
* @param year the year of the given date
* @param month the month of the given date, 0 for January.
* @param day the day of month
* @param dayOfWeek the day of week
* @param milliseconds the millis in the day (in local standard time)
* @return the time zone offset in milliseconds.
*/
public abstract int getOffset(int era, int year, int month,
int day, int dayOfWeek, int milliseconds);
/**
* Gets the time zone offset, ignoring daylight savings. This is
* the offset to add to UTC to get the local time.
* @return the time zone offset in milliseconds.
*/
public abstract int getRawOffset();
/**
* Sets the time zone offset, ignoring daylight savings. This is
* the offset to add to UTC to get the local time.
* @param offsetMillis the time zone offset to GMT.
*/
public abstract void setRawOffset(int offsetMillis);
/**
* Gets the identifier of this time zone. For instance, PST for
* Pacific Standard Time.
* @returns the ID of this time zone.
*/
public String getID()
{
return ID; // FIXME
return ID;
}
// public final String getDisplayName (Local locale) { ... } FIXME
/**
* Sets the identifier of this time zone. For instance, PST for
* Pacific Standard Time.
* @param id the new time zone ID.
*/
public void setID(String id)
{
this.ID = id;
}
public final String getDisplayName (boolean daylight, int style)
/**
* This method returns a string name of the time zone suitable
* for displaying to the user. The string returned will be the long
* description of the timezone in the current locale. The name
* displayed will assume daylight savings time is not in effect.
*
* @return The name of the time zone.
*/
public final String getDisplayName()
{
return ID; // FIXME
return (getDisplayName(false, LONG, Locale.getDefault()));
}
/*
public final String getDisplayName (boolean daylight, int style, Locale locale)
/**
* This method returns a string name of the time zone suitable
* for displaying to the user. The string returned will be the long
* description of the timezone in the specified locale. The name
* displayed will assume daylight savings time is not in effect.
*
* @param locale The locale for this timezone name.
*
* @return The name of the time zone.
*/
public final String getDisplayName(Locale locale)
{
return ID; // FIXME
return (getDisplayName(false, LONG, locale));
}
/**
* This method returns a string name of the time zone suitable
* for displaying to the user. The string returned will be of the
* specified type in the current locale.
*
* @param dst Whether or not daylight savings time is in effect.
* @param style <code>LONG</code> for a long name, <code>SHORT</code> for
* a short abbreviation.
*
* @return The name of the time zone.
*/
public final String getDisplayName(boolean dst, int style)
{
return (getDisplayName(dst, style, Locale.getDefault()));
}
public abstract boolean useDaylightTime();
public abstract boolean inDaylightTime (Date date);
/**
* This method returns a string name of the time zone suitable
* for displaying to the user. The string returned will be of the
* specified type in the specified locale.
*
* @param dst Whether or not daylight savings time is in effect.
* @param style <code>LONG</code> for a long name, <code>SHORT</code> for
* a short abbreviation.
* @param locale The locale for this timezone name.
*
* @return The name of the time zone.
*/
public String getDisplayName(boolean dst, int style, Locale locale)
{
DateFormatSymbols dfs;
try
{
dfs = new DateFormatSymbols(locale);
public static synchronized TimeZone getTimeZone (String ID)
// The format of the value returned is defined by us.
String[][]zoneinfo = dfs.getZoneStrings();
for (int i = 0; i < zoneinfo.length; i++)
{
int i;
for (i = 0; i < tzIDs.length; ++i)
if (zoneinfo[i][0].equals(getID()))
{
if (ID.equals(tzIDs[i]))
break;
if (!dst)
{
if (style == SHORT)
return (zoneinfo[i][2]);
else
return (zoneinfo[i][1]);
}
if (i == tzIDs.length)
return null;
if (timeZones[i] == null)
else
{
if (ID.equals("GMT"))
timeZones[i] = zoneGMT;
if (style == SHORT)
return (zoneinfo[i][4]);
else
timeZones[i] = new SimpleTimeZone (rawOffsets[i], tzIDs[i]);
return (zoneinfo[i][3]);
}
}
}
}
catch (MissingResourceException e)
{
}
return timeZones[i];
return getDefaultDisplayName(dst);
}
public static String[] getAvailableIDs()
private String getDefaultDisplayName(boolean dst)
{
int offset = getRawOffset();
if (dst && this instanceof SimpleTimeZone)
{
return (String[]) tzIDs.clone();
// ugly, but this is a design failure of the API:
// getDisplayName takes a dst parameter even though
// TimeZone knows nothing about daylight saving offsets.
offset += ((SimpleTimeZone) this).getDSTSavings();
}
public static String[] getAvailableIDs(int rawOffset)
StringBuffer sb = new StringBuffer(9);
sb.append("GMT");
sb.append(offset >= 0 ? '+' : '-');
offset = Math.abs(offset) / (1000 * 60);
int hours = offset / 60;
int minutes = offset % 60;
sb.append('0' + hours / 10).append('0' + hours % 10).append(':');
sb.append('0' + minutes / 10).append('0' + minutes % 10);
return sb.toString();
}
/**
* Returns true, if this time zone uses Daylight Savings Time.
*/
public abstract boolean useDaylightTime();
/**
* Returns true, if the given date is in Daylight Savings Time in this
* time zone.
* @param date the given Date.
*/
public abstract boolean inDaylightTime(Date date);
/**
* Gets the TimeZone for the given ID.
* @param ID the time zone identifier.
* @return The time zone for the identifier or GMT, if no such time
* zone exists.
*/
// FIXME: XXX: JCL indicates this and other methods are synchronized.
public static TimeZone getTimeZone(String ID)
{
// First check timezones hash
TimeZone tz = (TimeZone) timezones.get(ID);
if (tz != null)
{
int first, last;
if (tz.getID().equals(ID))
return tz;
for (first = 0; first < rawOffsets.length; ++first)
// We always return a timezone with the requested ID.
// This is the same behaviour as with JDK1.2.
tz = (TimeZone) tz.clone();
tz.setID(ID);
// We also save the alias, so that we return the same
// object again if getTimeZone is called with the same
// alias.
timezones.put(ID, tz);
return tz;
}
// See if the ID is really a GMT offset form.
// Note that GMT is in the table so we know it is different.
if (ID.startsWith("GMT"))
{
int pos = 3;
int offset_direction = 1;
if (ID.charAt(pos) == '-')
{
if (rawOffset == rawOffsets[first])
break;
offset_direction = -1;
pos++;
}
if (first == rawOffsets.length)
return new String[0];
for (last = first + 1; last < rawOffsets.length; ++last)
else if (ID.charAt(pos) == '+')
{
if (rawOffset != rawOffsets[last])
break;
pos++;
}
String[] r = new String[last - first];
for (int i = first; i < last; ++i)
try
{
r[i - first] = tzIDs[i];
}
int hour, minute;
return r;
String offset_str = ID.substring(pos);
int idx = offset_str.indexOf(":");
if (idx != -1)
{
hour = Integer.parseInt(offset_str.substring(0, idx));
minute = Integer.parseInt(offset_str.substring(idx + 1));
}
else
{
int offset_length = offset_str.length();
if (offset_length <= 2)
{
// Only hour
hour = Integer.parseInt(offset_str);
minute = 0;
}
else
{
// hour and minute, not separated by colon
hour = Integer.parseInt
(offset_str.substring(0, offset_length - 2));
minute = Integer.parseInt
(offset_str.substring(offset_length - 2));
}
}
private static synchronized TimeZone setDefault()
return new SimpleTimeZone((hour * (60 * 60 * 1000) +
minute * (60 * 1000))
* offset_direction, ID);
}
catch (NumberFormatException e)
{
if (zoneDefault == null)
}
}
// Finally, return GMT per spec
return getTimeZone("GMT");
}
/**
* Gets the available IDs according to the given time zone
* offset.
* @param rawOffset the given time zone GMT offset.
* @return An array of IDs, where the time zone has the specified GMT
* offset. For example <code>{"Phoenix", "Denver"}</code>, since both have
* GMT-07:00, but differ in daylight savings behaviour.
*/
/******************************************************************
* FIXME: XXX: Not yet available in libgcj. Need jdk 1.2 Iterator and Map.
public static String[] getAvailableIDs(int rawOffset)
{
try
int count = 0;
Iterator iter = timezones.entrySet().iterator();
while (iter.hasNext())
{
String id = System.getProperty("user.timezone");
if (id != null && ! id.equals("GMT"))
zoneDefault = getTimeZone(id);
// Don't iterate the values, since we want to count
// doubled values (aliases)
Map.Entry entry = (Map.Entry) iter.next();
if (((TimeZone) entry.getValue()).getRawOffset() == rawOffset)
count++;
}
catch (Exception ex)
String[] ids = new String[count];
count = 0;
iter = timezones.entrySet().iterator();
while (iter.hasNext())
{
Map.Entry entry = (Map.Entry) iter.next();
if (((TimeZone) entry.getValue()).getRawOffset() == rawOffset)
ids[count++] = (String) entry.getKey();
}
if (zoneDefault == null)
zoneDefault = zoneGMT;
return ids;
}
return zoneDefault;
******************************************************************/
/**
* Gets all available IDs.
* @return An array of all supported IDs.
*/
/******************************************************************
* FIXME: XXX: Not yet available in libgcj. Need jdk 1.2 java.util.Map.
public static String[] getAvailableIDs()
{
return (String[])
timezones.keySet().toArray(new String[timezones.size()]);
}
******************************************************************/
/**
* Returns the time zone under which the host is running. This
* can be changed with setDefault.
* @return the time zone for this host.
* @see #setDefault
*/
public static TimeZone getDefault()
{
return zoneDefault == null ? setDefault() : zoneDefault;
return defaultZone;
}
public static void setDefault (TimeZone zone) { zoneDefault = zone; }
public boolean hasSameRules (TimeZone other)
public static void setDefault(TimeZone zone)
{
return this == other;
defaultZone = zone;
}
public Object clone ()
/**
* Test if the other time zone uses the same rule and only
* possibly differs in ID. This implementation for this particular
* class will return true if the raw offsets are identical. Subclasses
* should override this method if they use daylight savings.
* @return true if this zone has the same raw offset
*/
public boolean hasSameRules(TimeZone other)
{
// Just use Object's generic cloner.
return super.clone ();
return other.getRawOffset() == getRawOffset();
}
// Names of timezones. This array is kept in parallel with
// rawOffsets. This list comes from the JCL 1.1 book.
private static final String[] tzIDs =
/**
* Returns a clone of this object. I can't imagine, why this is
* useful for a time zone.
*/
public Object clone()
{
"MIT", "HST", "AST", "PST", "PNT",
"MST", "CST", "EST", "IET", "PRT",
"CNT", "AGT", "BET", "CAT", "GMT",
"ECT", "EET", "ART", "EAT", "MET",
"NET", "PLT", "IST", "BST", "VST",
"CTT", "JST", "ACT", "AET", "SST",
"NST"
};
// This holds raw offsets in milliseconds.
// 3600000 == 60 * 60 * 1000
private static final int[] rawOffsets =
try
{
-11 * 3600000, -10 * 3600000, -9 * 3600000, -8 * 3600000, -7 * 3600000,
-7 * 3600000, -6 * 3600000, -5 * 3600000, -5 * 3600000, -4 * 3600000,
-35 * 360000, -3 * 3600000, -3 * 3600000, -1 * 3600000, 0,
1 * 3600000, 1 * 3600000, 2 * 3600000, 3 * 3600000, 35 * 360000,
4 * 3600000, 5 * 3600000, 55 * 360000, 6 * 3600000, 7 * 3600000,
8 * 3600000, 9 * 3600000, 95 * 360000, 10 * 3600000, 11 * 3600000,
12 * 3600000
};
// This caches all the corresponding zone objects.
private static TimeZone[] timeZones = new TimeZone[tzIDs.length];
return super.clone();
}
catch (CloneNotSupportedException ex)
{
return null;
}
}
static final TimeZone zoneGMT = new SimpleTimeZone(0, "GMT");
}
/* Copyright (C) 2000 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>
#include <gcj/cni.h>
#include <java/util/TimeZone.h>
#include <stdio.h>
#include <string.h>
#if TIME_WITH_SYS_TIME
# include <sys/time.h>
# include <time.h>
#else
# if HAVE_SYS_TIME_H
# include <sys/time.h>
# else
# include <time.h>
# endif
#endif
/*
* This method returns a time zone string that is used by the static
* initializer in java.util.TimeZone to create the default timezone
* instance. This is a key into the timezone table used by
* that class.
*/
jstring
java::util::TimeZone::getDefaultTimeZoneId (void)
{
time_t current_time;
char **tzinfo, *tzid;
long tzoffset;
jstring retval;
current_time = time(0);
mktime(localtime(&current_time));
tzinfo = tzname;
tzoffset = timezone;
if ((tzoffset % 3600) == 0)
tzoffset = tzoffset / 3600;
if (!strcmp(tzinfo[0], tzinfo[1]))
{
tzid = (char*) _Jv_Malloc (strlen(tzinfo[0]) + 6);
if (!tzid)
return NULL;
sprintf(tzid, "%s%ld", tzinfo[0], tzoffset);
}
else
{
tzid = (char*) _Jv_Malloc (strlen(tzinfo[0]) + strlen(tzinfo[1]) + 6);
if (!tzid)
return NULL;
sprintf(tzid, "%s%ld%s", tzinfo[0], tzoffset, tzinfo[1]);
}
retval = JvNewStringUTF (tzid);
_Jv_Free (tzid);
return retval;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment