diff options
author | jakub <jakub@138bc75d-0d04-0410-961f-82ee72b054a4> | 2007-02-22 16:04:55 +0000 |
---|---|---|
committer | jakub <jakub@138bc75d-0d04-0410-961f-82ee72b054a4> | 2007-02-22 16:04:55 +0000 |
commit | 94d43e7046ee9257b0e6684f41783b9f947c59d9 (patch) | |
tree | b6cca022867a508330c4917198eb1491fc030faa /libjava/java/util/VMTimeZone.java | |
parent | 3ab1d71055c182b3bd71a63ee47905eb700f1745 (diff) | |
download | gcc-94d43e7046ee9257b0e6684f41783b9f947c59d9.tar.gz |
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.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@122229 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'libjava/java/util/VMTimeZone.java')
-rw-r--r-- | libjava/java/util/VMTimeZone.java | 560 |
1 files changed, 84 insertions, 476 deletions
diff --git a/libjava/java/util/VMTimeZone.java b/libjava/java/util/VMTimeZone.java index 27bab939166..992ecaf28a8 100644 --- a/libjava/java/util/VMTimeZone.java +++ b/libjava/java/util/VMTimeZone.java @@ -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); - - // 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') - { - 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') - 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(); - } - 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 = ""; + br = new BufferedReader(new InputStreamReader(bis)); - 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) + for (String line = br.readLine(); line != null; line = br.readLine()) { - // Skip over the rest of 64-bit data - skipFully(dis, leapcnt * (8 + 4) + ttisgmtcnt + ttisstdcnt); - if (dis.readByte() == '\n') + 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 { - String posixtz = dis.readLine(); - if (posixtz.length() > 0) - id = posixtz; + posstart = 5; + posend = line.length(); } + if (posend < 0) + return null; + return line.substring(posstart, posend); } - - 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. |