deep-c-rsc/JCGO/goclsp/vm/java/util/VMTimeZone.java
2021-07-16 17:12:20 -05:00

465 lines
13 KiB
Java

/*
* @(#) $(JCGO)/goclsp/vm/java/util/VMTimeZone.java --
* VM specific methods for getting system timezone id.
**
* Project: JCGO (http://www.ivmaisoft.com/jcgo/)
* Copyright (C) 2001-2009 Ivan Maidanski <ivmai@ivmaisoft.com>
* All rights reserved.
**
* Class specification origin: GNU Classpath v0.93 vm/reference
*/
/*
* This 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.
**
* This software 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 (GPL) for more details.
**
* Linking this library statically or dynamically with other modules is
* making a combined work based on this library. Thus, the terms and
* conditions of the GNU General Public License cover the whole
* combination.
**
* As a special exception, the copyright holders of this library give you
* permission to link this library with independent modules to produce an
* executable, regardless of the license terms of these independent
* modules, and to copy and distribute the resulting executable under
* terms of your choice, provided that you also meet, for each linked
* independent module, the terms and conditions of the license of that
* module. An independent module is a module which is not derived from
* or based on this library. If you modify this library, you may extend
* this exception to your version of the library, but you are not
* obligated to do so. If you do not wish to do so, delete this
* exception statement from your version.
*/
package java.util;
import gnu.classpath.SystemProperties;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.VMAccessorJavaIo;
import java.text.DateFormatSymbols;
final class VMTimeZone
{
private static final String[] TZ_ABBRS_MAP =
{
"ACT", "Australia/Darwin",
"AET", "Australia/Sydney",
"AGT", "America/Cayenne",
"ART", "Africa/Cairo",
"AST", "America/Anchorage",
"BET", "America/Sao_Paulo",
"BST", "Asia/Dhaka",
"CAT", "Africa/Harare",
"CET", "Europe/Amsterdam",
"CNT", "America/St_Johns",
"CST", "America/Chicago",
"CTT", "Asia/Shanghai",
"Cuba", "America/Havana",
"EAT", "Africa/Addis_Ababa",
"ECT", "Europe/Paris",
"EET", "Europe/Athens",
"EST", "America/New_York",
"Egypt", "Africa/Cairo",
"Eire", "Europe/Dublin",
"GB", "Europe/London",
"GB-Eire", "Europe/Dublin",
"Greenwich", "GMT",
"HST", "Pacific/Honolulu",
"Hongkong", "Asia/Hong_Kong",
"IET", "America/Indianapolis",
"IST", "Asia/Calcutta",
"Iceland", "Atlantic/Reykjavik",
"Iran", "Asia/Tehran",
"Israel", "Asia/Jerusalem",
"JST", "Asia/Tokyo",
"Jamaica", "America/Jamaica",
"Japan", "Asia/Tokyo",
"Kwajalein", "Pacific/Kwajalein",
"Libya", "Africa/Tripoli",
"MET", "Asia/Tehran",
"MIT", "Pacific/Apia",
"MST", "America/Denver",
"NET", "Asia/Yerevan",
"NST", "Pacific/Auckland",
"NZ", "Pacific/Auckland",
"NZ-CHAT", "Pacific/Chatham",
"Navajo", "America/Shiprock",
"PLT", "Asia/Karachi",
"PNT", "America/Phoenix",
"PRC", "Asia/Harbin",
"PRT", "America/Puerto_Rico",
"PST", "America/Los_Angeles",
"Poland", "Europe/Warsaw",
"Portugal", "Europe/Lisbon",
"ROC", "Asia/Taipei",
"ROK", "Asia/Seoul",
"SST", "Pacific/Guadalcanal",
"Singapore", "Asia/Singapore",
"Turkey", "Asia/Istanbul",
"UCT", "GMT",
"UTC", "GMT",
"Universal", "GMT",
"VST", "Asia/Saigon",
"W-SU", "Europe/Moscow",
"WET", "Europe/Lisbon",
"Zulu", "GMT",
};
private VMTimeZone() {}
static TimeZone getDefaultTimeZoneId()
{
TimeZone[] defZoneArr = new TimeZone[1];
TimeZone zone = convertTzIdToZone(defZoneArr,
VMAccessorJavaIo.getenvPlatformVMFile("TZ"));
if (zone == null)
{
boolean isEtcLocaltime = false;
zone = defZoneArr[0];
if (!"\\".equals(File.separator) && (zone = convertTzIdToZone(defZoneArr,
readSysconfigClockFile("/etc/default/init"))) == null &&
(zone = convertTzIdToZone(defZoneArr,
readTimezoneFile("/etc/timezone"))) == null &&
(zone = convertTzIdToZone(defZoneArr,
readSysconfigClockFile("/etc/sysconfig/clock"))) == null)
{
isEtcLocaltime = true;
if ((zone = convertTzIdToZone(defZoneArr,
processLocaltimeFile("/etc/localtime"))) == null)
zone = defZoneArr[0];
}
if ((isEtcLocaltime || zone == null) && (defZoneArr[0] =
getTimeZoneFor(getSystemTimeZoneId())) != null)
{
int rawOffset;
if (zone == null || ((rawOffset = defZoneArr[0].getRawOffset()) != 0 &&
(zone.getRawOffset() != rawOffset || zone.useDaylightTime() !=
defZoneArr[0].useDaylightTime())))
zone = defZoneArr[0];
}
}
if (zone != null && (zone.getID().indexOf('/', 0) > 0 ||
TimeZone.getTimeZone("GMT") == zone))
SystemProperties.setProperty("user.timezone", zone.getID());
return zone;
}
private static TimeZone convertTzIdToZone(TimeZone[] defZoneArr, String tzid)
{
TimeZone zone = null;
if (tzid != null)
{
tzid = removeTzIdPrefix(tzid.trim());
zone = getTimeZoneFor(tzid);
if (zone == null && defZoneArr[0] == null && tzid.length() > 0)
defZoneArr[0] = TimeZone.getDefaultTimeZone(tzid);
}
return zone;
}
private static String removeTzIdPrefix(String tzid)
{
if (tzid.startsWith(":") && tzid.length() > 1)
tzid = tzid.substring(1);
if ((tzid.startsWith("posix/") || tzid.startsWith("right/")) &&
tzid.length() > 7)
tzid = tzid.substring(6);
return tzid;
}
private static String readTimezoneFile(String filename)
{
InputStreamReader in = null;
StringBuilder sb = null;
try
{
in = new InputStreamReader(new BufferedInputStream(new FileInputStream(
filename)));
sb = new StringBuilder();
int c;
while ((c = in.read()) >= 0 && ((c >= 'A' && c <= 'Z') ||
(c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') ||
c == '/' || c == '-' || c == '_'))
sb.append((char) c);
}
catch (IOException e) {}
if (in != null)
{
try
{
in.close();
}
catch (IOException e) {}
}
return sb != null ? sb.toString() : null;
}
private static String readSysconfigClockFile(String filename)
{
BufferedReader in = null;
String line = null;
try
{
in = new BufferedReader(new InputStreamReader(new FileInputStream(
filename)));
while ((line = in.readLine()) != null)
{
int pos = line.indexOf('=', 0);
if (pos > 0)
{
String key = line.substring(0, pos).trim();
if (key.equals("ZONE") || key.equals("TIMEZONE") || key.equals("TZ"))
{
line = line.substring(pos + 1).trim();
if (line.length() > 1)
break;
}
}
}
}
catch (IOException e) {}
if (in != null)
{
try
{
in.close();
}
catch (IOException e) {}
if (line != null)
{
char ch = line.charAt(0);
int pos;
if (ch == '"')
line = (pos = line.indexOf('"', 1)) > 2 ? line.substring(1, pos) : null;
else
{
if (ch == '\'')
line = (pos = line.indexOf('\'', 1)) > 2 ?
line.substring(1, pos) : null;
else
{
pos = line.indexOf(' ', 1);
if (pos > 1)
line = line.substring(0, pos);
}
}
}
}
return line;
}
private static String processLocaltimeFile(String filename)
{
String str = filename;
try
{
str = VMAccessorJavaIo.realPathVMFile(filename);
}
catch (IOException e) {}
if (!filename.equals(str))
{
String zoneinfoPrefix = "/zoneinfo/";
int pos = str.indexOf(zoneinfoPrefix);
if (pos >= 0)
{
str = str.substring(pos + zoneinfoPrefix.length());
if (str.length() > 1)
return str;
}
}
return null;
}
private static TimeZone getTimeZoneFor(String tzid)
{
int len = tzid.length();
TimeZone defZone = null;
if (len > 0)
{
TimeZone zone;
if (!tzid.startsWith("GMT") && (zone =
TimeZone.getTimeZone(tzid)) != null && tzid.equals(zone.getID()))
{
if (tzid.indexOf('/', 0) > 0)
return zone;
defZone = zone;
}
int pos = 0;
char ch;
do
{
ch = tzid.charAt(pos);
} while (((ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') ||
(ch == '-' && pos + 1 < len && tzid.charAt(pos + 1) > '9')) &&
++pos < len);
if ((pos >= 3 && pos <= 5) || (pos == len && pos >= 2))
{
String stdName = tzid.substring(0, pos);
int rawOffset = -1 >>> 1;
String dstName = null;
if (pos < len)
{
boolean isneg = ch == '-';
if (ch == '+' || isneg)
{
if (++pos >= len)
return null;
ch = tzid.charAt(pos);
}
if (ch < '0' || ch > '9')
return null;
rawOffset = (ch - '0') * 60;
int i = pos;
while (++pos < len)
if ((ch = tzid.charAt(pos)) < '0' || ch > '9')
break;
i = pos - i;
if (i > 4)
return null;
if ((i & 1) == 0)
rawOffset = (tzid.charAt(pos - i + 1) - '0') * 60 + rawOffset * 10;
if (ch == ':')
{
if (i > 2 || ++pos >= len ||
(ch = tzid.charAt(pos)) < '0' || ch > '9' ||
(++pos < len && (ch = tzid.charAt(pos)) >= '0' && ch <= '9' &&
++pos < len && (ch = tzid.charAt(pos)) >= '0' && ch <= '9'))
return null;
i = 4;
}
if (i > 2)
{
ch = tzid.charAt(pos - 2);
rawOffset += tzid.charAt(pos - 1) - '0';
if (ch != ':')
{
if (ch > '5')
return null;
rawOffset += (ch - '0') * 10;
}
}
rawOffset = rawOffset * (60 * 1000);
if (!isneg)
rawOffset = -rawOffset;
if (pos < len)
{
i = pos;
do
{
ch = tzid.charAt(pos);
} while (((ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z')) &&
++pos < len);
if (i < pos)
dstName = tzid.substring(i, pos);
}
}
if (dstName == null && stdName.equalsIgnoreCase("GMT"))
return TimeZone.getTimeZone(toGMTFormat(rawOffset != (-1 >>> 1) ?
rawOffset : 0));
String[] table = TZ_ABBRS_MAP;
int count = table.length;
for (int i = 0; i < count; i++)
if (stdName.equalsIgnoreCase(table[i++]) &&
(zone = TimeZone.getTimeZone(table[i])) != null &&
zone.getID().equals(table[i]) && (rawOffset == (-1 >>> 1) ||
(zone.getRawOffset() == rawOffset && (zone.useDaylightTime() ?
dstName != null && dstName.equalsIgnoreCase(zone.getDisplayName(true,
TimeZone.SHORT, Locale.US)) : dstName == null))))
return zone;
String[][] zoneStrings = new DateFormatSymbols(Locale.US).getZoneStrings();
if (zoneStrings != null)
{
count = zoneStrings.length;
for (int i = 0; i < count; i++)
{
String[] names = zoneStrings[i];
if (names != null && names.length > 4 &&
stdName.equalsIgnoreCase(names[2]) && names[0] != null &&
(dstName == null || dstName.equalsIgnoreCase(names[4])) &&
(zone = TimeZone.getTimeZone(names[0])) != null &&
names[0].equals(zone.getID()) && (rawOffset == (-1 >>> 1) ||
(zone.getRawOffset() == rawOffset &&
zone.useDaylightTime() == (dstName != null))))
return zone;
}
}
}
}
return defZone;
}
private static String getSystemTimeZoneId()
{
int rawOffset = getCTimezoneAndDaylight0();
if (rawOffset != 0)
{
boolean useDaylight = (rawOffset & 1) != 0;
rawOffset = (rawOffset >> 1) * 1000;
String[] ids = TimeZone.getAvailableIDs(-rawOffset);
int count = ids.length;
String tzid;
for (int i = 0; i < count; i++)
if ((tzid = ids[i]) != null)
{
TimeZone zone = TimeZone.getTimeZone(tzid);
if (zone != null && tzid.equals(zone.getID()) &&
zone.useDaylightTime() == useDaylight && !zone.getDisplayName(false,
TimeZone.SHORT, Locale.US).startsWith("GMT"))
return zone.getID();
}
for (int i = 0; i < count; i++)
if ((tzid = ids[i]) != null)
{
TimeZone zone = TimeZone.getTimeZone(tzid);
if (zone != null && tzid.equals(zone.getID()) &&
zone.useDaylightTime() == useDaylight)
return zone.getID();
}
}
return toGMTFormat(rawOffset);
}
private static String toGMTFormat(int rawOffset)
{
StringBuilder sb = new StringBuilder();
rawOffset = rawOffset / (60 * 1000);
sb.append("GMT");
if (rawOffset != 0)
{
if (rawOffset < 0)
{
sb.append('-');
rawOffset = -rawOffset;
}
else sb.append('+');
int hours = rawOffset / 60;
if (hours < 10)
sb.append('0');
sb.append(String.valueOf(hours));
sb.append(':');
int minutes = rawOffset % 60;
if (minutes < 10)
sb.append('0');
sb.append(String.valueOf(minutes));
}
return sb.toString();
}
private static native int getCTimezoneAndDaylight0();
}