ICU-5561 Added a new API TimeZone#getCanonicalID and its test case in ICU4J. Also cleaned up some code in ZoneMeta related to the new API implementation.
X-SVN-Rev: 23279
This commit is contained in:
parent
a74869abf6
commit
06b6c7f668
@ -1,7 +1,7 @@
|
||||
/*
|
||||
*******************************************************************************
|
||||
* Copyright (C) 2007, Google, IBM and *
|
||||
* others. All Rights Reserved. *
|
||||
* Copyright (C) 2007-2008, Google, IBM and *
|
||||
* others. All Rights Reserved. *
|
||||
*******************************************************************************
|
||||
*/
|
||||
|
||||
@ -138,7 +138,8 @@ public class TimeZoneFormatTest extends com.ibm.icu.dev.test.TestFmwk {
|
||||
}
|
||||
} else { // "VVVV"
|
||||
// Location: time zone rule must be preserved.
|
||||
if (!outtz.getID().equals(ZoneMeta.getCanonicalID(tzids[tzidx]))) {
|
||||
String canonicalID = TimeZone.getCanonicalID(tzids[tzidx]);
|
||||
if (canonicalID != null && !outtz.getID().equals(canonicalID)) {
|
||||
// Canonical ID did not match - check the rules
|
||||
if (!((BasicTimeZone)outtz).hasEquivalentTransitions(tz, low, high)) {
|
||||
errln("Canonical round trip failed; tz=" + tzids[tzidx]
|
||||
@ -221,7 +222,8 @@ public class TimeZoneFormatTest extends com.ibm.icu.dev.test.TestFmwk {
|
||||
|
||||
String[] ids = TimeZone.getAvailableIDs();
|
||||
for (int zidx = 0; zidx < ids.length; zidx++) {
|
||||
if(!ids[zidx].equals(ZoneMeta.getCanonicalID(ids[zidx]))) {
|
||||
String id = TimeZone.getCanonicalID(ids[zidx]);
|
||||
if (id == null || !id.equals(ids[zidx])) {
|
||||
// Skip aliases
|
||||
continue;
|
||||
}
|
||||
|
@ -1366,6 +1366,136 @@ public class TimeZoneTest extends TestFmwk
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void TestCanonicalID() {
|
||||
// Some canonical IDs in CLDR are defined as "Link"
|
||||
// in Olson tzdata.
|
||||
final String[][] excluded1 = {
|
||||
{"America/Shiprock", "America/Denver"}, // America/Shiprock is defined as a Link to America/Denver in tzdata
|
||||
{"Antarctica/South_Pole", "Antarctica/McMurdo"},
|
||||
{"Atlantic/Jan_Mayen", "Europe/Oslo"},
|
||||
{"Arctic/Longyearbyen", "Europe/Oslo"},
|
||||
{"Europe/Guernsey", "Europe/London"},
|
||||
{"Europe/Isle_of_Man", "Europe/London"},
|
||||
{"Europe/Jersey", "Europe/London"},
|
||||
{"Europe/Ljubljana", "Europe/Belgrade"},
|
||||
{"Europe/Podgorica", "Europe/Belgrade"},
|
||||
{"Europe/Sarajevo", "Europe/Belgrade"},
|
||||
{"Europe/Skopje", "Europe/Belgrade"},
|
||||
{"Europe/Zagreb", "Europe/Belgrade"},
|
||||
{"Europe/Bratislava", "Europe/Prague"},
|
||||
{"Europe/Mariehamn", "Europe/Helsinki"},
|
||||
{"Europe/San_Marino", "Europe/Rome"},
|
||||
{"Europe/Vatican", "Europe/Rome"},
|
||||
};
|
||||
|
||||
// Following IDs are aliases of Etc/GMT in CLDR,
|
||||
// but Olson tzdata has 3 independent definitions
|
||||
// for Etc/GMT, Etc/UTC, Etc/UCT.
|
||||
// Until we merge them into one equivalent group
|
||||
// in zoneinfo.res, we exclude them in the test
|
||||
// below.
|
||||
final String[] excluded2 = {
|
||||
"Etc/UCT", "UCT",
|
||||
"Etc/UTC", "UTC",
|
||||
"Etc/Universal", "Universal",
|
||||
"Etc/Zulu", "Zulu",
|
||||
};
|
||||
|
||||
// Walk through equivalency groups
|
||||
String[] ids = TimeZone.getAvailableIDs();
|
||||
for (int i = 0; i < ids.length; i++) {
|
||||
int nEquiv = TimeZone.countEquivalentIDs(ids[i]);
|
||||
if (nEquiv == 0) {
|
||||
continue;
|
||||
}
|
||||
String tmp = TimeZone.getEquivalentID(ids[i], 0);
|
||||
String canonicalID = TimeZone.getCanonicalID(tmp);
|
||||
if (canonicalID == null) {
|
||||
errln("FAIL: getCanonicalID(" + tmp + ") returned null");
|
||||
continue;
|
||||
}
|
||||
// Some exceptional cases
|
||||
for (int k = 0; k < excluded1.length; k++) {
|
||||
if (canonicalID.equals(excluded1[k][0])) {
|
||||
canonicalID = excluded1[k][1];
|
||||
}
|
||||
}
|
||||
boolean bFoundCanonical = false;
|
||||
// Make sure getCanonicalID returns the exact same result
|
||||
// for all entries within a same equivalency group with some
|
||||
// exceptions listed in exluded1.
|
||||
// Also, one of them must be canonical id.
|
||||
for (int j = 0; j < nEquiv; j++) {
|
||||
tmp = TimeZone.getEquivalentID(ids[i], j);
|
||||
if (canonicalID.equals(tmp)) {
|
||||
bFoundCanonical = true;
|
||||
}
|
||||
String tmpCanonical = TimeZone.getCanonicalID(tmp);
|
||||
// Some exceptional cases
|
||||
for (int k = 0; k < excluded1.length; k++) {
|
||||
if (tmpCanonical.equals(excluded1[k][0])) {
|
||||
tmpCanonical = excluded1[k][1];
|
||||
}
|
||||
}
|
||||
if (!canonicalID.equals(tmpCanonical)) {
|
||||
errln("FAIL: getCanonicalID(" + tmp + ") returned " + tmpCanonical + " expected:" + canonicalID);
|
||||
}
|
||||
}
|
||||
// At least one ID in an equvalency group must match the
|
||||
// canonicalID
|
||||
if (!bFoundCanonical) {
|
||||
// test exclusion because of differences between Olson tzdata and CLDR
|
||||
boolean isExcluded = false;
|
||||
for (int k = 0; k < excluded1.length; k++) {
|
||||
if (ids[i].equals(excluded2[k])) {
|
||||
isExcluded = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (isExcluded) {
|
||||
continue;
|
||||
}
|
||||
|
||||
errln("FAIL: No timezone ids match the canonical ID " + canonicalID);
|
||||
}
|
||||
}
|
||||
// Testing some special cases
|
||||
final String[] data = {
|
||||
"GMT-03",
|
||||
"GMT+4",
|
||||
"GMT-055",
|
||||
"GMT+430",
|
||||
"GMT-12:15",
|
||||
"GMT-091015",
|
||||
"GMT+1:90",
|
||||
"America/Argentina/Buenos_Aires",
|
||||
"bogus",
|
||||
"",
|
||||
null,
|
||||
};
|
||||
final String[] expected = {
|
||||
"GMT-0300",
|
||||
"GMT+0400",
|
||||
"GMT-0055",
|
||||
"GMT+0430",
|
||||
"GMT-1215",
|
||||
"GMT-091015",
|
||||
null,
|
||||
"America/Buenos_Aires",
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
};
|
||||
for (int i = 0; i < data.length; i++) {
|
||||
String canonical = TimeZone.getCanonicalID(data[i]);
|
||||
if (canonical != null && !canonical.equals(expected[i])
|
||||
|| canonical == null && expected[i] != null) {
|
||||
errln("FAIL: getCanonicalID(" + data[i] + ") returned " + canonical
|
||||
+ " - expected: " + expected[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//eof
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
**********************************************************************
|
||||
* Copyright (c) 2003-2007 International Business Machines
|
||||
* Copyright (c) 2003-2008 International Business Machines
|
||||
* Corporation and others. All Rights Reserved.
|
||||
**********************************************************************
|
||||
* Author: Alan Liu
|
||||
@ -173,73 +173,113 @@ public final class ZoneMeta {
|
||||
public static synchronized String getEquivalentID(String id, int index) {
|
||||
String result="";
|
||||
UResourceBundle res = openOlsonResource(id);
|
||||
int zone = -1;
|
||||
int size = res.getSize();
|
||||
if (size == 4 || size == 6) {
|
||||
UResourceBundle r = res.get(size-1);
|
||||
int[] v = r.getIntVector();
|
||||
if (index >= 0 && index < v.length && getOlsonMeta()) {
|
||||
zone = v[index];
|
||||
if (res != null) {
|
||||
int zone = -1;
|
||||
int size = res.getSize();
|
||||
if (size == 4 || size == 6) {
|
||||
UResourceBundle r = res.get(size-1);
|
||||
int[] v = r.getIntVector();
|
||||
if (index >= 0 && index < v.length) {
|
||||
zone = v[index];
|
||||
}
|
||||
}
|
||||
if (zone >= 0) {
|
||||
try {
|
||||
UResourceBundle top = UResourceBundle.getBundleInstance(ICUResourceBundle.ICU_BASE_NAME, "zoneinfo",
|
||||
ICUResourceBundle.ICU_DATA_CLASS_LOADER);
|
||||
UResourceBundle ares = top.get(kNAMES); // dereference Zones section
|
||||
result = ares.getString(zone);
|
||||
} catch (MissingResourceException e) {
|
||||
result = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
if (zone >= 0) {
|
||||
UResourceBundle top = UResourceBundle.getBundleInstance(ICUResourceBundle.ICU_BASE_NAME, "zoneinfo", ICUResourceBundle.ICU_DATA_CLASS_LOADER);
|
||||
UResourceBundle ares = top.get(kNAMES); // dereference Zones section
|
||||
result = ares.getString(zone);
|
||||
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static String[] getCanonicalInfo(String id) {
|
||||
// We need to resolve Olson links which are not available in CLDR first
|
||||
String olsonCanonicalID = getOlsonCanonicalID(id);
|
||||
if (olsonCanonicalID == null) {
|
||||
return null;
|
||||
}
|
||||
if (canonicalMap == null) {
|
||||
Map m = new HashMap();
|
||||
Set s = new HashSet();
|
||||
UResourceBundle supplementalDataBundle = UResourceBundle.getBundleInstance(ICUResourceBundle.ICU_BASE_NAME, "supplementalData", ICUResourceBundle.ICU_DATA_CLASS_LOADER);
|
||||
|
||||
UResourceBundle zoneFormatting = supplementalDataBundle.get("zoneFormatting");
|
||||
UResourceBundleIterator it = zoneFormatting.getIterator();
|
||||
|
||||
while ( it.hasNext()) {
|
||||
UResourceBundle temp = it.next();
|
||||
int resourceType = temp.getType();
|
||||
|
||||
switch(resourceType) {
|
||||
case UResourceBundle.TABLE:
|
||||
String [] result = { "", "" };
|
||||
UResourceBundle zoneInfo = temp;
|
||||
String canonicalID = zoneInfo.getKey().replace(':','/');
|
||||
String territory = zoneInfo.get("territory").getString();
|
||||
result[0] = canonicalID;
|
||||
if ( territory.equals("001")) {
|
||||
result[1] = null;
|
||||
}
|
||||
else {
|
||||
result[1] = territory;
|
||||
}
|
||||
m.put(canonicalID,result);
|
||||
try {
|
||||
UResourceBundle aliasBundle = zoneInfo.get("aliases");
|
||||
String [] aliases = aliasBundle.getStringArray();
|
||||
for (int i=0 ; i<aliases.length; i++) {
|
||||
m.put(aliases[i],result);
|
||||
try {
|
||||
UResourceBundle supplementalDataBundle = UResourceBundle.getBundleInstance(ICUResourceBundle.ICU_BASE_NAME, "supplementalData", ICUResourceBundle.ICU_DATA_CLASS_LOADER);
|
||||
|
||||
UResourceBundle zoneFormatting = supplementalDataBundle.get("zoneFormatting");
|
||||
UResourceBundleIterator it = zoneFormatting.getIterator();
|
||||
|
||||
while ( it.hasNext()) {
|
||||
UResourceBundle temp = it.next();
|
||||
int resourceType = temp.getType();
|
||||
|
||||
switch(resourceType) {
|
||||
case UResourceBundle.TABLE:
|
||||
String [] result = { "", "" };
|
||||
UResourceBundle zoneInfo = temp;
|
||||
String canonicalID = zoneInfo.getKey().replace(':','/');
|
||||
String territory = zoneInfo.get("territory").getString();
|
||||
result[0] = canonicalID;
|
||||
if ( territory.equals("001")) {
|
||||
result[1] = null;
|
||||
}
|
||||
} catch(MissingResourceException ex){
|
||||
// Disregard if there are no aliases
|
||||
}
|
||||
break;
|
||||
case UResourceBundle.ARRAY:
|
||||
String[] territoryList = temp.getStringArray();
|
||||
for (int i=0 ; i < territoryList.length; i++) {
|
||||
s.add(territoryList[i]);
|
||||
}
|
||||
break;
|
||||
else {
|
||||
result[1] = territory;
|
||||
}
|
||||
m.put(canonicalID,result);
|
||||
try {
|
||||
UResourceBundle aliasBundle = zoneInfo.get("aliases");
|
||||
String [] aliases = aliasBundle.getStringArray();
|
||||
for (int i=0 ; i<aliases.length; i++) {
|
||||
m.put(aliases[i],result);
|
||||
}
|
||||
} catch(MissingResourceException ex){
|
||||
// Disregard if there are no aliases
|
||||
}
|
||||
break;
|
||||
case UResourceBundle.ARRAY:
|
||||
String[] territoryList = temp.getStringArray();
|
||||
for (int i=0 ; i < territoryList.length; i++) {
|
||||
s.add(territoryList[i]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (MissingResourceException e) {
|
||||
// throws away the exception - maps are empty for this case
|
||||
}
|
||||
|
||||
// Some available Olson zones are not included in CLDR data (such as Asia/Riyadh87).
|
||||
// Also, when we update Olson tzdata, new zones may be added.
|
||||
// This code scans all available zones in zoneinfo.res, and if any of them are
|
||||
// missing, add them to the map.
|
||||
try{
|
||||
UResourceBundle top = (ICUResourceBundle)ICUResourceBundle.getBundleInstance(ICUResourceBundle.ICU_BASE_NAME,
|
||||
"zoneinfo", ICUResourceBundle.ICU_DATA_CLASS_LOADER);
|
||||
UResourceBundle names = top.get(kNAMES);
|
||||
String[] ids = names.getStringArray();
|
||||
for (int i = 0; i < ids.length; i++) {
|
||||
if (m.containsKey(ids[i])) {
|
||||
// Already included in CLDR data
|
||||
continue;
|
||||
}
|
||||
// Check if this is a canonical zone in the tzdata
|
||||
UResourceBundle res = getZoneByName(top, ids[i]);
|
||||
if (res.getSize() == 1) {
|
||||
// This is an alias in the tzdata
|
||||
// Check if the canonical zone is already in the canonical map
|
||||
int deref = res.getInt();
|
||||
String[] tmpinfo = (String[])m.get(ids[deref]);
|
||||
if (tmpinfo != null) {
|
||||
m.put(ids[i], tmpinfo);
|
||||
} else {
|
||||
m.put(ids[i], new String[] {ids[deref], null});
|
||||
}
|
||||
} else {
|
||||
// This is a canonical zone
|
||||
m.put(ids[i], new String[] {ids[i], null});
|
||||
}
|
||||
}
|
||||
} catch (MissingResourceException ex) {
|
||||
//throw away the exception
|
||||
}
|
||||
|
||||
synchronized (ZoneMeta.class) {
|
||||
@ -248,22 +288,22 @@ public final class ZoneMeta {
|
||||
}
|
||||
}
|
||||
|
||||
return (String[])canonicalMap.get(olsonCanonicalID);
|
||||
return (String[])canonicalMap.get(id);
|
||||
}
|
||||
|
||||
private static Map canonicalMap = null;
|
||||
private static Set multiZoneTerritories = null;
|
||||
|
||||
/**
|
||||
* Return the canonical id for this tzid, which might be the id itself.
|
||||
* If there is no canonical id for it, return the passed-in id.
|
||||
* Return the canonical id for this system tzid, which might be the id itself.
|
||||
* If the given system tzid is not know, return null.
|
||||
*/
|
||||
public static String getCanonicalID(String tzid) {
|
||||
public static String getCanonicalSystemID(String tzid) {
|
||||
String[] info = getCanonicalInfo(tzid);
|
||||
if (info != null) {
|
||||
return info[0];
|
||||
}
|
||||
return tzid;
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -309,20 +349,24 @@ public final class ZoneMeta {
|
||||
|
||||
String country = null;
|
||||
if (country_code != null) {
|
||||
ICUResourceBundle rb =
|
||||
(ICUResourceBundle)UResourceBundle.getBundleInstance(ICUResourceBundle.ICU_BASE_NAME, locale);
|
||||
try {
|
||||
ICUResourceBundle rb =
|
||||
(ICUResourceBundle)UResourceBundle.getBundleInstance(ICUResourceBundle.ICU_BASE_NAME, locale);
|
||||
//
|
||||
// TODO: There is a design bug in UResourceBundle and getLoadingStatus() does not work well.
|
||||
//
|
||||
// if (rb.getLoadingStatus() != ICUResourceBundle.FROM_ROOT && rb.getLoadingStatus() != ICUResourceBundle.FROM_DEFAULT) {
|
||||
// country = ULocale.getDisplayCountry("xx_" + country_code, locale);
|
||||
// }
|
||||
// if (rb.getLoadingStatus() != ICUResourceBundle.FROM_ROOT && rb.getLoadingStatus() != ICUResourceBundle.FROM_DEFAULT) {
|
||||
// country = ULocale.getDisplayCountry("xx_" + country_code, locale);
|
||||
// }
|
||||
// START WORKAROUND
|
||||
ULocale rbloc = rb.getULocale();
|
||||
if (!rbloc.equals(ULocale.ROOT) && rbloc.getLanguage().equals(locale.getLanguage())) {
|
||||
country = ULocale.getDisplayCountry("xx_" + country_code, locale);
|
||||
}
|
||||
ULocale rbloc = rb.getULocale();
|
||||
if (!rbloc.equals(ULocale.ROOT) && rbloc.getLanguage().equals(locale.getLanguage())) {
|
||||
country = ULocale.getDisplayCountry("xx_" + country_code, locale);
|
||||
}
|
||||
// END WORKAROUND
|
||||
} catch (MissingResourceException e) {
|
||||
// fall through
|
||||
}
|
||||
if (country == null || country.length() == 0) {
|
||||
country = country_code;
|
||||
}
|
||||
@ -332,6 +376,9 @@ public final class ZoneMeta {
|
||||
// TR35 says to display the country _only_ if there is a localization.
|
||||
if (getSingleCountry(tzid) != null) { // single country
|
||||
String regPat = getTZLocalizationInfo(locale, REGION_FORMAT);
|
||||
if (regPat == null) {
|
||||
regPat = DEF_REGION_FORMAT;
|
||||
}
|
||||
MessageFormat mf = new MessageFormat(regPat);
|
||||
return mf.format(new Object[] { country });
|
||||
}
|
||||
@ -341,11 +388,17 @@ public final class ZoneMeta {
|
||||
}
|
||||
|
||||
String flbPat = getTZLocalizationInfo(locale, FALLBACK_FORMAT);
|
||||
if (flbPat == null) {
|
||||
flbPat = DEF_FALLBACK_FORMAT;
|
||||
}
|
||||
MessageFormat mf = new MessageFormat(flbPat);
|
||||
|
||||
return mf.format(new Object[] { city, country });
|
||||
}
|
||||
|
||||
private static final String DEF_REGION_FORMAT = "{0}";
|
||||
private static final String DEF_FALLBACK_FORMAT = "{1} ({0})";
|
||||
|
||||
public static final String
|
||||
HOUR = "hourFormat",
|
||||
GMT = "gmtFormat",
|
||||
@ -359,8 +412,14 @@ public final class ZoneMeta {
|
||||
* values PREFIX, HOUR, GMT, REGION_FORMAT, FALLBACK_FORMAT
|
||||
*/
|
||||
public static String getTZLocalizationInfo(ULocale locale, String format) {
|
||||
ICUResourceBundle bundle = (ICUResourceBundle) ICUResourceBundle.getBundleInstance(locale);
|
||||
return bundle.getStringWithFallback(ZONE_STRINGS+FORWARD_SLASH+format);
|
||||
String result = null;
|
||||
try {
|
||||
ICUResourceBundle bundle = (ICUResourceBundle) ICUResourceBundle.getBundleInstance(locale);
|
||||
result = bundle.getStringWithFallback(ZONE_STRINGS+FORWARD_SLASH+format);
|
||||
} catch (MissingResourceException e) {
|
||||
result = null;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// private static Set getValidIDs() {
|
||||
@ -387,56 +446,30 @@ public final class ZoneMeta {
|
||||
*/
|
||||
public static UResourceBundle openOlsonResource(String id)
|
||||
{
|
||||
if(!getOlsonMeta()){
|
||||
return null;
|
||||
UResourceBundle res = null;
|
||||
try {
|
||||
ICUResourceBundle top = (ICUResourceBundle)UResourceBundle.getBundleInstance(ICUResourceBundle.ICU_BASE_NAME, "zoneinfo", ICUResourceBundle.ICU_DATA_CLASS_LOADER);
|
||||
res = getZoneByName(top, id);
|
||||
// Dereference if this is an alias. Docs say result should be 1
|
||||
// but it is 0 in 2.8 (?).
|
||||
if (res.getSize() <= 1) {
|
||||
int deref = res.getInt() + 0;
|
||||
UResourceBundle ares = top.get(kZONES); // dereference Zones section
|
||||
res = (ICUResourceBundle) ares.get(deref);
|
||||
}
|
||||
} catch (MissingResourceException e) {
|
||||
res = null;
|
||||
}
|
||||
ICUResourceBundle top = (ICUResourceBundle)UResourceBundle.getBundleInstance(ICUResourceBundle.ICU_BASE_NAME, "zoneinfo", ICUResourceBundle.ICU_DATA_CLASS_LOADER);
|
||||
UResourceBundle res = getZoneByName(top, id);
|
||||
// Dereference if this is an alias. Docs say result should be 1
|
||||
// but it is 0 in 2.8 (?).
|
||||
if (res.getSize() <= 1 && getOlsonMeta(top)) {
|
||||
int deref = res.getInt() + 0;
|
||||
UResourceBundle ares = top.get(kZONES); // dereference Zones section
|
||||
res = (ICUResourceBundle) ares.get(deref);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a canonical Olson zone ID for the given ID. If the given ID is not valid,
|
||||
* this method returns null as the result. If the given ID is a link, then the
|
||||
* referenced ID (canonical ID) is returned.
|
||||
* @param id zone id
|
||||
* @return a canonical Olson id (not a link)
|
||||
*/
|
||||
public static synchronized String getOlsonCanonicalID(String id) {
|
||||
if (!getOlsonMeta()) {
|
||||
return null;
|
||||
}
|
||||
String canonicalID = null;
|
||||
ICUResourceBundle top = (ICUResourceBundle)UResourceBundle.getBundleInstance(ICUResourceBundle.ICU_BASE_NAME, "zoneinfo", ICUResourceBundle.ICU_DATA_CLASS_LOADER);
|
||||
try {
|
||||
UResourceBundle res = getZoneByName(top, id);
|
||||
if (res.getSize() == 1) {
|
||||
int deref = res.getInt();
|
||||
UResourceBundle names = top.get(kNAMES);
|
||||
canonicalID = names.getString(deref);
|
||||
} else {
|
||||
canonicalID = id;
|
||||
}
|
||||
} catch (MissingResourceException mre) {
|
||||
// throw away the exception
|
||||
}
|
||||
return canonicalID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch a specific zone by name. Replaces the getByKey call.
|
||||
* @param top Top timezone resource
|
||||
* @param id Time zone ID
|
||||
* @return the zone's bundle if found, or undefined if error. Reuses oldbundle.
|
||||
*/
|
||||
private static UResourceBundle getZoneByName(UResourceBundle top, String id) {
|
||||
private static UResourceBundle getZoneByName(UResourceBundle top, String id) throws MissingResourceException {
|
||||
// load the Rules object
|
||||
UResourceBundle tmp = top.get(kNAMES);
|
||||
|
||||
@ -505,10 +538,14 @@ public final class ZoneMeta {
|
||||
* meta-data. Return true if successful.
|
||||
*/
|
||||
private static boolean getOlsonMeta(ICUResourceBundle top) {
|
||||
if (OLSON_ZONE_START < 0) {
|
||||
UResourceBundle res = top.get(kZONES);
|
||||
OLSON_ZONE_COUNT = res.getSize();
|
||||
OLSON_ZONE_START = 0;
|
||||
if (OLSON_ZONE_START < 0 && top != null) {
|
||||
try {
|
||||
UResourceBundle res = top.get(kZONES);
|
||||
OLSON_ZONE_COUNT = res.getSize();
|
||||
OLSON_ZONE_START = 0;
|
||||
} catch (MissingResourceException e) {
|
||||
// throws away the exception
|
||||
}
|
||||
}
|
||||
return (OLSON_ZONE_START >= 0);
|
||||
}
|
||||
@ -517,12 +554,17 @@ public final class ZoneMeta {
|
||||
* Load up the Olson meta-data. Return true if successful.
|
||||
*/
|
||||
private static boolean getOlsonMeta() {
|
||||
ICUResourceBundle top = (ICUResourceBundle)ICUResourceBundle.getBundleInstance(ICUResourceBundle.ICU_BASE_NAME, "zoneinfo", ICUResourceBundle.ICU_DATA_CLASS_LOADER);
|
||||
if(OLSON_ZONE_START < 0) {
|
||||
getOlsonMeta(top);
|
||||
if (OLSON_ZONE_START < 0) {
|
||||
try {
|
||||
ICUResourceBundle top = (ICUResourceBundle)ICUResourceBundle.getBundleInstance(ICUResourceBundle.ICU_BASE_NAME, "zoneinfo", ICUResourceBundle.ICU_DATA_CLASS_LOADER);
|
||||
getOlsonMeta(top);
|
||||
} catch (MissingResourceException e) {
|
||||
// throws away the exception
|
||||
}
|
||||
}
|
||||
return (OLSON_ZONE_START >= 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Lookup the given name in our system zone table. If found,
|
||||
* instantiate a new zone of that name and return it. If not
|
||||
@ -563,11 +605,45 @@ public final class ZoneMeta {
|
||||
* no Daylight Savings Time, or null if the id cannot be parsed.
|
||||
*/
|
||||
public static TimeZone getCustomTimeZone(String id){
|
||||
int[] fields = new int[4];
|
||||
if (parseCustomID(id, fields)) {
|
||||
String zid = formatCustomID(fields[1], fields[2], fields[3], fields[0] < 0);
|
||||
int offset = fields[0] * ((fields[1] * 60 + fields[2]) * 60 + fields[3]) * 1000;
|
||||
return new SimpleTimeZone(offset, zid);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a custom time zone identifier and return the normalized
|
||||
* custom time zone identifier for the given custom id string.
|
||||
* @param id a string of the form GMT[+-]hh:mm, GMT[+-]hhmm, or
|
||||
* GMT[+-]hh.
|
||||
* @return The normalized custom id string.
|
||||
*/
|
||||
public static String getCustomID(String id) {
|
||||
int[] fields = new int[4];
|
||||
if (parseCustomID(id, fields)) {
|
||||
return formatCustomID(fields[1], fields[2], fields[3], fields[0] < 0);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/*
|
||||
* Parses the given custom time zone identifier
|
||||
* @param id id A string of the form GMT[+-]hh:mm, GMT[+-]hhmm, or
|
||||
* GMT[+-]hh.
|
||||
* @param fields An array of int (length = 4) to receive the parsed
|
||||
* offset time fields. The sign is set to fields[0] (-1 or 1),
|
||||
* hour is set to fields[1], minute is set to fields[2] and second is
|
||||
* set to fields[3].
|
||||
* @return Returns true when the given custom id is valid.
|
||||
*/
|
||||
private static boolean parseCustomID(String id, int[] fields) {
|
||||
NumberFormat numberFormat = null;
|
||||
String idUppercase = id.toUpperCase();
|
||||
|
||||
if (id.length() > kGMT_ID.length() &&
|
||||
if (id != null && id.length() > kGMT_ID.length() &&
|
||||
idUppercase.startsWith(kGMT_ID)) {
|
||||
ParsePosition pos = new ParsePosition(kGMT_ID.length());
|
||||
boolean negative = false;
|
||||
@ -578,7 +654,7 @@ public final class ZoneMeta {
|
||||
if (id.charAt(pos.getIndex()) == 0x002D /*'-'*/) {
|
||||
negative = true;
|
||||
} else if (id.charAt(pos.getIndex()) != 0x002B /*'+'*/) {
|
||||
return null;
|
||||
return false;
|
||||
}
|
||||
pos.setIndex(pos.getIndex() + 1);
|
||||
|
||||
@ -590,14 +666,14 @@ public final class ZoneMeta {
|
||||
|
||||
Number n = numberFormat.parse(id, pos);
|
||||
if (pos.getIndex() == start) {
|
||||
return null;
|
||||
return false;
|
||||
}
|
||||
hour = n.intValue();
|
||||
|
||||
if (pos.getIndex() < id.length()){
|
||||
if (pos.getIndex() - start > 2
|
||||
|| id.charAt(pos.getIndex()) != 0x003A /*':'*/) {
|
||||
return null;
|
||||
return false;
|
||||
}
|
||||
// hh:mm
|
||||
pos.setIndex(pos.getIndex() + 1);
|
||||
@ -605,12 +681,12 @@ public final class ZoneMeta {
|
||||
n = numberFormat.parse(id, pos);
|
||||
if ((pos.getIndex() - oldPos) != 2) {
|
||||
// must be 2 digits
|
||||
return null;
|
||||
return false;
|
||||
}
|
||||
min = n.intValue();
|
||||
if (pos.getIndex() < id.length()) {
|
||||
if (id.charAt(pos.getIndex()) != 0x003A /*':'*/) {
|
||||
return null;
|
||||
return false;
|
||||
}
|
||||
// [:ss]
|
||||
pos.setIndex(pos.getIndex() + 1);
|
||||
@ -618,7 +694,7 @@ public final class ZoneMeta {
|
||||
n = numberFormat.parse(id, pos);
|
||||
if (pos.getIndex() != id.length()
|
||||
|| (pos.getIndex() - oldPos) != 2) {
|
||||
return null;
|
||||
return false;
|
||||
}
|
||||
sec = n.intValue();
|
||||
}
|
||||
@ -635,7 +711,7 @@ public final class ZoneMeta {
|
||||
int length = pos.getIndex() - start;
|
||||
if (length <= 0 || 6 < length) {
|
||||
// invalid length
|
||||
return null;
|
||||
return false;
|
||||
}
|
||||
switch (length) {
|
||||
case 1:
|
||||
@ -656,19 +732,25 @@ public final class ZoneMeta {
|
||||
}
|
||||
}
|
||||
|
||||
if (hour > kMAX_CUSTOM_HOUR || min > kMAX_CUSTOM_MIN || sec > kMAX_CUSTOM_SEC) {
|
||||
return null;
|
||||
if (hour <= kMAX_CUSTOM_HOUR && min <= kMAX_CUSTOM_MIN && sec <= kMAX_CUSTOM_SEC) {
|
||||
if (fields != null) {
|
||||
if (fields.length >= 1) {
|
||||
fields[0] = negative ? -1 : 1;
|
||||
}
|
||||
if (fields.length >= 2) {
|
||||
fields[1] = hour;
|
||||
}
|
||||
if (fields.length >= 3) {
|
||||
fields[2] = min;
|
||||
}
|
||||
if (fields.length >= 4) {
|
||||
fields[3] = sec;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
String zid = getCustomID(hour, min, sec, negative);
|
||||
int offset = ((hour * 60 + min) * 60 + sec) * 1000;
|
||||
if(negative) {
|
||||
offset = -offset;
|
||||
}
|
||||
TimeZone z = new SimpleTimeZone(offset, zid);
|
||||
return z;
|
||||
}
|
||||
return null;
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -687,6 +769,9 @@ public final class ZoneMeta {
|
||||
int hour, min, sec, millis;
|
||||
|
||||
millis = tmp % 1000;
|
||||
if (ASSERT) {
|
||||
Assert.assrt("millis!=0", millis != 0);
|
||||
}
|
||||
tmp /= 1000;
|
||||
sec = tmp % 60;
|
||||
tmp /= 60;
|
||||
@ -694,7 +779,7 @@ public final class ZoneMeta {
|
||||
hour = tmp / 60;
|
||||
|
||||
// Note: No millisecond part included in TZID for now
|
||||
String zid = getCustomID(hour, min, sec, negative);
|
||||
String zid = formatCustomID(hour, min, sec, negative);
|
||||
|
||||
return new SimpleTimeZone(offset, zid);
|
||||
}
|
||||
@ -702,7 +787,7 @@ public final class ZoneMeta {
|
||||
/*
|
||||
* Returns the normalized custom TimeZone ID
|
||||
*/
|
||||
private static String getCustomID(int hour, int min, int sec, boolean negative) {
|
||||
private static String formatCustomID(int hour, int min, int sec, boolean negative) {
|
||||
// Create normalized time zone ID - GMT[+|-]hhmm[ss]
|
||||
StringBuffer zid = new StringBuffer(kCUSTOM_TZ_PREFIX);
|
||||
if (hour != 0 || min != 0) {
|
||||
@ -785,7 +870,8 @@ public final class ZoneMeta {
|
||||
String[] tzids = getAvailableIDs();
|
||||
for (int i = 0; i < tzids.length; i++) {
|
||||
// Skip aliases
|
||||
if (!tzids[i].equals(getCanonicalID(tzids[i]))) {
|
||||
String canonicalID = TimeZone.getCanonicalID(tzids[i]);
|
||||
if (canonicalID == null || !tzids[i].equals(canonicalID)) {
|
||||
continue;
|
||||
}
|
||||
String tzkey = tzids[i].replace('/', ':');
|
||||
@ -845,7 +931,8 @@ public final class ZoneMeta {
|
||||
String[] tzids = getAvailableIDs();
|
||||
for (int i = 0; i < tzids.length; i++) {
|
||||
// Skip aliases
|
||||
if (!tzids[i].equals(getCanonicalID(tzids[i]))) {
|
||||
String canonicalID = TimeZone.getCanonicalID(tzids[i]);
|
||||
if (canonicalID == null || !tzids[i].equals(canonicalID)) {
|
||||
continue;
|
||||
}
|
||||
String tzkey = tzids[i].replace('/', ':');
|
||||
@ -896,6 +983,13 @@ public final class ZoneMeta {
|
||||
String mzid = null;
|
||||
Map olsonToMeta = getOlsonToMetaMap();
|
||||
List mappings = (List)olsonToMeta.get(olsonID);
|
||||
if (mappings == null) {
|
||||
// The given ID might be an alias - try its canonical id
|
||||
String canonicalID = getCanonicalSystemID(olsonID);
|
||||
if (canonicalID != null && !canonicalID.equals(olsonID)) {
|
||||
mappings = (List)olsonToMeta.get(canonicalID);
|
||||
}
|
||||
}
|
||||
if (mappings != null) {
|
||||
for (int i = 0; i < mappings.size(); i++) {
|
||||
OlsonToMetaMappingEntry mzm = (OlsonToMetaMappingEntry)mappings.get(i);
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
*******************************************************************************
|
||||
* Copyright (C) 2007, International Business Machines Corporation and *
|
||||
* Copyright (C) 2007-2008, International Business Machines Corporation and *
|
||||
* others. All Rights Reserved. *
|
||||
*******************************************************************************
|
||||
*/
|
||||
@ -238,11 +238,11 @@ public class ZoneStringFormat {
|
||||
String[][] mzPartialLoc = new String[10][4]; // maximum 10 metazones per zone
|
||||
|
||||
for (int i = 0; i < zoneIDs.length; i++) {
|
||||
// Skip IDs that are not canonicalized...
|
||||
if (!zoneIDs[i].equals(ZoneMeta.getCanonicalID(zoneIDs[i]))) {
|
||||
// Skip aliases
|
||||
String tzid = ZoneMeta.getCanonicalSystemID(zoneIDs[i]);
|
||||
if (tzid == null || !zoneIDs[i].equals(tzid)) {
|
||||
continue;
|
||||
}
|
||||
String tzid = zoneIDs[i];
|
||||
|
||||
String zoneKey = tzid.replace('/', ':');
|
||||
zstrarray[ZSIDX_LONG_STANDARD] = getZoneStringFromBundle(zoneStringsBundle, zoneKey, RESKEY_LONG_STANDARD);
|
||||
@ -451,8 +451,13 @@ public class ZoneStringFormat {
|
||||
ZoneStrings zstrings = (ZoneStrings)tzidToStrings.get(tzid);
|
||||
if (zstrings == null) {
|
||||
// ICU's own array does not have entries for aliases
|
||||
tzid = ZoneMeta.getCanonicalID(tzid);
|
||||
zstrings = (ZoneStrings)tzidToStrings.get(tzid);
|
||||
String canonicalID = ZoneMeta.getCanonicalSystemID(tzid);
|
||||
if (canonicalID != null && !canonicalID.equals(tzid)) {
|
||||
// Canonicalize tzid here. The rest of operations
|
||||
// require tzid to be canonicalized.
|
||||
tzid = canonicalID;
|
||||
zstrings = (ZoneStrings)tzidToStrings.get(tzid);
|
||||
}
|
||||
}
|
||||
if (zstrings != null) {
|
||||
switch (typeIdx) {
|
||||
@ -522,8 +527,13 @@ public class ZoneStringFormat {
|
||||
ZoneStrings zstrings = (ZoneStrings)tzidToStrings.get(tzid);
|
||||
if (zstrings == null) {
|
||||
// ICU's own array does not have entries for aliases
|
||||
tzid = ZoneMeta.getCanonicalID(tzid);
|
||||
zstrings = (ZoneStrings)tzidToStrings.get(tzid);
|
||||
String canonicalID = ZoneMeta.getCanonicalSystemID(tzid);
|
||||
if (canonicalID != null && !canonicalID.equals(tzid)) {
|
||||
// Canonicalize tzid here. The rest of operations
|
||||
// require tzid to be canonicalized.
|
||||
tzid = canonicalID;
|
||||
zstrings = (ZoneStrings)tzidToStrings.get(tzid);
|
||||
}
|
||||
}
|
||||
if (zstrings != null) {
|
||||
if (isShort) {
|
||||
@ -635,7 +645,6 @@ public class ZoneStringFormat {
|
||||
* Private method to get a generic partial location string
|
||||
*/
|
||||
private String getGenericPartialLocationString(String tzid, boolean isShort, long date, boolean commonlyUsedOnly) {
|
||||
tzid = ZoneMeta.getCanonicalID(tzid);
|
||||
String result = null;
|
||||
String mzid = ZoneMeta.getMetazoneID(tzid, date);
|
||||
if (mzid != null) {
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
*******************************************************************************
|
||||
* Copyright (C) 1996-2007, International Business Machines Corporation and *
|
||||
* Copyright (C) 1996-2008, International Business Machines Corporation and *
|
||||
* others. All Rights Reserved. *
|
||||
*******************************************************************************
|
||||
*/
|
||||
@ -1233,9 +1233,8 @@ public class DateFormatSymbols implements Serializable, Cloneable {
|
||||
*/
|
||||
private void initializeGMTFormat(ULocale desiredLocale) {
|
||||
// TimeZone format localization is not included in CalendarData
|
||||
try {
|
||||
gmtFormat = ZoneMeta.getTZLocalizationInfo(desiredLocale, ZoneMeta.GMT);
|
||||
} catch (MissingResourceException e) {
|
||||
gmtFormat = ZoneMeta.getTZLocalizationInfo(desiredLocale, ZoneMeta.GMT);
|
||||
if (gmtFormat == null) {
|
||||
gmtFormat = DEFAULT_GMT_PATTERN;
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* @(#)TimeZone.java 1.51 00/01/19
|
||||
*
|
||||
* Copyright (C) 1996-2007, International Business Machines
|
||||
* Copyright (C) 1996-2008, International Business Machines
|
||||
* Corporation and others. All Rights Reserved.
|
||||
*/
|
||||
|
||||
@ -786,6 +786,28 @@ abstract public class TimeZone implements Serializable, Cloneable {
|
||||
return TZDATA_VERSION;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the canonical system timezone ID or the normalized
|
||||
* custom time zone ID for the given time zone ID.
|
||||
* @param id The input timezone ID to be canonicalized.
|
||||
* @return The canonical system timezone ID or the custom timezone ID
|
||||
* in normalized format for the given timezone ID. When the given timezone ID
|
||||
* is neither a known system time zone ID nor a valid custom timezone ID,
|
||||
* null is returned.
|
||||
* @draft ICU 4.0
|
||||
* @provisional This API might change or be removed in a future release.
|
||||
*/
|
||||
public static String getCanonicalID(String id) {
|
||||
if (id == null || id.length() == 0) {
|
||||
return null;
|
||||
}
|
||||
String canonicalID = ZoneMeta.getCanonicalSystemID(id);
|
||||
if (canonicalID == null) {
|
||||
canonicalID = ZoneMeta.getCustomID(id);
|
||||
}
|
||||
return canonicalID;
|
||||
}
|
||||
|
||||
// =======================privates===============================
|
||||
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user