re PR libgcj/17002 (java.util.TimeZone.getDefault() is broken)

libjava/
	PR libgcj/17002
	PR classpath/28550
	* java/util/VMTimeZone.java (getDefaultTimeZoneId): To read
	/etc/localtime, use ZoneInfo.readTZFile instead of
	VMTimeZone.readtzFile.  Get better timezone name for /etc/localtime,
	either if it is a symlink or through /etc/sysconfig/clock.
	(readSysconfigClockFile): New static method.
	(readtzFile): Removed.
	* java/lang/System.java: Add gnu.java.util.zoneinfo.dir to comments.
	* posix.cc (_Jv_platform_initProperties): Set
	gnu.java.util.zoneinfo.dir.
	* sources.am (gnu_java_util_source_files): Add
	classpath/gnu/java/util/ZoneInfo.java.
	* Makefile.in: Regenerated.
	* java/util/VMTimeZone.h: Regenerated.
	* java/util/TimeZone.h: Regenerated.
	* gnu/java/util/ZoneInfo.h: Generated.
libjava/classpath/
	* java/util/Date.java (parse): Properly parse 09:01:02 as
	hours/minutes/seconds, not as hours/minutes/year.
	* java/util/SimpleTimeZone.java (SimpleTimeZone): Simplify
	{start,end}TimeMode constructor by calling shorter constructor,
	set {start,end}TimeMode fields after it returns.
	(setStartRule): Don't adjust startTime into WALL_TIME.  Set
	startTimeMode to WALL_TIME.
	(endStartRule): Similarly.
	(getOffset): Handle properly millis + dstOffset overflowing into the
	next day.  Adjust startTime resp. endTime based on startTimeMode
	resp. endTimeMode.
	* java/util/TimeZone.java (zoneinfo_dir, availableIDs, aliases0): New
	static fields.
	(timezones): Remove synchronized keyword.  Set zoneinfo_dir.
	If non-null, set up aliases0 and don't put anything into
	timezones0.
	(defaultZone): Call getTimeZone instead of timezones().get.
	(getDefaultTimeZone): Fix parsing of EST5 or EST5EDT6.  Use
	getTimeZoneInternal instead of timezones().get.
	(parseTime): Parse correctly hour:minute.
	(getTimeZoneInternal): New private method.
	(getTimeZone): Do the custom ID checking first, canonicalize
	ID for custom IDs as required by documentation.  Call
	getTimeZoneInternal to handle the rest.
	(getAvailableIDs(int)): Add locking.  Handle zoneinfo_dir != null.
	(getAvailableIDs(File,String,ArrayList)): New private method.
	(getAvailableIDs()): Add locking.  Handle zoneinfo_dir != null.
	* gnu/java/util/ZoneInfo.java: New file.

From-SVN: r122229
This commit is contained in:
Jakub Jelinek 2007-02-22 17:04:55 +01:00 committed by Jakub Jelinek
parent 0c5c188f07
commit b3502aa8d4
20 changed files with 1702 additions and 607 deletions

View file

@ -1,3 +1,23 @@
2007-02-22 Jakub Jelinek <jakub@redhat.com>
PR libgcj/17002
PR classpath/28550
* java/util/VMTimeZone.java (getDefaultTimeZoneId): To read
/etc/localtime, use ZoneInfo.readTZFile instead of
VMTimeZone.readtzFile. Get better timezone name for /etc/localtime,
either if it is a symlink or through /etc/sysconfig/clock.
(readSysconfigClockFile): New static method.
(readtzFile): Removed.
* java/lang/System.java: Add gnu.java.util.zoneinfo.dir to comments.
* posix.cc (_Jv_platform_initProperties): Set
gnu.java.util.zoneinfo.dir.
* sources.am (gnu_java_util_source_files): Add
classpath/gnu/java/util/ZoneInfo.java.
* Makefile.in: Regenerated.
* java/util/VMTimeZone.h: Regenerated.
* java/util/TimeZone.h: Regenerated.
* gnu/java/util/ZoneInfo.h: Generated.
2007-02-22 Mohan Embar <gnustuff@thisiscool.com>
* include/win32-threads.h: Added #undef OUT.

View file

@ -2402,7 +2402,8 @@ gnu_java_text_header_files = $(patsubst classpath/%,%,$(patsubst %.java,%.h,$(gn
gnu_java_util_source_files = \
classpath/gnu/java/util/DoubleEnumeration.java \
classpath/gnu/java/util/EmptyEnumeration.java \
classpath/gnu/java/util/WeakIdentityHashMap.java
classpath/gnu/java/util/WeakIdentityHashMap.java \
classpath/gnu/java/util/ZoneInfo.java
gnu_java_util_header_files = $(patsubst classpath/%,%,$(patsubst %.java,%.h,$(gnu_java_util_source_files)))
gnu_java_util_jar_source_files = \

View file

@ -1,3 +1,34 @@
2007-02-20 Jakub Jelinek <jakub@redhat.com>
* java/util/Date.java (parse): Properly parse 09:01:02 as
hours/minutes/seconds, not as hours/minutes/year.
* java/util/SimpleTimeZone.java (SimpleTimeZone): Simplify
{start,end}TimeMode constructor by calling shorter constructor,
set {start,end}TimeMode fields after it returns.
(setStartRule): Don't adjust startTime into WALL_TIME. Set
startTimeMode to WALL_TIME.
(endStartRule): Similarly.
(getOffset): Handle properly millis + dstOffset overflowing into the
next day. Adjust startTime resp. endTime based on startTimeMode
resp. endTimeMode.
* java/util/TimeZone.java (zoneinfo_dir, availableIDs, aliases0): New
static fields.
(timezones): Remove synchronized keyword. Set zoneinfo_dir.
If non-null, set up aliases0 and don't put anything into
timezones0.
(defaultZone): Call getTimeZone instead of timezones().get.
(getDefaultTimeZone): Fix parsing of EST5 or EST5EDT6. Use
getTimeZoneInternal instead of timezones().get.
(parseTime): Parse correctly hour:minute.
(getTimeZoneInternal): New private method.
(getTimeZone): Do the custom ID checking first, canonicalize
ID for custom IDs as required by documentation. Call
getTimeZoneInternal to handle the rest.
(getAvailableIDs(int)): Add locking. Handle zoneinfo_dir != null.
(getAvailableIDs(File,String,ArrayList)): New private method.
(getAvailableIDs()): Add locking. Handle zoneinfo_dir != null.
* gnu/java/util/ZoneInfo.java: New file.
2007-02-20 Matthias Klose <doko@ubuntu.com>
* doc/Makefile.am: Add rules to build and install man pages

File diff suppressed because it is too large Load diff

View file

@ -754,6 +754,7 @@ public class Date
}
else if (firstch >= '0' && firstch <= '9')
{
int lastPunct = -1;
while (tok != null && tok.length() > 0)
{
int punctOffset = tok.length();
@ -791,6 +792,13 @@ public class Date
else
minute = num;
}
else if (lastPunct == ':' && hour >= 0 && (minute < 0 || second < 0))
{
if (minute < 0)
minute = num;
else
second = num;
}
else if ((num >= 70
&& (punct == ' ' || punct == ','
|| punct == '/' || punct < 0))
@ -828,6 +836,7 @@ public class Date
tok = null;
else
tok = tok.substring(punctOffset + 1);
lastPunct = punct;
}
}
else if (firstch >= 'A' && firstch <= 'Z')

View file

@ -1,5 +1,6 @@
/* java.util.SimpleTimeZone
Copyright (C) 1998, 1999, 2000, 2003, 2004, 2005 Free Software Foundation, Inc.
Copyright (C) 1998, 1999, 2000, 2003, 2004, 2005, 2007
Free Software Foundation, Inc.
This file is part of GNU Classpath.
@ -141,8 +142,8 @@ public class SimpleTimeZone extends TimeZone
/**
* This variable specifies the time of change to daylight savings.
* This time is given in milliseconds after midnight local
* standard time.
* This time is given in milliseconds after midnight in startTimeMode
* chosen time mode.
* @serial
*/
private int startTime;
@ -187,8 +188,8 @@ public class SimpleTimeZone extends TimeZone
/**
* This variable specifies the time of change back to standard time.
* This time is given in milliseconds after midnight local
* standard time.
* This time is given in milliseconds after midnight in endTimeMode
* chosen time mode.
* @serial
*/
private int endTime;
@ -380,24 +381,17 @@ public class SimpleTimeZone extends TimeZone
int endDayOfWeekInMonth, int endDayOfWeek,
int endTime, int endTimeMode, int dstSavings)
{
this.rawOffset = rawOffset;
setID(id);
useDaylight = true;
this(rawOffset, id, startMonth, startDayOfWeekInMonth, startDayOfWeek,
startTime, endMonth, endDayOfWeekInMonth, endDayOfWeek, endTime);
if (startTimeMode < WALL_TIME || startTimeMode > UTC_TIME)
throw new IllegalArgumentException("startTimeMode must be one of WALL_TIME, STANDARD_TIME, or UTC_TIME");
if (endTimeMode < WALL_TIME || endTimeMode > UTC_TIME)
throw new IllegalArgumentException("endTimeMode must be one of WALL_TIME, STANDARD_TIME, or UTC_TIME");
this.startTimeMode = startTimeMode;
this.endTimeMode = endTimeMode;
setStartRule(startMonth, startDayOfWeekInMonth, startDayOfWeek, startTime);
setEndRule(endMonth, endDayOfWeekInMonth, endDayOfWeek, endTime);
if (startMonth == endMonth)
throw new IllegalArgumentException("startMonth and endMonth must be different");
this.startYear = 0;
this.dstSavings = dstSavings;
this.startTimeMode = startTimeMode;
this.endTimeMode = endTimeMode;
}
/**
@ -477,12 +471,8 @@ public class SimpleTimeZone extends TimeZone
this.startMonth = month;
this.startDay = day;
this.startDayOfWeek = Math.abs(dayOfWeek);
if (this.startTimeMode == WALL_TIME || this.startTimeMode == STANDARD_TIME)
this.startTime = time;
else
// Convert from UTC to STANDARD
this.startTime = time + this.rawOffset;
useDaylight = true;
this.startTime = time;
this.startTimeMode = WALL_TIME;
}
/**
@ -513,24 +503,10 @@ public class SimpleTimeZone extends TimeZone
public void setStartRule(int month, int day, int dayOfWeek, int time,
boolean after)
{
// FIXME: XXX: Validate that checkRule and offset processing work with on
// or before mode.
this.startDay = after ? Math.abs(day) : -Math.abs(day);
this.startDayOfWeek = after ? Math.abs(dayOfWeek) : -Math.abs(dayOfWeek);
this.startMode = (dayOfWeek != 0)
? (after ? DOW_GE_DOM_MODE : DOW_LE_DOM_MODE)
: checkRule(month, day, dayOfWeek);
this.startDay = Math.abs(this.startDay);
this.startDayOfWeek = Math.abs(this.startDayOfWeek);
this.startMonth = month;
if (this.startTimeMode == WALL_TIME || this.startTimeMode == STANDARD_TIME)
this.startTime = time;
if (after)
setStartRule(month, day, -dayOfWeek, time);
else
// Convert from UTC to STANDARD
this.startTime = time + this.rawOffset;
useDaylight = true;
setStartRule(month, -day, -dayOfWeek, time);
}
/**
@ -570,14 +546,8 @@ public class SimpleTimeZone extends TimeZone
this.endMonth = month;
this.endDay = day;
this.endDayOfWeek = Math.abs(dayOfWeek);
if (this.endTimeMode == WALL_TIME)
this.endTime = time;
else if (this.endTimeMode == STANDARD_TIME)
// Convert from STANDARD to DST
this.endTime = time + this.dstSavings;
else
// Convert from UTC to DST
this.endTime = time + this.rawOffset + this.dstSavings;
this.endTime = time;
this.endTimeMode = WALL_TIME;
useDaylight = true;
}
@ -607,27 +577,10 @@ public class SimpleTimeZone extends TimeZone
public void setEndRule(int month, int day, int dayOfWeek, int time,
boolean after)
{
// FIXME: XXX: Validate that checkRule and offset processing work with on
// or before mode.
this.endDay = after ? Math.abs(day) : -Math.abs(day);
this.endDayOfWeek = after ? Math.abs(dayOfWeek) : -Math.abs(dayOfWeek);
this.endMode = (dayOfWeek != 0)
? (after ? DOW_GE_DOM_MODE : DOW_LE_DOM_MODE)
: checkRule(month, day, dayOfWeek);
this.endDay = Math.abs(this.endDay);
this.endDayOfWeek = Math.abs(endDayOfWeek);
this.endMonth = month;
if (this.endTimeMode == WALL_TIME)
this.endTime = time;
else if (this.endTimeMode == STANDARD_TIME)
// Convert from STANDARD to DST
this.endTime = time + this.dstSavings;
if (after)
setEndRule(month, day, -dayOfWeek, time);
else
// Convert from UTC to DST
this.endTime = time + this.rawOffset + this.dstSavings;
useDaylight = true;
setEndRule(month, -day, -dayOfWeek, time);
}
/**
@ -688,16 +641,37 @@ public class SimpleTimeZone extends TimeZone
int daylightSavings = 0;
if (useDaylight && era == GregorianCalendar.AD && year >= startYear)
{
int orig_year = year;
int time = startTime + (startTimeMode == UTC_TIME ? rawOffset : 0);
// This does only work for Gregorian calendars :-(
// This is mainly because setStartYear doesn't take an era.
boolean afterStart = ! isBefore(year, month, day, dayOfWeek, millis,
startMode, startMonth, startDay,
startDayOfWeek, startTime);
boolean beforeEnd = isBefore(year, month, day, dayOfWeek,
millis + dstSavings,
endMode, endMonth, endDay, endDayOfWeek,
endTime);
startDayOfWeek, time);
millis += dstSavings;
if (millis >= 24 * 60 * 60 * 1000)
{
millis -= 24 * 60 * 60 * 1000;
dayOfWeek = (dayOfWeek % 7) + 1;
if (++day > daysInMonth)
{
day = 1;
if (month++ == Calendar.DECEMBER)
{
month = Calendar.JANUARY;
year++;
}
}
}
time = endTime + (endTimeMode == UTC_TIME ? rawOffset : 0);
if (endTimeMode != WALL_TIME)
time += dstSavings;
boolean beforeEnd = isBefore(year, month, day, dayOfWeek, millis,
endMode, endMonth, endDay, endDayOfWeek,
time);
if (year != orig_year)
afterStart = false;
if (startMonth < endMonth)
// use daylight savings, if the date is after the start of
// savings, and before the end of savings.

View file

@ -39,6 +39,9 @@ exception statement from your version. */
package java.util;
import gnu.classpath.SystemProperties;
import gnu.java.util.ZoneInfo;
import java.io.File;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.text.DateFormatSymbols;
@ -115,7 +118,7 @@ public abstract class TimeZone implements java.io.Serializable, Cloneable
// Fall back on GMT.
if (zone == null)
zone = (TimeZone) timezones().get("GMT");
zone = getTimeZone ("GMT");
return zone;
}
@ -127,6 +130,22 @@ public abstract class TimeZone implements java.io.Serializable, Cloneable
private static final long serialVersionUID = 3581463369166924961L;
/**
* Flag whether zoneinfo data should be used,
* otherwise builtin timezone data will be provided.
*/
private static String zoneinfo_dir;
/**
* Cached copy of getAvailableIDs().
*/
private static String[] availableIDs = null;
/**
* JDK 1.1.x compatibility aliases.
*/
private static HashMap aliases0;
/**
* HashMap for timezones by ID.
*/
@ -135,13 +154,55 @@ public abstract class TimeZone implements java.io.Serializable, Cloneable
* it is not needed:
*/
// Package-private to avoid a trampoline.
static synchronized HashMap timezones()
static HashMap timezones()
{
if (timezones0 == null)
{
HashMap timezones = new HashMap();
timezones0 = timezones;
zoneinfo_dir = SystemProperties.getProperty("gnu.java.util.zoneinfo.dir");
if (zoneinfo_dir != null && !new File(zoneinfo_dir).isDirectory())
zoneinfo_dir = null;
if (zoneinfo_dir != null)
{
aliases0 = new HashMap();
// These deprecated aliases for JDK 1.1.x compatibility
// should take precedence over data files read from
// /usr/share/zoneinfo.
aliases0.put("ACT", "Australia/Darwin");
aliases0.put("AET", "Australia/Sydney");
aliases0.put("AGT", "America/Argentina/Buenos_Aires");
aliases0.put("ART", "Africa/Cairo");
aliases0.put("AST", "America/Juneau");
aliases0.put("BST", "Asia/Colombo");
aliases0.put("CAT", "Africa/Gaborone");
aliases0.put("CNT", "America/St_Johns");
aliases0.put("CST", "CST6CDT");
aliases0.put("CTT", "Asia/Brunei");
aliases0.put("EAT", "Indian/Comoro");
aliases0.put("ECT", "CET");
aliases0.put("EST", "EST5EDT");
aliases0.put("EST5", "EST5EDT");
aliases0.put("IET", "EST5EDT");
aliases0.put("IST", "Asia/Calcutta");
aliases0.put("JST", "Asia/Seoul");
aliases0.put("MIT", "Pacific/Niue");
aliases0.put("MST", "MST7MDT");
aliases0.put("MST7", "MST7MDT");
aliases0.put("NET", "Indian/Mauritius");
aliases0.put("NST", "Pacific/Auckland");
aliases0.put("PLT", "Indian/Kerguelen");
aliases0.put("PNT", "MST7MDT");
aliases0.put("PRT", "America/Anguilla");
aliases0.put("PST", "PST8PDT");
aliases0.put("SST", "Pacific/Ponape");
aliases0.put("VST", "Asia/Bangkok");
return timezones;
}
TimeZone tz;
// Automatically generated by scripts/timezones.pl
// XXX - Should we read this data from a file?
@ -887,7 +948,6 @@ public abstract class TimeZone implements java.io.Serializable, Cloneable
static TimeZone getDefaultTimeZone(String sysTimeZoneId)
{
String stdName = null;
String dstName;
int stdOffs;
int dstOffs;
try
@ -900,14 +960,14 @@ public abstract class TimeZone implements java.io.Serializable, Cloneable
// get std
do
c = sysTimeZoneId.charAt(index++);
c = sysTimeZoneId.charAt(index);
while (c != '+' && c != '-' && c != ',' && c != ':'
&& ! Character.isDigit(c) && c != '\0' && index < idLength);
&& ! Character.isDigit(c) && c != '\0' && ++index < idLength);
if (index >= idLength)
return (TimeZone)timezones().get(sysTimeZoneId);
return getTimeZoneInternal(sysTimeZoneId);
stdName = sysTimeZoneId.substring(0, --index);
stdName = sysTimeZoneId.substring(0, index);
prevIndex = index;
// get the std offset
@ -938,7 +998,7 @@ public abstract class TimeZone implements java.io.Serializable, Cloneable
if (index >= idLength)
{
// Do we have an existing timezone with that name and offset?
TimeZone tz = (TimeZone) timezones().get(stdName);
TimeZone tz = getTimeZoneInternal(stdName);
if (tz != null)
if (tz.getRawOffset() == stdOffs)
return tz;
@ -949,16 +1009,16 @@ public abstract class TimeZone implements java.io.Serializable, Cloneable
// get dst
do
c = sysTimeZoneId.charAt(index++);
c = sysTimeZoneId.charAt(index);
while (c != '+' && c != '-' && c != ',' && c != ':'
&& ! Character.isDigit(c) && c != '\0' && index < idLength);
&& ! Character.isDigit(c) && c != '\0' && ++index < idLength);
// Done yet? (Format: std offset dst)
if (index >= idLength)
{
// Do we have an existing timezone with that name and offset
// which has DST?
TimeZone tz = (TimeZone) timezones().get(stdName);
TimeZone tz = getTimeZoneInternal(stdName);
if (tz != null)
if (tz.getRawOffset() == stdOffs && tz.useDaylightTime())
return tz;
@ -968,7 +1028,6 @@ public abstract class TimeZone implements java.io.Serializable, Cloneable
}
// get the dst offset
dstName = sysTimeZoneId.substring(prevIndex, --index);
prevIndex = index;
do
c = sysTimeZoneId.charAt(index++);
@ -1005,7 +1064,7 @@ public abstract class TimeZone implements java.io.Serializable, Cloneable
if (index >= idLength)
{
// Time Zone existing with same name, dst and offsets?
TimeZone tz = (TimeZone) timezones().get(stdName);
TimeZone tz = getTimeZoneInternal(stdName);
if (tz != null)
if (tz.getRawOffset() == stdOffs && tz.useDaylightTime()
&& tz.getDSTSavings() == (dstOffs - stdOffs))
@ -1171,10 +1230,10 @@ public abstract class TimeZone implements java.io.Serializable, Cloneable
break;
else
i++;
millis += 60 * 1000 * Integer.parseInt(time.substring(iprev, i));
if (i >= time.length())
return millis;
millis += 60 * 1000 * Integer.parseInt(time.substring(iprev, i));
millis += 1000 * Integer.parseInt(time.substring(++i));
return millis;
}
@ -1406,30 +1465,67 @@ public abstract class TimeZone implements java.io.Serializable, Cloneable
* @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)
private static TimeZone getTimeZoneInternal(String ID)
{
// First check timezones hash
TimeZone tz = (TimeZone) timezones().get(ID);
if (tz != null)
TimeZone tz = null;
TimeZone tznew = null;
for (int pass = 0; pass < 2; pass++)
{
if (tz.getID().equals(ID))
return tz;
synchronized (TimeZone.class)
{
tz = (TimeZone) timezones().get(ID);
if (tz != null)
{
if (!tz.getID().equals(ID))
{
// 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;
}
else if (tznew != null)
{
timezones().put(ID, tznew);
return tznew;
}
}
// 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;
if (pass == 1 || zoneinfo_dir == null)
return null;
// aliases0 is never changing after first timezones(), so should
// be safe without synchronization.
String zonename = (String) aliases0.get(ID);
if (zonename == null)
zonename = ID;
// Read the file outside of the critical section, it is expensive.
tznew = ZoneInfo.readTZFile (ID, zoneinfo_dir
+ File.separatorChar + zonename);
if (tznew == null)
return null;
}
// 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"))
return null;
}
/**
* 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.
*/
public static TimeZone getTimeZone(String ID)
{
// Check for custom IDs first
if (ID.startsWith("GMT") && ID.length() > 3)
{
int pos = 3;
int offset_direction = 1;
@ -1474,8 +1570,20 @@ public abstract class TimeZone implements java.io.Serializable, Cloneable
}
}
return new SimpleTimeZone((hour * (60 * 60 * 1000) +
minute * (60 * 1000))
// Custom IDs have to be normalized
StringBuffer sb = new StringBuffer(9);
sb.append("GMT");
sb.append(offset_direction >= 0 ? '+' : '-');
sb.append((char) ('0' + hour / 10));
sb.append((char) ('0' + hour % 10));
sb.append(':');
sb.append((char) ('0' + minute / 10));
sb.append((char) ('0' + minute % 10));
ID = sb.toString();
return new SimpleTimeZone((hour * (60 * 60 * 1000)
+ minute * (60 * 1000))
* offset_direction, ID);
}
catch (NumberFormatException e)
@ -1483,8 +1591,11 @@ public abstract class TimeZone implements java.io.Serializable, Cloneable
}
}
// Finally, return GMT per spec
return getTimeZone("GMT");
TimeZone tz = getTimeZoneInternal(ID);
if (tz != null)
return tz;
return new SimpleTimeZone(0, "GMT");
}
/**
@ -1497,37 +1608,134 @@ public abstract class TimeZone implements java.io.Serializable, Cloneable
*/
public static String[] getAvailableIDs(int rawOffset)
{
int count = 0;
Iterator iter = timezones().entrySet().iterator();
while (iter.hasNext())
synchronized (TimeZone.class)
{
// 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++;
HashMap h = timezones();
int count = 0;
if (zoneinfo_dir == null)
{
Iterator iter = h.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 = h.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;
}
}
String[] s = getAvailableIDs();
int count = 0;
for (int i = 0; i < s.length; i++)
{
TimeZone t = getTimeZoneInternal(s[i]);
if (t == null || t.getRawOffset() != rawOffset)
s[i] = null;
else
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();
}
for (int i = 0; i < s.length; i++)
if (s[i] != null)
ids[count++] = s[i];
return ids;
}
private static int getAvailableIDs(File d, String prefix, ArrayList list)
{
String[] files = d.list();
int count = files.length;
boolean top = prefix.length() == 0;
list.add (files);
for (int i = 0; i < files.length; i++)
{
if (top
&& (files[i].equals("posix")
|| files[i].equals("right")
|| files[i].endsWith(".tab")
|| aliases0.get(files[i]) != null))
{
files[i] = null;
count--;
continue;
}
File f = new File(d, files[i]);
if (f.isDirectory())
{
count += getAvailableIDs(f, prefix + files[i]
+ File.separatorChar, list) - 1;
files[i] = null;
}
else
files[i] = prefix + files[i];
}
return count;
}
/**
* Gets all available IDs.
* @return An array of all supported IDs.
*/
public static String[] getAvailableIDs()
{
return (String[])
timezones().keySet().toArray(new String[timezones().size()]);
synchronized (TimeZone.class)
{
HashMap h = timezones();
if (zoneinfo_dir == null)
return (String[]) h.keySet().toArray(new String[h.size()]);
if (availableIDs != null)
{
String[] ids = new String[availableIDs.length];
for (int i = 0; i < availableIDs.length; i++)
ids[i] = availableIDs[i];
return ids;
}
File d = new File(zoneinfo_dir);
ArrayList list = new ArrayList(30);
int count = getAvailableIDs(d, "", list) + aliases0.size();
availableIDs = new String[count];
String[] ids = new String[count];
count = 0;
for (int i = 0; i < list.size(); i++)
{
String[] s = (String[]) list.get(i);
for (int j = 0; j < s.length; j++)
if (s[j] != null)
{
availableIDs[count] = s[j];
ids[count++] = s[j];
}
}
Iterator iter = aliases0.entrySet().iterator();
while (iter.hasNext())
{
Map.Entry entry = (Map.Entry) iter.next();
availableIDs[count] = (String) entry.getKey();
ids[count++] = (String) entry.getKey();
}
return ids;
}
}
/**

Binary file not shown.

View file

@ -0,0 +1,70 @@
// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*-
#ifndef __gnu_java_util_ZoneInfo__
#define __gnu_java_util_ZoneInfo__
#pragma interface
#include <java/util/TimeZone.h>
#include <gcj/array.h>
extern "Java"
{
namespace gnu
{
namespace java
{
namespace util
{
class ZoneInfo;
}
}
}
}
class gnu::java::util::ZoneInfo : public ::java::util::TimeZone
{
public:
ZoneInfo(jint, ::java::lang::String *, JArray< jlong > *, ::java::util::SimpleTimeZone *);
virtual jint getOffset(jint, jint, jint, jint, jint, jint);
private:
jlong findTransition(jlong);
public:
virtual jint getOffset(jlong);
virtual jint getRawOffset();
virtual void setRawOffset(jint);
private:
void computeDSTSavings();
public:
virtual jint getDSTSavings();
virtual jboolean useDaylightTime();
virtual jboolean inDaylightTime(::java::util::Date *);
virtual jint hashCode();
virtual jboolean equals(::java::lang::Object *);
virtual jboolean hasSameRules(::java::util::TimeZone *);
virtual ::java::lang::String * toString();
static ::java::util::TimeZone * readTZFile(::java::lang::String *, ::java::lang::String *);
private:
static void skipFully(::java::io::InputStream *, jlong);
static ::java::util::SimpleTimeZone * createLastRule(::java::lang::String *);
static JArray< jint > * getDateParams(::java::lang::String *);
static jint parseTime(::java::lang::String *);
static const jint SECS_SHIFT = 22;
static const jlong OFFSET_MASK = 2097151LL;
static const jint OFFSET_SHIFT = 43;
static const jlong IS_DST = 2097152LL;
jint __attribute__((aligned(__alignof__( ::java::util::TimeZone)))) rawOffset;
jint dstSavings;
jboolean useDaylight;
JArray< jlong > * transitions;
::java::util::SimpleTimeZone * lastRule;
static ::java::util::SimpleTimeZone * gmtZone;
public: // actually package-private
static const jlong serialVersionUID = -3740626706860383657LL;
public:
static ::java::lang::Class class$;
};
#endif // __gnu_java_util_ZoneInfo__

View file

@ -1,5 +1,5 @@
/* System.java -- useful methods to interface with the system
Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006
Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
Free Software Foundation, Inc.
This file is part of GNU Classpath.
@ -318,6 +318,7 @@ public final class System
* <dt>gnu.java.io.encoding_scheme_alias.latin?</dt> <dd>8859_?</dd>
* <dt>gnu.java.io.encoding_scheme_alias.UTF-8</dt> <dd>UTF8</dd>
* <dt>gnu.java.io.encoding_scheme_alias.utf-8</dt> <dd>UTF8</dd>
* <dt>gnu.java.util.zoneinfo.dir</dt> <dd>Root of zoneinfo tree</dd>
* </dl>
*
* @return the system properties, will never be null

View file

@ -40,8 +40,14 @@ public:
virtual jboolean useDaylightTime() = 0;
virtual jboolean inDaylightTime(::java::util::Date *) = 0;
virtual jint getDSTSavings();
private:
static ::java::util::TimeZone * getTimeZoneInternal(::java::lang::String *);
public:
static ::java::util::TimeZone * getTimeZone(::java::lang::String *);
static JArray< ::java::lang::String * > * getAvailableIDs(jint);
private:
static jint getAvailableIDs(::java::io::File *, ::java::lang::String *, ::java::util::ArrayList *);
public:
static JArray< ::java::lang::String * > * getAvailableIDs();
static ::java::util::TimeZone * getDefault();
static void setDefault(::java::util::TimeZone *);
@ -53,6 +59,9 @@ private:
::java::lang::String * __attribute__((aligned(__alignof__( ::java::lang::Object)))) ID;
static ::java::util::TimeZone * defaultZone0;
static const jlong serialVersionUID = 3581463369166924961LL;
static ::java::lang::String * zoneinfo_dir;
static JArray< ::java::lang::String * > * availableIDs;
static ::java::util::HashMap * aliases0;
static ::java::util::HashMap * timezones0;
public:
static ::java::lang::Class class$;

View file

@ -16,8 +16,7 @@ public: // actually package-private
static ::java::util::TimeZone * getDefaultTimeZoneId();
private:
static ::java::lang::String * readTimeZoneFile(::java::lang::String *);
static ::java::lang::String * readtzFile(::java::lang::String *);
static void skipFully(::java::io::InputStream *, jlong);
static ::java::lang::String * readSysconfigClockFile(::java::lang::String *);
static ::java::lang::String * getSystemTimeZoneId();
public:
static ::java::lang::Class class$;

View file

@ -40,9 +40,9 @@ exception statement from your version. */
package java.util;
import gnu.classpath.Configuration;
import gnu.classpath.SystemProperties;
import gnu.java.util.ZoneInfo;
import java.util.TimeZone;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.io.*;
@ -78,9 +78,10 @@ final class VMTimeZone
* The reference implementation which is made for GNU/Posix like
* systems calls <code>System.getenv("TZ")</code>,
* <code>readTimeZoneFile("/etc/timezone")</code>,
* <code>readtzFile("/etc/localtime")</code> and finally
* <code>getSystemTimeZoneId()</code> till a supported TimeZone is
* found through <code>TimeZone.getDefaultTimeZone(String)</code>.
* <code>ZoneInfo.readTZFile((String)null, "/etc/localtime")</code>
* and finally <code>getSystemTimeZoneId()</code> till a supported
* TimeZone is found through
* <code>TimeZone.getDefaultTimeZone(String)</code>.
* If every method fails <code>null</code> is returned (which means
* the TimeZone code will fall back on GMT as default time zone).
* <p>
@ -111,9 +112,51 @@ final class VMTimeZone
// Try to parse /etc/localtime
if (zone == null)
{
tzid = readtzFile("/etc/localtime");
if (tzid != null && !tzid.equals(""))
zone = TimeZone.getDefaultTimeZone(tzid);
zone = ZoneInfo.readTZFile((String) null, "/etc/localtime");
if (zone != null)
{
// Try to find a more suitable ID for the /etc/localtime
// timezone.
// Sometimes /etc/localtime is a symlink to some
// /usr/share/zoneinfo/ file.
String id = null;
try
{
id = new File("/etc/localtime").getCanonicalPath();
if (id != null)
{
String zoneinfo_dir
= SystemProperties.getProperty("gnu.java.util.zoneinfo.dir");
if (zoneinfo_dir != null)
zoneinfo_dir
= new File(zoneinfo_dir
+ File.separatorChar).getCanonicalPath();
if (zoneinfo_dir != null && id.startsWith(zoneinfo_dir))
{
int pos = zoneinfo_dir.length();
while (pos < id.length()
&& id.charAt(pos) == File.separatorChar)
pos++;
if (pos < id.length())
id = id.substring(pos);
else
id = null;
}
else
id = null;
}
}
catch (IOException ioe)
{
id = null;
}
if (id == null)
id = readSysconfigClockFile("/etc/sysconfig/clock");
if (id != null)
zone.setID(id);
}
}
// Try some system specific way
@ -189,466 +232,47 @@ final class VMTimeZone
}
/**
* Tries to read a file as a "standard" tzfile and return a time
* zone id string as expected by <code>getDefaultTimeZone(String)</code>.
* If the file doesn't exist, an IOException occurs or it isn't a tzfile
* that can be parsed null is returned.
* Tries to read the time zone name from a file.
* If the file cannot be read or an IOException occurs null is returned.
* <p>
* The tzfile structure (as also used by glibc) is described in the Olson
* tz database archive as can be found at
* <code>ftp://elsie.nci.nih.gov/pub/</code>.
* <p>
* At least the following platforms support the tzdata file format
* and /etc/localtime (GNU/Linux, Darwin, Solaris and FreeBSD at
* least). Some systems (like Darwin) don't start the file with the
* required magic bytes 'TZif', this implementation can handle
* that).
* The /etc/sysconfig/clock file is not standard, but a lot of systems
* have it. The file is included by shell scripts and the timezone
* name is defined in ZONE variable.
* This routine should grok it with or without quotes:
* ZONE=America/New_York
* or
* ZONE="Europe/London"
*/
private static String readtzFile(String file)
private static String readSysconfigClockFile(String file)
{
File f = new File(file);
if (!f.exists())
return null;
DataInputStream dis = null;
BufferedReader br = null;
try
{
FileInputStream fis = new FileInputStream(f);
FileInputStream fis = new FileInputStream(file);
BufferedInputStream bis = new BufferedInputStream(fis);
dis = new DataInputStream(bis);
br = new BufferedReader(new InputStreamReader(bis));
// Make sure we are reading a tzfile.
byte[] tzif = new byte[5];
dis.readFully(tzif);
int tzif2 = 4;
if (tzif[0] == 'T' && tzif[1] == 'Z'
&& tzif[2] == 'i' && tzif[3] == 'f')
for (String line = br.readLine(); line != null; line = br.readLine())
{
if (tzif[4] >= '2')
tzif2 = 8;
// Reserved bytes
skipFully(dis, 16 - 1);
}
else
// Darwin has tzdata files that don't start with the TZif marker
skipFully(dis, 16 - 5);
String id = null;
int ttisgmtcnt = dis.readInt();
int ttisstdcnt = dis.readInt();
int leapcnt = dis.readInt();
int timecnt = dis.readInt();
int typecnt = dis.readInt();
int charcnt = dis.readInt();
if (tzif2 == 8)
{
skipFully(dis, timecnt * (4 + 1) + typecnt * (4 + 1 + 1) + charcnt
+ leapcnt * (4 + 4) + ttisgmtcnt + ttisstdcnt);
dis.readFully(tzif);
if (tzif[0] != 'T' || tzif[1] != 'Z' || tzif[2] != 'i'
|| tzif[3] != 'f' || tzif[4] < '2')
line = line.trim();
if (line.length() < 8 || !line.startsWith("ZONE="))
continue;
int posstart = 6;
int posend;
if (line.charAt(5) == '"')
posend = line.indexOf('"', 6);
else if (line.charAt(5) == '\'')
posend = line.indexOf('\'', 6);
else
{
posstart = 5;
posend = line.length();
}
if (posend < 0)
return null;
// Reserved bytes
skipFully(dis, 16 - 1);
ttisgmtcnt = dis.readInt();
ttisstdcnt = dis.readInt();
leapcnt = dis.readInt();
timecnt = dis.readInt();
typecnt = dis.readInt();
charcnt = dis.readInt();
return line.substring(posstart, posend);
}
if (typecnt > 0)
{
int seltimecnt = timecnt;
if (seltimecnt > 16)
seltimecnt = 16;
long[] times = new long[seltimecnt];
int[] types = new int[seltimecnt];
// Transition times
skipFully(dis, (timecnt - seltimecnt) * tzif2);
for (int i = 0; i < seltimecnt; i++)
if (tzif2 == 8)
times[i] = dis.readLong();
else
times[i] = (long) dis.readInt();
// Transition types
skipFully(dis, timecnt - seltimecnt);
for (int i = 0; i < seltimecnt; i++)
{
types[i] = dis.readByte();
if (types[i] < 0)
types[i] += 256;
}
// Get std/dst_offset and dst/non-dst time zone names.
int std_abbrind = -1;
int dst_abbrind = -1;
int std_offset = 0;
int dst_offset = 0;
int std_ind = -1;
int dst_ind = -1;
int alternation = 0;
if (seltimecnt >= 4 && types[0] != types[1]
&& types[0] < typecnt && types[1] < typecnt)
{
// Verify only two types are involved
// in the transitions and they alternate.
alternation = 1;
for (int i = 2; i < seltimecnt; i++)
if (types[i] != types[i % 2])
alternation = 0;
}
// If a timezone previously used DST, but no longer does
// (or no longer will in the near future, say 5 years),
// then always pick only the std zone type corresponding
// to latest applicable transition.
if (seltimecnt > 0
&& times[seltimecnt - 1]
< System.currentTimeMillis() / 1000 + 5 * 365 * 86400)
alternation = -1;
for (int i = 0; i < typecnt; i++)
{
// gmtoff
int offset = dis.readInt();
int dst = dis.readByte();
int abbrind = dis.readByte();
if (dst == 0)
{
if (alternation == 0
|| (alternation == 1
&& (i == types[0] || i == types[1]))
|| (alternation == -1 && i == types[seltimecnt - 1]))
{
std_abbrind = abbrind;
std_offset = offset * -1;
std_ind = i;
}
}
else if (alternation >= 0)
{
if (alternation == 0 || i == types[0] || i == types[1])
{
dst_abbrind = abbrind;
dst_offset = offset * -1;
dst_ind = i;
}
}
}
if (std_abbrind >= 0)
{
byte[] names = new byte[charcnt];
dis.readFully(names);
int j = std_abbrind;
while (j < charcnt && names[j] != 0)
j++;
String zonename = new String(names, std_abbrind,
j - std_abbrind, "ASCII");
String dst_zonename;
if (dst_abbrind >= 0)
{
j = dst_abbrind;
while (j < charcnt && names[j] != 0)
j++;
dst_zonename = new String(names, dst_abbrind,
j - dst_abbrind, "ASCII");
}
else
dst_zonename = "";
String[] change_spec = { null, null };
if (dst_abbrind >= 0 && alternation > 0)
{
// Guess rules for the std->dst and dst->std transitions
// from the transition times since Epoch.
// tzdata actually uses only 3 forms of rules:
// fixed date within a month, e.g. change on April, 5th
// 1st weekday on or after Nth: change on Sun>=15 in April
// last weekday in a month: change on lastSun in April
GregorianCalendar cal
= new GregorianCalendar (TimeZone.getTimeZone("GMT"));
int[] values = new int[2 * 11];
int i;
for (i = seltimecnt - 1; i >= 0; i--)
{
int base = (i % 2) * 11;
int offset = types[i] == dst_ind ? std_offset : dst_offset;
cal.setTimeInMillis((times[i] - offset) * 1000);
if (i >= seltimecnt - 2)
{
values[base + 0] = cal.get(Calendar.YEAR);
values[base + 1] = cal.get(Calendar.MONTH);
values[base + 2] = cal.get(Calendar.DAY_OF_MONTH);
values[base + 3]
= cal.getActualMaximum(Calendar.DAY_OF_MONTH);
values[base + 4] = cal.get(Calendar.DAY_OF_WEEK);
values[base + 5] = cal.get(Calendar.HOUR_OF_DAY);
values[base + 6] = cal.get(Calendar.MINUTE);
values[base + 7] = cal.get(Calendar.SECOND);
values[base + 8] = values[base + 2]; // Range start
values[base + 9] = values[base + 2]; // Range end
values[base + 10] = 0; // Determined type
}
else
{
int year = cal.get(Calendar.YEAR);
int month = cal.get(Calendar.MONTH);
int day_of_month = cal.get(Calendar.DAY_OF_MONTH);
int month_days
= cal.getActualMaximum(Calendar.DAY_OF_MONTH);
int day_of_week = cal.get(Calendar.DAY_OF_WEEK);
int hour = cal.get(Calendar.HOUR_OF_DAY);
int minute = cal.get(Calendar.MINUTE);
int second = cal.get(Calendar.SECOND);
if (year != values[base + 0] - 1
|| month != values[base + 1]
|| hour != values[base + 5]
|| minute != values[base + 6]
|| second != values[base + 7])
break;
if (day_of_week == values[base + 4])
{
// Either a Sun>=8 or lastSun rule.
if (day_of_month < values[base + 8])
values[base + 8] = day_of_month;
if (day_of_month > values[base + 9])
values[base + 9] = day_of_month;
if (values[base + 10] < 0)
break;
if (values[base + 10] == 0)
{
values[base + 10] = 1;
// If day of month > 28, this is
// certainly lastSun rule.
if (values[base + 2] > 28)
values[base + 2] = 3;
// If day of month isn't in the last
// week, it can't be lastSun rule.
else if (values[base + 2]
<= values[base + 3] - 7)
values[base + 3] = 2;
}
if (values[base + 10] == 1)
{
// If day of month is > 28, this is
// certainly lastSun rule.
if (day_of_month > 28)
values[base + 10] = 3;
// If day of month isn't in the last
// week, it can't be lastSun rule.
else if (day_of_month <= month_days - 7)
values[base + 10] = 2;
}
else if ((values[base + 10] == 2
&& day_of_month > 28)
|| (values[base + 10] == 3
&& day_of_month
<= month_days - 7))
break;
}
else
{
// Must be fixed day in month rule.
if (day_of_month != values[base + 2]
|| values[base + 10] > 0)
break;
values[base + 4] = day_of_week;
values[base + 10] = -1;
}
values[base + 0] -= 1;
}
}
if (i < 0)
{
for (i = 0; i < 2; i++)
{
int base = 11 * i;
if (values[base + 10] == 0)
continue;
if (values[base + 10] == -1)
{
int[] dayCount
= { 0, 31, 59, 90, 120, 151,
181, 212, 243, 273, 304, 334 };
int d = dayCount[values[base + 1]
- Calendar.JANUARY];
d += values[base + 2];
change_spec[i] = ",J" + Integer.toString(d);
}
else if (values[base + 10] == 2)
{
// If we haven't seen all days of the week,
// we can't be sure what the rule really is.
if (values[base + 8] + 6 != values[base + 9])
continue;
// FIXME: Sun >= 5 is representable in
// SimpleTimeZone, but not in POSIX TZ env
// strings. Should we change readtzFile
// to actually return a SimpleTimeZone
// rather than POSIX TZ string?
if ((values[base + 8] % 7) != 1)
continue;
int d;
d = values[base + 1] - Calendar.JANUARY + 1;
change_spec[i] = ",M" + Integer.toString(d);
d = (values[base + 8] + 6) / 7;
change_spec[i] += "." + Integer.toString(d);
d = values[base + 4] - Calendar.SUNDAY;
change_spec[i] += "." + Integer.toString(d);
}
else
{
// If we don't know whether this is lastSun or
// Sun >= 22 rule. That can be either because
// there was insufficient number of
// transitions, or February, where it is quite
// probable we haven't seen any 29th dates.
// For February, assume lastSun rule, otherwise
// punt.
if (values[base + 10] == 1
&& values[base + 1] != Calendar.FEBRUARY)
continue;
int d;
d = values[base + 1] - Calendar.JANUARY + 1;
change_spec[i] = ",M" + Integer.toString(d);
d = values[base + 4] - Calendar.SUNDAY;
change_spec[i] += ".5." + Integer.toString(d);
}
// Don't add time specification if time is
// 02:00:00.
if (values[base + 5] != 2
|| values[base + 6] != 0
|| values[base + 7] != 0)
{
int d = values[base + 5];
change_spec[i] += "/" + Integer.toString(d);
if (values[base + 6] != 0
|| values[base + 7] != 0)
{
d = values[base + 6];
if (d < 10)
change_spec[i]
+= ":0" + Integer.toString(d);
else
change_spec[i]
+= ":" + Integer.toString(d);
d = values[base + 7];
if (d >= 10)
change_spec[i]
+= ":" + Integer.toString(d);
else if (d > 0)
change_spec[i]
+= ":0" + Integer.toString(d);
}
}
}
if (types[0] == std_ind)
{
String tmp = change_spec[0];
change_spec[0] = change_spec[1];
change_spec[1] = tmp;
}
}
}
// Only use gmt offset when necessary.
// Also special case GMT+/- timezones.
String offset_string, dst_offset_string = "";
if (dst_abbrind < 0
&& (std_offset == 0
|| zonename.startsWith("GMT+")
|| zonename.startsWith("GMT-")))
offset_string = "";
else
{
offset_string = Integer.toString(std_offset / 3600);
int seconds = std_offset % 3600;
if (seconds != 0)
{
if (seconds < 0)
seconds *= -1;
if (seconds < 600)
offset_string
+= ":0" + Integer.toString(seconds / 60);
else
offset_string
+= ":" + Integer.toString(seconds / 60);
seconds = seconds % 60;
if (seconds >= 10)
offset_string
+= ":" + Integer.toString(seconds);
else if (seconds > 0)
offset_string
+= ":0" + Integer.toString(seconds);
}
if (dst_abbrind >= 0
&& dst_offset != std_offset - 3600)
{
dst_offset_string
= Integer.toString(dst_offset / 3600);
seconds = dst_offset % 3600;
if (seconds != 0)
{
if (seconds < 0)
seconds *= -1;
if (seconds < 600)
dst_offset_string
+= ":0" + Integer.toString(seconds / 60);
else
dst_offset_string
+= ":" + Integer.toString(seconds / 60);
seconds = seconds % 60;
if (seconds >= 10)
dst_offset_string
+= ":" + Integer.toString(seconds);
else if (seconds > 0)
dst_offset_string
+= ":0" + Integer.toString(seconds);
}
}
}
if (dst_abbrind < 0)
id = zonename + offset_string;
else if (change_spec[0] != null && change_spec[1] != null)
id = zonename + offset_string + dst_zonename
+ dst_offset_string + change_spec[0] + change_spec[1];
}
else if (tzif2 == 8)
skipFully(dis, charcnt);
}
else if (tzif2 == 8)
skipFully(dis, timecnt * (8 + 1) + typecnt * (4 + 1 + 1) + charcnt);
if (tzif2 == 8)
{
// Skip over the rest of 64-bit data
skipFully(dis, leapcnt * (8 + 4) + ttisgmtcnt + ttisstdcnt);
if (dis.readByte() == '\n')
{
String posixtz = dis.readLine();
if (posixtz.length() > 0)
id = posixtz;
}
}
return id;
return null;
}
catch (IOException ioe)
{
@ -659,31 +283,15 @@ final class VMTimeZone
{
try
{
if (dis != null)
dis.close();
if (br != null)
br.close();
}
catch(IOException ioe)
catch (IOException ioe)
{
// Error while close, nothing we can do.
}
}
}
/**
* Skips the requested number of bytes in the given InputStream.
* Throws EOFException if not enough bytes could be skipped.
* Negative numbers of bytes to skip are ignored.
*/
private static void skipFully(InputStream is, long l) throws IOException
{
while (l > 0)
{
long k = is.skip(l);
if (k <= 0)
throw new EOFException();
l -= k;
}
}
/**
* Tries to get the system time zone id through native code.

View file

@ -139,6 +139,10 @@ _Jv_platform_initProperties (java::util::Properties* newprops)
if (! tmpdir)
tmpdir = "/tmp";
SET ("java.io.tmpdir", tmpdir);
const char *zoneinfodir = ::getenv("TZDATA");
if (! zoneinfodir)
zoneinfodir = "/usr/share/zoneinfo";
SET ("gnu.java.util.zoneinfo.dir", zoneinfodir);
}
static inline void

View file

@ -2110,7 +2110,8 @@ gnu/java/text.list: $(gnu_java_text_source_files)
gnu_java_util_source_files = \
classpath/gnu/java/util/DoubleEnumeration.java \
classpath/gnu/java/util/EmptyEnumeration.java \
classpath/gnu/java/util/WeakIdentityHashMap.java
classpath/gnu/java/util/WeakIdentityHashMap.java \
classpath/gnu/java/util/ZoneInfo.java
gnu_java_util_header_files = $(patsubst classpath/%,%,$(patsubst %.java,%.h,$(gnu_java_util_source_files)))