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> 2000-11-27 Bryce McKinlay <bryce@albatross.co.nz>
* java/util/Vector.java (ensureCapacity): Don't increment modCount. * java/util/Vector.java (ensureCapacity): Don't increment modCount.
......
...@@ -1229,6 +1229,7 @@ java/net/natPlainDatagramSocketImpl.cc \ ...@@ -1229,6 +1229,7 @@ java/net/natPlainDatagramSocketImpl.cc \
java/net/natPlainSocketImpl.cc \ java/net/natPlainSocketImpl.cc \
java/text/natCollator.cc \ java/text/natCollator.cc \
java/util/natGregorianCalendar.cc \ java/util/natGregorianCalendar.cc \
java/util/natTimeZone.cc \
java/util/zip/natDeflater.cc \ java/util/zip/natDeflater.cc \
java/util/zip/natInflater.cc java/util/zip/natInflater.cc
......
...@@ -991,6 +991,7 @@ java/net/natPlainDatagramSocketImpl.cc \ ...@@ -991,6 +991,7 @@ java/net/natPlainDatagramSocketImpl.cc \
java/net/natPlainSocketImpl.cc \ java/net/natPlainSocketImpl.cc \
java/text/natCollator.cc \ java/text/natCollator.cc \
java/util/natGregorianCalendar.cc \ java/util/natGregorianCalendar.cc \
java/util/natTimeZone.cc \
java/util/zip/natDeflater.cc \ java/util/zip/natDeflater.cc \
java/util/zip/natInflater.cc java/util/zip/natInflater.cc
...@@ -1142,8 +1143,8 @@ java/lang/reflect/natArray.lo java/lang/reflect/natConstructor.lo \ ...@@ -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/lang/reflect/natField.lo java/lang/reflect/natMethod.lo \
java/net/natInetAddress.lo java/net/natPlainDatagramSocketImpl.lo \ java/net/natInetAddress.lo java/net/natPlainDatagramSocketImpl.lo \
java/net/natPlainSocketImpl.lo java/text/natCollator.lo \ java/net/natPlainSocketImpl.lo java/text/natCollator.lo \
java/util/natGregorianCalendar.lo java/util/zip/natDeflater.lo \ java/util/natGregorianCalendar.lo java/util/natTimeZone.lo \
java/util/zip/natInflater.lo java/util/zip/natDeflater.lo java/util/zip/natInflater.lo
libgcjx_la_OBJECTS = gnu/gcj/xlib/natClip.lo \ libgcjx_la_OBJECTS = gnu/gcj/xlib/natClip.lo \
gnu/gcj/xlib/natColormap.lo gnu/gcj/xlib/natDisplay.lo \ gnu/gcj/xlib/natColormap.lo gnu/gcj/xlib/natDisplay.lo \
gnu/gcj/xlib/natDrawable.lo gnu/gcj/xlib/natFont.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 \ ...@@ -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/JarException.P .deps/java/util/jar/JarFile.P \
.deps/java/util/jar/JarInputStream.P \ .deps/java/util/jar/JarInputStream.P \
.deps/java/util/jar/JarOutputStream.P .deps/java/util/jar/Manifest.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/natGregorianCalendar.P .deps/java/util/natTimeZone.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/CheckedOutputStream.P \
.deps/java/util/zip/Checksum.P \ .deps/java/util/zip/Checksum.P \
.deps/java/util/zip/DataFormatException.P \ .deps/java/util/zip/DataFormatException.P \
......
...@@ -68,6 +68,16 @@ public final class LocaleData_en extends ListResourceBundle ...@@ -68,6 +68,16 @@ public final class LocaleData_en extends ListResourceBundle
{ "shortWeekdays", shortWeekdaysDefault }, { "shortWeekdays", shortWeekdaysDefault },
{ "weekdays", weekdaysDefault }, { "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. // For RuleBasedCollator.
// FIXME: this is nowhere near complete. // FIXME: this is nowhere near complete.
// In particular we must mark accents as ignorable, // In particular we must mark accents as ignorable,
......
...@@ -24,21 +24,29 @@ import java.util.ResourceBundle; ...@@ -24,21 +24,29 @@ import java.util.ResourceBundle;
public class DateFormatSymbols extends Object public class DateFormatSymbols extends Object
implements java.io.Serializable, Cloneable implements java.io.Serializable, Cloneable
{ {
private String[] ampms; String[] ampms;
private String[] eras; String[] eras;
private String localPatternChars; private String localPatternChars;
private String[] months; String[] months;
private String[] shortMonths; String[] shortMonths;
private String[] shortWeekdays; String[] shortWeekdays;
private String[] weekdays; String[] weekdays;
private String[][] zoneStrings; private String[][] zoneStrings;
private static final long serialVersionUID = -5987973545549424702L; 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[] ampmsDefault = {"AM", "PM" };
private static final String[] erasDefault = {"BC", "AD" }; private static final String[] erasDefault = {"BC", "AD" };
// localPatternCharsDefault is used by SimpleDateFormat. // localPatternCharsDefault is used by SimpleDateFormat.
protected static final String localPatternCharsDefault private static final String localPatternCharsDefault
= "GyMdkHmsSEDFwWahKz"; = "GyMdkHmsSEDFwWahKz";
private static final String[] monthsDefault = { private static final String[] monthsDefault = {
"January", "February", "March", "April", "May", "June", "January", "February", "March", "April", "May", "June",
...@@ -77,6 +85,24 @@ public class DateFormatSymbols extends Object ...@@ -77,6 +85,24 @@ public class DateFormatSymbols extends Object
/**/ "Alaska Daylight Time", "ADT", "Anchorage" } /**/ "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, private final Object safeGetResource (ResourceBundle res,
String key, Object def) String key, Object def)
{ {
...@@ -116,6 +142,9 @@ public class DateFormatSymbols extends Object ...@@ -116,6 +142,9 @@ public class DateFormatSymbols extends Object
weekdays = (String[]) safeGetResource (res, "weekdays", weekdaysDefault); weekdays = (String[]) safeGetResource (res, "weekdays", weekdaysDefault);
zoneStrings = (String[][]) safeGetResource (res, "zoneStrings", zoneStrings = (String[][]) safeGetResource (res, "zoneStrings",
zoneStringsDefault); zoneStringsDefault);
dateFormats = formatsForKey(res, "DateFormat");
timeFormats = formatsForKey(res, "TimeFormat");
} }
public DateFormatSymbols () public DateFormatSymbols ()
...@@ -134,6 +163,8 @@ public class DateFormatSymbols extends Object ...@@ -134,6 +163,8 @@ public class DateFormatSymbols extends Object
shortWeekdays = old.shortWeekdays; shortWeekdays = old.shortWeekdays;
weekdays = old.weekdays; weekdays = old.weekdays;
zoneStrings = old.zoneStrings; zoneStrings = old.zoneStrings;
dateFormats = old.dateFormats;
timeFormats = old.timeFormats;
} }
public String[] getAmPmStrings() 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; 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.ObjectInputStream;
import java.io.IOException; import java.io.IOException;
/** /**
* @author Per Bothner <bothner@cygnus.com> * SimpleDateFormat provides convenient methods for parsing and formatting
* @date October 25, 1998. * dates using Gregorian calendars (see java.util.GregorianCalendar).
*/ */
/* Written using "Java Class Libraries", 2nd edition, plus online public class SimpleDateFormat extends DateFormat
* API docs for JDK 1.2 beta from http://www.javasoft.com.
* Status: Believed complete and correct to 1.2.
*/
public class SimpleDateFormat extends DateFormat
{ {
// Serialization fields. /** A pair class used by SimpleDateFormat as a compiled representation
private Date defaultCenturyStart = new Date(); * of a format string.
private DateFormatSymbols formatData; */
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 String pattern;
private int serialVersionOnStream = 1; private int serialVersionOnStream = 1; // 0 indicates JDK1.1.3 or earlier
private static final long serialVersionUID = 4774881970558875024L; 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) private void readObject(ObjectInputStream stream)
throws IOException, ClassNotFoundException throws IOException, ClassNotFoundException
{ {
stream.defaultReadObject(); stream.defaultReadObject();
if (serialVersionOnStream < 1) if (serialVersionOnStream < 1)
{ {
defaultCenturyStart = new Date(); defaultCenturyStart =
new Date(System.currentTimeMillis() - (80*365*24*60*60*1000));
serialVersionOnStream = 1; 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.
public SimpleDateFormat (String pattern) 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 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); * There does not appear to be a standard API for determining
this.numberFormat = NumberFormat.getInstance(locale); * what the default pattern for a locale is, so use package-scope
numberFormat.setGroupingUsed(false); * variables in DateFormatSymbols to encapsulate this.
this.formatData = new DateFormatSymbols (locale); */
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(pattern, Locale.getDefault());
this.formatData = formatData;
this.calendar = Calendar.getInstance();
this.numberFormat = NumberFormat.getInstance();
numberFormat.setGroupingUsed(false);
} }
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) /**
{ * Creates a date formatter using the specified pattern. The
defaultCenturyStart = startDate; * 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) String oldChars, String newChars)
{ {
int len = pattern.length(); int len = pattern.length();
StringBuffer buf = new StringBuffer(len); StringBuffer buf = new StringBuffer(len);
...@@ -122,424 +283,874 @@ public class SimpleDateFormat extends DateFormat ...@@ -122,424 +283,874 @@ public class SimpleDateFormat extends DateFormat
return buf.toString(); 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(); return defaultCenturyStart;
String standardChars = DateFormatSymbols.localPatternCharsDefault;
pattern = applyLocalizedPattern (pattern, localChars, standardChars);
applyPattern(pattern);
} }
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(); defaultCenturyStart = date;
String standardChars = DateFormatSymbols.localPatternCharsDefault;
return applyLocalizedPattern (pattern, standardChars, localChars);
} }
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); return formatData;
numberFormat.format(value, buf, null);
} }
public StringBuffer format (Date date, StringBuffer buf, FieldPosition pos) /**
* This method sets the format symbols information used for parsing
* and formatting dates.
*
* @param formatData The date format symbols.
*/
public void setDateFormatSymbols(DateFormatSymbols formatData)
{
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)
{ {
Calendar calendar = (Calendar) this.calendar.clone(); if (o == null)
calendar.setTime(date); return false;
int len = pattern.length();
int quoteStart = -1; if (!super.equals(o))
for (int i = 0; i < len; i++) return false;
{
char ch = pattern.charAt(i); if (!(o instanceof SimpleDateFormat))
if (ch == '\'') return false;
{
// We must do a little lookahead to see if we have two SimpleDateFormat sdf = (SimpleDateFormat)o;
// single quotes embedded in quoted text.
if (i < len - 1 && pattern.charAt(i + 1) == '\'') if (!toPattern().equals(sdf.toPattern()))
{ return false;
++i;
buf.append(ch); if (!get2DigitYearStart().equals(sdf.get2DigitYearStart()))
} return false;
else
quoteStart = quoteStart < 0 ? i : -1; if (!getDateFormatSymbols().equals(sdf.getDateFormatSymbols()))
} return false;
// From JCL: any characters in the pattern that are not in
// the ranges of [a..z] and [A..Z] are treated as quoted return true;
// text. }
else if (quoteStart != -1
|| ((ch < 'a' || ch > 'z')
&& (ch < 'A' || ch > 'Z'))) /**
buf.append(ch); * Formats the date input according to the format string in use,
else * 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
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
buffer.append(formatData.months[theCalendar.get(Calendar.MONTH)]);
break;
case DATE_FIELD:
withLeadingZeros(theCalendar.get(Calendar.DATE),p.size,buffer);
break;
case HOUR_OF_DAY1_FIELD: // 1-12
withLeadingZeros(theCalendar.get(Calendar.HOUR),p.size,buffer);
break;
case HOUR_OF_DAY0_FIELD: // 0-23
withLeadingZeros(theCalendar.get(Calendar.HOUR_OF_DAY),p.size,buffer);
break;
case MINUTE_FIELD:
withLeadingZeros(theCalendar.get(Calendar.MINUTE),p.size,buffer);
break;
case SECOND_FIELD:
withLeadingZeros(theCalendar.get(Calendar.SECOND),p.size,buffer);
break;
case MILLISECOND_FIELD:
withLeadingZeros(theCalendar.get(Calendar.MILLISECOND),p.size,buffer);
break;
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 DAY_OF_YEAR_FIELD:
withLeadingZeros(theCalendar.get(Calendar.DAY_OF_YEAR),p.size,buffer);
break;
case DAY_OF_WEEK_IN_MONTH_FIELD:
withLeadingZeros(theCalendar.get(Calendar.DAY_OF_WEEK_IN_MONTH),p.size,buffer);
break;
case WEEK_OF_YEAR_FIELD:
withLeadingZeros(theCalendar.get(Calendar.WEEK_OF_YEAR),p.size,buffer);
break;
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:
throw new IllegalArgumentException("Illegal pattern character");
}
if (pos != null && p.field == pos.getField())
{ {
int first = i; pos.setBeginIndex(beginIndex);
int value; pos.setEndIndex(buffer.length());
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);
else
buf.append(count <= 3 ? formatData.getShortMonths()[value]
: formatData.getMonths()[value]);
field = DateFormat.MONTH_FIELD;
break;
case 'y':
value = calendar.get(Calendar.YEAR);
append(buf, count <= 2 ? value % 100 : value, count);
field = DateFormat.YEAR_FIELD;
break;
case 'K':
append(buf, calendar.get(Calendar.HOUR), count);
field = DateFormat.HOUR0_FIELD;
break;
case 'h':
value = ((calendar.get(Calendar.HOUR) + 11) % 12) + 1;
append(buf, value, count);
field = DateFormat.HOUR1_FIELD;
break;
case 'H':
append(buf, calendar.get(Calendar.HOUR_OF_DAY), count);
field = DateFormat.HOUR_OF_DAY0_FIELD;
break;
case 'k':
value = ((calendar.get(Calendar.HOUR_OF_DAY) + 23) % 24) + 1;
append(buf, value, count);
field = DateFormat.HOUR_OF_DAY1_FIELD;
break;
case 'm':
append(buf, calendar.get(Calendar.MINUTE), count);
field = DateFormat.MINUTE_FIELD;
break;
case 's':
append(buf, calendar.get(Calendar.SECOND), count);
field = DateFormat.SECOND_FIELD;
break;
case 'S':
append(buf, calendar.get(Calendar.MILLISECOND), count);
field = DateFormat.MILLISECOND_FIELD;
break;
case 'a':
value = calendar.get(calendar.AM_PM);
buf.append(formatData.getAmPmStrings()[value]);
field = DateFormat.AM_PM_FIELD;
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];
break;
}
}
buf.append(zoneID);
field = DateFormat.TIMEZONE_FIELD;
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())
{
pos.setBeginIndex(beginIndex);
pos.setEndIndex(buf.length());
}
} }
} else {
buffer.append(o.toString());
} }
return buf; }
return buffer;
}
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 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;
} }
private final boolean expect (String source, ParsePosition pos, /*
char ch) * Get the actual year value, converting two digit years if necessary.
*/
private int processYear(int val)
{ {
int x = pos.getIndex(); if (val > 100)
boolean r = x < source.length() && source.charAt(x) == ch; return val;
if (r)
pos.setIndex(x + 1); Date d = get2DigitYearStart();
else Calendar c = Calendar.getInstance();
pos.setErrorIndex(x); c.setTime(d);
return r; 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 month = -1;
int fmt_max = pattern.length(); 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(); top:
int quote_start = -1; for(;;)
for (; fmt_index < fmt_max; ++fmt_index)
{ {
char ch = pattern.charAt(fmt_index);
if (ch == '\'')
{
int index = pos.getIndex();
if (fmt_index < fmt_max - 1
&& pattern.charAt(fmt_index + 1) == '\'')
{
if (! expect (source, pos, ch))
return null;
++fmt_index;
}
else
quote_start = quote_start < 0 ? fmt_index : -1;
continue;
}
if (quote_start != -1 // Are we at the end of the string? If so, make sure we have
|| ((ch < 'a' || ch > 'z') // enough data and return. // FIXME: Also detect sufficient data
&& (ch < 'A' || ch > 'Z'))) // and return by setting buf to "" on an unparsible string.
{ if (buf.equals(""))
if (! expect (source, pos, ch)) {
return null; pos.setIndex(index);
continue;
}
// We've arrived at a potential pattern character in the // This is the minimum we need
// pattern. if ((month == -1) || (day == -1) || (year == -1))
int first = fmt_index; {
while (++fmt_index < fmt_max && pattern.charAt(fmt_index) == ch) pos.setErrorIndex(index);
; return null;
int count = fmt_index - first; }
--fmt_index;
if (tz != null)
// We can handle most fields automatically: most either are cal.setTimeZone(tz);
// numeric or are looked up in a string vector. In some cases
// we need an offset. When numeric, `offset' is added to the cal.set(Calendar.YEAR, year);
// resulting value. When doing a string lookup, offset is the cal.set(Calendar.MONTH, month - 1);
// initial index into the string array. cal.set(Calendar.DATE, day);
int calendar_field;
boolean is_numeric = true; if (ampm == 0)
String[] match = null; cal.set(Calendar.AM_PM, Calendar.AM);
int offset = 0; else if (ampm == 1)
int zone_number = 0; cal.set(Calendar.AM_PM, Calendar.PM);
switch (ch)
{ // If am/pm not set, we assume 24 hour day
case 'd': if (hour != -1)
calendar_field = Calendar.DATE; {
break; if (ampm == -1)
case 'D': cal.set(Calendar.HOUR_OF_DAY, hour);
calendar_field = Calendar.DAY_OF_YEAR; else
break; {
case 'F': if (ampm == 0)
calendar_field = Calendar.DAY_OF_WEEK_IN_MONTH; {
break; if (hour == 12)
case 'E': hour = 0;
is_numeric = false; }
offset = 1; else
calendar_field = Calendar.DAY_OF_WEEK; {
match = (count <= 3 if (hour != 12)
? formatData.getShortWeekdays() hour += 12;
: formatData.getWeekdays()); }
break;
case 'w': cal.set(Calendar.HOUR_OF_DAY, hour);
calendar_field = Calendar.WEEK_OF_YEAR; }
break; }
case 'W':
calendar_field = Calendar.WEEK_OF_MONTH; if (minute != -1)
break; cal.set(Calendar.MINUTE, minute);
case 'M':
calendar_field = Calendar.MONTH; if (second != -1)
if (count <= 2) cal.set(Calendar.SECOND, second);
;
else if (millis != -1)
{ cal.set(Calendar.MILLISECOND, millis);
is_numeric = false;
match = (count <= 3 if (era == 0)
? formatData.getShortMonths() cal.set(Calendar.ERA, GregorianCalendar.BC);
: formatData.getMonths()); else if (era == 1)
} cal.set(Calendar.ERA, GregorianCalendar.AD);
break;
case 'y': return cal.getTime();
calendar_field = Calendar.YEAR; }
if (count <= 2)
offset = 1900; // Skip over whitespace and expected punctuation
break; char c = buf.charAt(0);
case 'K': boolean comma_found = false;
calendar_field = Calendar.HOUR; while(Character.isWhitespace(c) || (c == ':') ||
break; (c == ',') || (c == '.') || (c == '/'))
case 'h': {
calendar_field = Calendar.HOUR; lastsep = c;
offset = -1; if (c == ',') // This is a total and utter crock
break; comma_found = true;
case 'H': buf = buf.substring(1);
calendar_field = Calendar.HOUR_OF_DAY; if (buf.equals(""))
break; continue;
case 'k': c = buf.charAt(0);
calendar_field = Calendar.HOUR_OF_DAY; }
offset = -1;
break; if (comma_found == true)
case 'm': lastsep = ',';
calendar_field = Calendar.MINUTE;
break; // Is it a month name?
case 's': for (int i = 0; i < formatData.months.length; i++)
calendar_field = Calendar.SECOND; if ((formatData.months[i] != null)
break; && buf.startsWith(formatData.months[i]))
case 'S': {
calendar_field = Calendar.MILLISECOND; month = i + 1;
break; buf = buf.substring(formatData.months[i].length());
case 'a': index += formatData.months[i].length();
is_numeric = false; last = MONTH_FIELD;
calendar_field = Calendar.AM_PM; continue top;
match = formatData.getAmPmStrings(); }
break;
case 'z': // Is it a short month name?
// We need a special case for the timezone, because it for (int i = 0; i < formatData.shortMonths.length; i++)
// uses a different data structure than the other cases. if ((formatData.shortMonths[i] != null)
is_numeric = false; && buf.startsWith(formatData.shortMonths[i]))
calendar_field = Calendar.DST_OFFSET; {
String[][] zoneStrings = formatData.getZoneStrings(); month = i + 1;
int zoneCount = zoneStrings.length; buf = buf.substring(formatData.shortMonths[i].length());
int index = pos.getIndex(); index += formatData.shortMonths[i].length();
boolean found_zone = false; last = MONTH_FIELD;
for (int j = 0; j < zoneCount; j++) continue top;
{ }
String[] strings = zoneStrings[j];
int k; // Is it a weekday name?
for (k = 1; k < strings.length; ++k) for (int i = 0; i < formatData.weekdays.length; i++)
{ if ((formatData.weekdays[i] != null)
if (source.startsWith(strings[k], index)) && buf.startsWith(formatData.weekdays[i]))
break; {
} buf = buf.substring(formatData.weekdays[i].length());
if (k != strings.length) index += formatData.weekdays[i].length();
{ last = DAY_OF_WEEK_FIELD;
if (k > 2) continue top;
; // FIXME: dst. }
zone_number = 0; // FIXME: dst.
// FIXME: raw offset to SimpleTimeZone const. // Is it a short weekday name?
calendar.setTimeZone(new SimpleTimeZone (1, strings[0])); for (int i = 0; i < formatData.shortWeekdays.length; i++)
pos.setIndex(index + strings[k].length()); if ((formatData.shortWeekdays[i] != null)
break; && buf.startsWith(formatData.shortWeekdays[i]))
} {
} buf = buf.substring(formatData.shortWeekdays[i].length());
if (! found_zone) index += formatData.shortWeekdays[i].length();
{ last = DAY_OF_WEEK_FIELD;
pos.setErrorIndex(pos.getIndex()); continue top;
return null; }
}
break; // Is this an am/pm string?
default: for (int i = 0; i < formatData.ampms.length; i++) {
if ((formatData.ampms[i] != null)
&& buf.toLowerCase().startsWith(formatData.ampms[i].toLowerCase()))
{
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))
{
nbrstr = nbrstr + c;
buf = buf.substring(1);
if (buf.equals(""))
break;
c = buf.charAt(0);
}
// 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 != '/'))
{
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;
}
}
tz = tmptz;
last = TIMEZONE_FIELD;
index += nbrstr.length();
continue top;
}
// Convert to integer
int val = 0;
try
{
val = Integer.parseInt(nbrstr);
}
catch(Exception e)
{
return null; // Shouldn't happen
}
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)
{
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 (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();
String buf = null;
if (p.size == 1)
{
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);
}
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()); pos.setErrorIndex(pos.getIndex());
return null; return null;
} }
pos.setIndex(pos.getIndex() + formatData.eras[value].length());
theCalendar.set(Calendar.ERA,value);
break;
// Compute the value we should assign to the field. case YEAR_FIELD:
int value; String y;
if (is_numeric) if (p.size < 4)
{ y = dateStr.substring(pos.getIndex(), pos.getIndex() + 2);
numberFormat.setMinimumIntegerDigits(count); else
Number n = numberFormat.parse(source, pos); y = dateStr.substring(pos.getIndex(), pos.getIndex() + 4);
if (pos == null || ! (n instanceof Long))
return null; int year;
value = n.intValue() + offset; try
} {
else if (match != null) year = Integer.parseInt(y);
{ }
int index = pos.getIndex(); catch(NumberFormatException nfe)
int i; {
for (i = offset; i < match.length; ++i) pos.setErrorIndex(pos.getIndex());
{ return null;
if (source.startsWith(match[i], index)) }
break;
}
if (i == match.length)
{
pos.setErrorIndex(index);
return null;
}
pos.setIndex(index + match[i].length());
value = i;
}
else
value = zone_number;
// Assign the value and move on. if (p.size < 4)
try year += get2DigitYearStart().getYear();
{
calendar.set(calendar_field, value); 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
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;
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
{
value = Integer.parseInt(buf);
}
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;
} }
// FIXME: what exception is thrown on an invalid pos.setIndex(pos.getIndex() + ((p.size < 4) ? formatData.shortWeekdays[value].length()
// non-lenient set? : formatData.weekdays[value].length()));
catch (IllegalArgumentException x) // 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()); pos.setErrorIndex(pos.getIndex());
return null; 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;
*/
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;
}
} }
}
return calendar.getTime(); if (hour != -1)
} {
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);
}
else
{
if (hour == 12)
theCalendar.set(Calendar.HOUR_OF_DAY, 0);
else
theCalendar.set(Calendar.HOUR_OF_DAY, hour);
}
}
public boolean equals (Object obj) return theCalendar.getTime();
{
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));
} }
public Object clone () /**
{ * This method parses the specified string into a date.
// We know the superclass just call's Object's generic cloner. *
return super.clone (); * @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);
public int hashCode ()
{
int hash = super.hashCode();
if (pattern != null)
hash ^= pattern.hashCode();
return hash;
} }
} }
/* 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; package java.util;
import java.text.DateFormatSymbols;
/** /**
* @author Per Bothner <bothner@cygnus.com> * This class represents a time zone offset and handles daylight savings.
* @date October 24, 1998. *
*/ * You can get the default time zone with <code>getDefault</code>.
* This represents the time zone where program is running.
/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3. *
* Status: getAvailableIDs, getDefault, getTimeZone only know about GMT. * 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
*/ */
public abstract class TimeZone implements java.io.Serializable, Cloneable 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 SHORT = 0;
/**
* Constant used to indicate that a long timezone name should be
* returned, such as "Eastern Standard Time".
*/
public static final int LONG = 1; 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. * The time zone identifier, e.g. PST.
String ID; */
private String ID;
static final TimeZone zoneGMT = new SimpleTimeZone(0, "GMT"); /**
* The default time zone, as returned by getDefault.
private static TimeZone zoneDefault; */
private static TimeZone defaultZone;
private static final long serialVersionUID = 3581463369166924961L; 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));
} }
*/
public abstract boolean useDaylightTime(); /**
* 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 inDaylightTime (Date date);
public static synchronized TimeZone getTimeZone (String ID) /**
* 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)
{ {
int i; DateFormatSymbols dfs;
for (i = 0; i < tzIDs.length; ++i) try
{ {
if (ID.equals(tzIDs[i])) dfs = new DateFormatSymbols(locale);
break;
}
if (i == tzIDs.length)
return null;
if (timeZones[i] == null) // The format of the value returned is defined by us.
String[][]zoneinfo = dfs.getZoneStrings();
for (int i = 0; i < zoneinfo.length; i++)
{
if (zoneinfo[i][0].equals(getID()))
{
if (!dst)
{
if (style == SHORT)
return (zoneinfo[i][2]);
else
return (zoneinfo[i][1]);
}
else
{
if (style == SHORT)
return (zoneinfo[i][4]);
else
return (zoneinfo[i][3]);
}
}
}
}
catch (MissingResourceException e)
{ {
if (ID.equals("GMT"))
timeZones[i] = zoneGMT;
else
timeZones[i] = new SimpleTimeZone (rawOffsets[i], tzIDs[i]);
} }
return timeZones[i]; return getDefaultDisplayName(dst);
} }
public static String[] getAvailableIDs() private String getDefaultDisplayName(boolean dst)
{ {
return (String[]) tzIDs.clone(); int offset = getRawOffset();
if (dst && this instanceof SimpleTimeZone)
{
// 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();
}
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();
} }
public static String[] getAvailableIDs(int rawOffset) /**
{ * Returns true, if this time zone uses Daylight Savings Time.
int first, last; */
public abstract boolean useDaylightTime();
for (first = 0; first < rawOffsets.length; ++first) /**
{ * Returns true, if the given date is in Daylight Savings Time in this
if (rawOffset == rawOffsets[first]) * time zone.
break; * @param date the given Date.
} */
if (first == rawOffsets.length) public abstract boolean inDaylightTime(Date date);
return new String[0];
for (last = first + 1; last < rawOffsets.length; ++last) /**
* 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)
{ {
if (rawOffset != rawOffsets[last]) if (tz.getID().equals(ID))
break; return tz;
// 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;
} }
String[] r = new String[last - first]; // See if the ID is really a GMT offset form.
for (int i = first; i < last; ++i) // Note that GMT is in the table so we know it is different.
if (ID.startsWith("GMT"))
{ {
r[i - first] = tzIDs[i]; int pos = 3;
} int offset_direction = 1;
return r; if (ID.charAt(pos) == '-')
} {
offset_direction = -1;
pos++;
}
else if (ID.charAt(pos) == '+')
{
pos++;
}
private static synchronized TimeZone setDefault()
{
if (zoneDefault == null)
{
try try
{ {
String id = System.getProperty("user.timezone"); int hour, minute;
if (id != null && ! id.equals("GMT"))
zoneDefault = getTimeZone(id); 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));
}
}
return new SimpleTimeZone((hour * (60 * 60 * 1000) +
minute * (60 * 1000))
* offset_direction, ID);
} }
catch (Exception ex) catch (NumberFormatException e)
{ {
} }
if (zoneDefault == null)
zoneDefault = zoneGMT;
} }
return zoneDefault;
// Finally, return GMT per spec
return getTimeZone("GMT");
} }
public static TimeZone getDefault() /**
* 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)
{ {
return zoneDefault == null ? setDefault() : zoneDefault; int count = 0;
Iterator iter = timezones.entrySet().iterator();
while (iter.hasNext())
{
// 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++;
}
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();
}
return ids;
} }
******************************************************************/
public static void setDefault (TimeZone zone) { zoneDefault = zone; } /**
* 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()]);
}
******************************************************************/
public boolean hasSameRules (TimeZone other) /**
* 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 this == other; return defaultZone;
} }
public Object clone () public static void setDefault(TimeZone zone)
{ {
// Just use Object's generic cloner. defaultZone = zone;
return super.clone ();
} }
// Names of timezones. This array is kept in parallel with /**
// rawOffsets. This list comes from the JCL 1.1 book. * Test if the other time zone uses the same rule and only
private static final String[] tzIDs = * 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)
{ {
"MIT", "HST", "AST", "PST", "PNT", return other.getRawOffset() == getRawOffset();
"MST", "CST", "EST", "IET", "PRT", }
"CNT", "AGT", "BET", "CAT", "GMT",
"ECT", "EET", "ART", "EAT", "MET", /**
"NET", "PLT", "IST", "BST", "VST", * Returns a clone of this object. I can't imagine, why this is
"CTT", "JST", "ACT", "AET", "SST", * useful for a time zone.
"NST" */
}; public Object clone()
// This holds raw offsets in milliseconds.
// 3600000 == 60 * 60 * 1000
private static final int[] rawOffsets =
{ {
-11 * 3600000, -10 * 3600000, -9 * 3600000, -8 * 3600000, -7 * 3600000, try
-7 * 3600000, -6 * 3600000, -5 * 3600000, -5 * 3600000, -4 * 3600000, {
-35 * 360000, -3 * 3600000, -3 * 3600000, -1 * 3600000, 0, return super.clone();
1 * 3600000, 1 * 3600000, 2 * 3600000, 3 * 3600000, 35 * 360000, }
4 * 3600000, 5 * 3600000, 55 * 360000, 6 * 3600000, 7 * 3600000, catch (CloneNotSupportedException ex)
8 * 3600000, 9 * 3600000, 95 * 360000, 10 * 3600000, 11 * 3600000, {
12 * 3600000 return null;
}; }
// This caches all the corresponding zone objects. }
private static TimeZone[] timeZones = new TimeZone[tzIDs.length];
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