Commit 42348101 by Mark Wielaard Committed by Mark Wielaard

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

2004-08-26  Mark Wielaard  <mark@klomp.org>

       Fixes PR libgcj/17002:
       * java/util/TimeZone.java (defaultZone): Try a couple of ways to get
       a TimeZoneId string and then try to convert that to a TimeZone with
       getDefaultSystemTimeZone(String).
       (timezones0): Changed type from Hashtable to HashMap.
       (timezones): Create HashMap, not Hashtable.
       (getDefaultTimeZone): New method, rewritten from CNI version.
       (readTimeZoneFile): New method.
       (readtzFile): Likewise.
       (skipFully): Likewise.
       * java/util/natTimeZone.cc (getSystemTimeZone): Renamed to
       getDefaultTimeZoneId and rewritten.
       (getDefaultTimeZoneId): Rewritten in java.

From-SVN: r86623
parent 20edd06b
2004-08-26 Mark Wielaard <mark@klomp.org>
Fixes PR libgcj/17002:
* java/util/TimeZone.java (defaultZone): Try a couple of ways to get
a TimeZoneId string and then try to convert that to a TimeZone with
getDefaultSystemTimeZone(String).
(timezones0): Changed type from Hashtable to HashMap.
(timezones): Create HashMap, not Hashtable.
(getDefaultTimeZone): New method, rewritten from CNI version.
(readTimeZoneFile): New method.
(readtzFile): Likewise.
(skipFully): Likewise.
* java/util/natTimeZone.cc (getSystemTimeZone): Renamed to
getDefaultTimeZoneId and rewritten.
(getDefaultTimeZoneId): Rewritten in java.
2004-08-25 David Daney <daney@avtrex.com> 2004-08-25 David Daney <daney@avtrex.com>
* Makefile.am (AM_GCJFLAGS): Add LIBGCJ_JAVAFLAGS. * Makefile.am (AM_GCJFLAGS): Add LIBGCJ_JAVAFLAGS.
......
...@@ -40,6 +40,9 @@ exception statement from your version. */ ...@@ -40,6 +40,9 @@ exception statement from your version. */
package java.util; package java.util;
import gnu.classpath.Configuration; import gnu.classpath.Configuration;
import java.io.*;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.text.DateFormatSymbols; import java.text.DateFormatSymbols;
/** /**
...@@ -83,44 +86,99 @@ public abstract class TimeZone implements java.io.Serializable, Cloneable ...@@ -83,44 +86,99 @@ public abstract class TimeZone implements java.io.Serializable, Cloneable
* The default time zone, as returned by getDefault. * The default time zone, as returned by getDefault.
*/ */
private static TimeZone defaultZone0; private static TimeZone defaultZone0;
/* initialize this static field lazily to overhead if
* it is not needed: /**
* Tries to get the default TimeZone for this system if not already
* set. It will call <code>getDefaultTimeZone(String)</code> with
* the result of
* <code>System.getProperty("user.timezone")</code>,
* <code>System.getenv("TZ")</code>,
* <code>readTimeZoneFile("/etc/timezone")</code>,
* <code>readtzFile("/etc/localtime")</code> and
* <code>getDefaultTimeZoneId()</code>
* till a supported TimeZone is found.
* If every method fails GMT is returned.
*/ */
private static synchronized TimeZone defaultZone() { private static synchronized TimeZone defaultZone()
{
/* Look up default timezone */ /* Look up default timezone */
if (defaultZone0 == null) if (defaultZone0 == null)
{ {
if (Configuration.INIT_LOAD_LIBRARY) defaultZone0 = (TimeZone) AccessController.doPrivileged
{ (new PrivilegedAction()
System.loadLibrary("javautil"); {
} public Object run()
String tzid = System.getProperty("user.timezone"); {
if (Configuration.INIT_LOAD_LIBRARY)
if (tzid == null) {
tzid = getDefaultTimeZoneId(); System.loadLibrary("javautil");
}
if (tzid == null)
tzid = "GMT"; TimeZone zone = null;
defaultZone0 = getTimeZone(tzid); // Prefer System property user.timezone.
String tzid = System.getProperty("user.timezone");
if (tzid != null && !tzid.equals(""))
zone = getDefaultTimeZone(tzid);
// See if TZ environment variable is set and accessible.
if (zone == null)
{
tzid = System.getenv("TZ");
if (tzid != null && !tzid.equals(""))
zone = getDefaultTimeZone(tzid);
}
// Try to parse /etc/timezone.
if (zone == null)
{
tzid = readTimeZoneFile("/etc/timezone");
if (tzid != null && !tzid.equals(""))
zone = getDefaultTimeZone(tzid);
}
// Try to parse /etc/localtime
if (zone == null)
{
tzid = readtzFile("/etc/localtime");
if (tzid != null && !tzid.equals(""))
zone = getDefaultTimeZone(tzid);
}
// Try some system specific way
if (zone == null)
{
tzid = getDefaultTimeZoneId();
if (tzid != null && !tzid.equals(""))
zone = getDefaultTimeZone(tzid);
}
// Fall back on GMT.
if (zone == null)
zone = (TimeZone) timezones().get("GMT");
return zone;
}
});
} }
return defaultZone0; return defaultZone0;
} }
private static final long serialVersionUID = 3581463369166924961L; private static final long serialVersionUID = 3581463369166924961L;
/** /**
* Hashtable for timezones by ID. * HashMap for timezones by ID.
*/ */
private static Hashtable timezones0; private static HashMap timezones0;
/* initialize this static field lazily to overhead if /* initialize this static field lazily to overhead if
* it is not needed: * it is not needed:
*/ */
private static synchronized Hashtable timezones() { private static synchronized HashMap timezones()
if (timezones0==null) {
if (timezones0 == null)
{ {
Hashtable timezones = new Hashtable(); HashMap timezones = new HashMap();
timezones0 = timezones; timezones0 = timezones;
TimeZone tz; TimeZone tz;
...@@ -784,19 +842,363 @@ public abstract class TimeZone implements java.io.Serializable, Cloneable ...@@ -784,19 +842,363 @@ public abstract class TimeZone implements java.io.Serializable, Cloneable
return timezones0; return timezones0;
} }
/**
/* This method returns us a time zone id string which is in the * This method returns a time zone id string which is in the form
form <standard zone name><GMT offset><daylight time zone name>. * (standard zone name) or (standard zone name)(GMT offset) or
The GMT offset is in seconds, except where it is evenly divisible * (standard zone name)(GMT offset)(daylight time zone name). The
by 3600, then it is in hours. If the zone does not observe * GMT offset can be in seconds, or where it is evenly divisible by
daylight time, then the daylight zone name is omitted. Examples: * 3600, then it can be in hours. The offset must be the time to
in Chicago, the timezone would be CST6CDT. In Indianapolis * add to the local time to get GMT. If a offset is given and the
(which does not have Daylight Savings Time) the string would * time zone observes daylight saving then the (daylight time zone
be EST5 * name) must also be given (otherwise it is assumed the time zone
* does not observe any daylight savings).
* <p>
* The result of this method is given to getDefaultTimeZone(String)
* which tries to map the time zone id to a known TimeZone. See
* that method on how the returned String is mapped to a real
* TimeZone object.
*/ */
private static native String getDefaultTimeZoneId(); private static native String getDefaultTimeZoneId();
/** /**
* Tries to read the time zone name from a file. Only the first
* consecutive letters, digits, slashes, dashes and underscores are
* read from the file. If the file cannot be read or an IOException
* occurs null is returned.
* <p>
* The /etc/timezone file is not standard, but a lot of systems have
* it. If it exist the first line always contains a string
* describing the timezone of the host of domain. Some systems
* contain a /etc/TIMEZONE file which is used to set the TZ
* environment variable (which is checked before /etc/timezone is
* read).
*/
private static String readTimeZoneFile(String file)
{
File f = new File(file);
if (!f.exists())
return null;
InputStreamReader isr = null;
try
{
FileInputStream fis = new FileInputStream(f);
BufferedInputStream bis = new BufferedInputStream(fis);
isr = new InputStreamReader(bis);
StringBuffer sb = new StringBuffer();
int i = isr.read();
while (i != -1)
{
char c = (char) i;
if (Character.isLetter(c) || Character.isDigit(c)
|| c == '/' || c == '-' || c == '_')
{
sb.append(c);
i = isr.read();
}
else
break;
}
return sb.toString();
}
catch (IOException ioe)
{
// Parse error, not a proper tzfile.
return null;
}
finally
{
try
{
if (isr != null)
isr.close();
}
catch (IOException ioe)
{
// Error while close, nothing we can do.
}
}
}
/**
* 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.
* <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).
*/
private static String readtzFile(String file)
{
File f = new File(file);
if (!f.exists())
return null;
DataInputStream dis = null;
try
{
FileInputStream fis = new FileInputStream(f);
BufferedInputStream bis = new BufferedInputStream(fis);
dis = new DataInputStream(bis);
// Make sure we are reading a tzfile.
byte[] tzif = new byte[4];
dis.readFully(tzif);
if (tzif[0] == 'T' && tzif[1] == 'Z'
&& tzif[2] == 'i' && tzif[3] == 'f')
// Reserved bytes, ttisgmtcnt, ttisstdcnt and leapcnt
skipFully(dis, 16 + 3 * 4);
else
// Darwin has tzdata files that don't start with the TZif marker
skipFully(dis, 16 + 3 * 4 - 4);
int timecnt = dis.readInt();
int typecnt = dis.readInt();
if (typecnt > 0)
{
int charcnt = dis.readInt();
// Transition times plus indexed transition times.
skipFully(dis, timecnt * (4 + 1));
// Get last gmt_offset and dst/non-dst time zone names.
int abbrind = -1;
int dst_abbrind = -1;
int gmt_offset = 0;
while (typecnt-- > 0)
{
// gmtoff
int offset = dis.readInt();
int dst = dis.readByte();
if (dst == 0)
{
abbrind = dis.readByte();
gmt_offset = offset;
}
else
dst_abbrind = dis.readByte();
}
// gmt_offset is the offset you must add to UTC/GMT to
// get the local time, we need the offset to add to
// the local time to get UTC/GMT.
gmt_offset *= -1;
// Turn into hours if possible.
if (gmt_offset % 3600 == 0)
gmt_offset /= 3600;
if (abbrind >= 0)
{
byte[] names = new byte[charcnt];
dis.readFully(names);
int j = abbrind;
while (j < charcnt && names[j] != 0)
j++;
String zonename = new String(names, abbrind, j - 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 = "";
// Only use gmt offset when necessary.
// Also special case GMT+/- timezones.
String offset_string;
if ("".equals(dst_zonename)
&& (gmt_offset == 0
|| zonename.startsWith("GMT+")
|| zonename.startsWith("GMT-")))
offset_string = "";
else
offset_string = Integer.toString(gmt_offset);
String id = zonename + offset_string + dst_zonename;
return id;
}
}
// Something didn't match while reading the file.
return null;
}
catch (IOException ioe)
{
// Parse error, not a proper tzfile.
return null;
}
finally
{
try
{
if (dis != null)
dis.close();
}
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;
}
}
/**
* Maps a time zone name (with optional GMT offset and daylight time
* zone name) to one of the known time zones. This method called
* with the result of <code>System.getProperty("user.timezone")</code>
* or <code>getDefaultTimeZoneId()</code>. Note that giving one of
* the standard tz data names from ftp://elsie.nci.nih.gov/pub/ is
* preferred. The time zone name can be given as follows:
* <code>(standard zone name)[(GMT offset)[(daylight time zone name)]]</code>
* <p>
* If only a (standard zone name) is given (no numbers in the
* String) then it gets mapped directly to the TimeZone with that
* name, if that fails null is returned.
* <p>
* A GMT offset is the offset to add to the local time to get GMT.
* If a (GMT offset) is included (either in seconds or hours) then
* an attempt is made to find a TimeZone name matching both the name
* and the offset (that doesn't observe daylight time, if the
* timezone observes daylight time then you must include a daylight
* time zone name after the offset), if that fails then a TimeZone
* with the given GMT offset is returned (whether or not the
* TimeZone observes daylight time is ignored), if that also fails
* the GMT TimeZone is returned.
* <p>
* If the String ends with (GMT offset)(daylight time zone name)
* then an attempt is made to find a TimeZone with the given name and
* GMT offset that also observes (the daylight time zone name is not
* currently used in any other way), if that fails a TimeZone with
* the given GMT offset that observes daylight time is returned, if
* that also fails the GMT TimeZone is returned.
* <p>
* Examples: In Chicago, the time zone id could be "CST6CDT", but
* the preferred name would be "America/Chicago". In Indianapolis
* (which does not have Daylight Savings Time) the string could be
* "EST5", but the preferred name would be "America/Indianapolis".
* The standard time zone name for The Netherlands is "Europe/Amsterdam",
* but can also be given as "CET-1CEST".
*/
private static TimeZone getDefaultTimeZone(String sysTimeZoneId)
{
// First find start of GMT offset info and any Daylight zone name.
int startGMToffset = 0;
int sysTimeZoneIdLength = sysTimeZoneId.length();
for (int i = 0; i < sysTimeZoneIdLength && startGMToffset == 0; i++)
{
char c = sysTimeZoneId.charAt(i);
if (c == '+' || c == '-' || Character.isDigit(c))
startGMToffset = i;
}
String tzBasename;
if (startGMToffset == 0)
tzBasename = sysTimeZoneId;
else
tzBasename = sysTimeZoneId.substring (0, startGMToffset);
int startDaylightZoneName = 0;
for (int i = sysTimeZoneIdLength - 1;
i >= 0 && !Character.isDigit(sysTimeZoneId.charAt(i)); --i)
startDaylightZoneName = i;
boolean useDaylightTime = startDaylightZoneName > 0;
// Integer.parseInt() doesn't handle leading +.
if (sysTimeZoneId.charAt(startGMToffset) == '+')
startGMToffset++;
int gmtOffset = 0;
if (startGMToffset > 0)
{
gmtOffset = Integer.parseInt
(startDaylightZoneName == 0
? sysTimeZoneId.substring(startGMToffset)
: sysTimeZoneId.substring(startGMToffset,
startDaylightZoneName));
// Offset could be in hours or seconds. Convert to millis.
// The offset is given as the time to add to local time to get GMT
// we need the time to add to GMT to get localtime.
if (gmtOffset < 24)
gmtOffset *= 60 * 60;
gmtOffset *= -1000;
}
// Try to be optimistic and get the timezone that matches the base name.
// If we only have the base name then just accept this timezone.
// Otherwise check the gmtOffset and day light attributes.
TimeZone tz = (TimeZone) timezones().get(tzBasename);
if (tz != null
&& (tzBasename == sysTimeZoneId
|| (tz.getRawOffset() == gmtOffset
&& tz.useDaylightTime() == useDaylightTime)))
return tz;
// Maybe there is one with the daylight zone name?
if (useDaylightTime)
{
String daylightZoneName;
daylightZoneName = sysTimeZoneId.substring(startDaylightZoneName);
if (!daylightZoneName.equals(tzBasename))
{
tz = (TimeZone) timezones().get(tzBasename);
if (tz != null
&& tz.getRawOffset() == gmtOffset
&& tz.useDaylightTime())
return tz;
}
}
// If no match, see if a valid timezone has similar attributes as this
// and then use it instead. We take the first one that looks OKish.
if (startGMToffset > 0)
{
String[] ids = getAvailableIDs(gmtOffset);
for (int i = 0; i < ids.length; i++)
{
tz = (TimeZone) timezones().get(ids[i]);
if (tz.useDaylightTime() == useDaylightTime)
return tz;
}
}
return null;
}
/**
* Gets the time zone offset, for current date, modified in case of * 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 * daylight savings. This is the offset to add to UTC to get the local
* time. * time.
...@@ -1140,16 +1542,18 @@ public abstract class TimeZone implements java.io.Serializable, Cloneable ...@@ -1140,16 +1542,18 @@ public abstract class TimeZone implements java.io.Serializable, Cloneable
/** /**
* Returns the time zone under which the host is running. This * Returns the time zone under which the host is running. This
* can be changed with setDefault. * can be changed with setDefault.
* @return the time zone for this host. *
* @return A clone of the current default time zone for this host.
* @see #setDefault * @see #setDefault
*/ */
public static TimeZone getDefault() public static TimeZone getDefault()
{ {
return defaultZone(); return (TimeZone) defaultZone().clone();
} }
public static void setDefault(TimeZone zone) public static void setDefault(TimeZone zone)
{ {
// Hmmmm. No Security checks?
defaultZone0 = zone; defaultZone0 = zone;
} }
......
// natTimeZone.cc -- Native side of TimeZone class. // natTimeZone.cc -- Native side of TimeZone class.
/* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Free Software Foundation /* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004
Free Software Foundation
This file is part of libgcj. This file is part of libgcj.
...@@ -33,53 +34,105 @@ details. */ ...@@ -33,53 +34,105 @@ details. */
#include <string.h> #include <string.h>
/* /**
* This method returns a time zone string that is used by init_properties * This method returns a time zone id string which is in the form
* to set the default timezone property 'user.timezone'. That value is * (standard zone name) or (standard zone name)(GMT offset) or
* used by default as a key into the timezone table used by the * (standard zone name)(GMT offset)(daylight time zone name). The
* java::util::TimeZone class. * GMT offset can be in seconds, or where it is evenly divisible by
* 3600, then it can be in hours. The offset must be the time to
* add to the local time to get GMT. If a offset is given and the
* time zone observes daylight saving then the (daylight time zone
* name) must also be given (otherwise it is assumed the time zone
* does not observe any daylight savings).
* <p>
* The result of this method is given to getDefaultTimeZone(String)
* which tries to map the time zone id to a known TimeZone. See
* that method on how the returned String is mapped to a real
* TimeZone object.
*/ */
static jstring jstring
getSystemTimeZone (void) java::util::TimeZone::getDefaultTimeZoneId ()
{ {
struct tm *tim; struct tm tim;
#ifndef HAVE_LOCALTIME_R
struct tm *lt_tim;
#endif
#ifdef HAVE_TM_ZONE
int month;
#endif
time_t current_time; time_t current_time;
long tzoffset; long tzoffset;
const char *tz1, *tz2; const char *tz1, *tz2;
char *tzid; char *tzid;
current_time = time(0); time(&current_time);
#ifdef HAVE_LOCALTIME_R
localtime_r(&current_time, &tim);
#else
/* Fall back on non-thread safe localtime. */
lt_tim = localtime(&current_time);
memcpy(&tim, lt_tim, sizeof (struct tm));
#endif
mktime(&tim);
#ifdef HAVE_TM_ZONE
/* We will cycle through the months to make sure we hit dst. */
month = tim.tm_mon;
tz1 = tz2 = NULL;
while (tz1 == NULL || tz2 == NULL)
{
if (tim.tm_isdst > 0)
tz2 = tim.tm_zone;
else if (tz1 == NULL)
{
tz1 = tim.tm_zone;
month = tim.tm_mon;
}
if (tz1 == NULL || tz2 == NULL)
{
tim.tm_mon++;
tim.tm_mon %= 12;
}
if (tim.tm_mon == month && tz2 == NULL)
tz2 = "";
else
mktime(&tim);
}
/* We want to make sure the tm struct we use later on is not dst. */
tim.tm_mon = month;
mktime(&tim);
#elif defined (HAVE_TZNAME)
/* If dst is never used, tzname[1] is the empty string. */
tzset();
tz1 = tzname[0];
tz2 = tzname[1];
#else
/* Some targets have no concept of timezones. Assume GMT without dst. */
tz1 = "GMT";
tz2 = "";
#endif
mktime(tim = localtime(&current_time));
#ifdef STRUCT_TM_HAS_GMTOFF #ifdef STRUCT_TM_HAS_GMTOFF
// tm_gmtoff is secs EAST of UTC. /* tm_gmtoff is the number of seconds that you must add to GMT to get
tzoffset = -(tim->tm_gmtoff) + tim->tm_isdst * 3600L; local time, we need the number of seconds to add to the local time
to get GMT. */
tzoffset = -1L * tim.tm_gmtoff;
#elif HAVE_UNDERSCORE_TIMEZONE #elif HAVE_UNDERSCORE_TIMEZONE
tzoffset = _timezone; tzoffset = _timezone;
#elif HAVE_TIMEZONE #elif HAVE_TIMEZONE
// timezone is secs WEST of UTC. /* timezone is secs WEST of UTC. */
tzoffset = timezone; tzoffset = timezone;
#else #else
// FIXME: there must be another global if neither tm_gmtoff nor timezone /* FIXME: there must be another global if neither tm_gmtoff nor timezone
// is available, esp. if tzname is valid. is available, esp. if tzname is valid.
// Richard Earnshaw <rearnsha@arm.com> has suggested using difftime to Richard Earnshaw <rearnsha@arm.com> has suggested using difftime to
// calculate between gmtime and localtime (and accounting for possible calculate between gmtime and localtime (and accounting for possible
// daylight savings time) as an alternative. daylight savings time) as an alternative. */
tzoffset = 0L; tzoffset = 0L;
#endif #endif
#ifdef HAVE_TM_ZONE
tz1 = tim->tm_zone;
tz2 = "";
#elif defined (HAVE_TZNAME)
tz1 = tzname[0];
tz2 = strcmp (tzname[0], tzname[1]) ? tzname[1] : "";
#else
// Some targets have no concept of timezones.
tz1 = "???";
tz2 = tz1;
#endif
if ((tzoffset % 3600) == 0) if ((tzoffset % 3600) == 0)
tzoffset = tzoffset / 3600; tzoffset = tzoffset / 3600;
...@@ -90,81 +143,3 @@ getSystemTimeZone (void) ...@@ -90,81 +143,3 @@ getSystemTimeZone (void)
return retval; return retval;
} }
// Get the System Timezone as reported by the OS. It should be in
// the form PST8PDT so we'll need to parse it and check that it's valid.
// FIXME: Using the code from Classpath for generating the System
// Timezone IMO is suboptimal because it ignores whether the rules for
// DST match up.
jstring
java::util::TimeZone::getDefaultTimeZoneId ()
{
jstring sysTimeZoneId = getSystemTimeZone ();
using namespace java::lang;
// Check if this is a valid timezone. Make sure the IDs match
// since getTimeZone returns GMT if no match is found.
TimeZone *tz = TimeZone::getTimeZone (sysTimeZoneId);
if (tz->getID ()->equals (sysTimeZoneId))
return sysTimeZoneId;
// Check if the base part of sysTimeZoneId is a valid timezone that
// matches with daylight usage and rawOffset. Make sure the IDs match
// since getTimeZone returns GMT if no match is found.
// First find start of GMT offset info and any Daylight zone name.
int startGMToffset = 0;
int sysTimeZoneIdLength = sysTimeZoneId->length();
for (int i = 0; i < sysTimeZoneIdLength && startGMToffset == 0; i++)
{
if (Character::isDigit (sysTimeZoneId->charAt (i)))
startGMToffset = i;
}
int startDaylightZoneName = 0;
jboolean usesDaylight = false;
for (int i = sysTimeZoneIdLength - 1;
i >= 0 && !Character::isDigit (sysTimeZoneId->charAt (i)); --i)
{
startDaylightZoneName = i;
}
if (startDaylightZoneName > 0)
usesDaylight = true;
int GMToffset
= Integer::parseInt (startDaylightZoneName == 0 ?
sysTimeZoneId->substring (startGMToffset) :
sysTimeZoneId->substring (startGMToffset,
startDaylightZoneName));
// Offset could be in hours or seconds. Convert to millis.
if (GMToffset < 24)
GMToffset *= 60 * 60;
GMToffset *= -1000;
jstring tzBasename = sysTimeZoneId->substring (0, startGMToffset);
tz = TimeZone::getTimeZone (tzBasename);
if (tz->getID ()->equals (tzBasename) && tz->getRawOffset () == GMToffset)
{
jboolean tzUsesDaylight = tz->useDaylightTime ();
if (usesDaylight && tzUsesDaylight || !usesDaylight && !tzUsesDaylight)
return tzBasename;
}
// If no match, see if a valid timezone has the same attributes as this
// and then use it instead.
jstringArray IDs = TimeZone::getAvailableIDs (GMToffset);
jstring *elts = elements (IDs);
for (int i = 0; i < IDs->length; ++i)
{
// FIXME: The daylight savings rules may not match the rules
// for the desired zone.
jboolean IDusesDaylight =
TimeZone::getTimeZone (elts[i])->useDaylightTime ();
if (usesDaylight && IDusesDaylight || !usesDaylight && !IDusesDaylight)
return elts[i];
}
// If all else fails, return null.
return NULL;
}
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