diff --git a/icu4j/main/classes/core/src/com/ibm/icu/util/TimeZone.java b/icu4j/main/classes/core/src/com/ibm/icu/util/TimeZone.java index 217483967c..af7804a11c 100644 --- a/icu4j/main/classes/core/src/com/ibm/icu/util/TimeZone.java +++ b/icu4j/main/classes/core/src/com/ibm/icu/util/TimeZone.java @@ -16,6 +16,7 @@ import java.util.logging.Logger; import com.ibm.icu.impl.Grego; import com.ibm.icu.impl.ICUConfig; +import com.ibm.icu.impl.ICUResourceBundle; import com.ibm.icu.impl.JavaTimeZone; import com.ibm.icu.impl.TimeZoneAdapter; import com.ibm.icu.impl.ZoneMeta; @@ -1112,6 +1113,122 @@ abstract public class TimeZone implements Serializable, Cloneable, FreezableThere are system time zones that cannot be mapped to Windows zones. When the input + * system time zone ID is unknown or unmappable to a Windows time zone, then this + * method returns null. + * + *

This implementation utilizes + * Zone-Tzid mapping data. The mapping data is updated time to time. To get the latest changes, + * please read the ICU user guide section + * Updating the Time Zone Data. + * + * @param id A system time zone ID + * @return A Windows time zone ID mapped from the input system time zone ID, + * or null when the input ID is unknown or unmappable. + * @see #getIDForWindowsID(String, String) + * + * @draft ICU 52 + * @provisional This API might change or be removed in a future release. + */ + public static String getWindowsID(String id) { + // canonicalize the input ID + boolean[] isSystemID = {false}; + id = getCanonicalID(id, isSystemID); + if (!isSystemID[0]) { + // mapping data is only applicable to tz database IDs + return null; + } + + UResourceBundle top = UResourceBundle.getBundleInstance( + ICUResourceBundle.ICU_BASE_NAME, "windowsZones", ICUResourceBundle.ICU_DATA_CLASS_LOADER); + UResourceBundle mapTimezones = top.get("mapTimezones"); + + UResourceBundleIterator resitr = mapTimezones.getIterator(); + while (resitr.hasNext()) { + UResourceBundle winzone = resitr.next(); + if (winzone.getType() != UResourceBundle.TABLE) { + continue; + } + UResourceBundleIterator rgitr = winzone.getIterator(); + while (rgitr.hasNext()) { + UResourceBundle regionalData = rgitr.next(); + if (regionalData.getType() != UResourceBundle.STRING) { + continue; + } + String[] tzids = regionalData.getString().split(" "); + for (String tzid : tzids) { + if (tzid.equals(id)) { + return winzone.getKey(); + } + } + } + } + + return null; + } + + /** + * {@icu} Converts a Windows time zone ID to an equivalent system time zone ID + * for a region. For example, system time zone ID "America/Los_Angeles" is returned + * for input Windows ID "Pacific Standard Time" and region "US" (or null), + * "America/Vancouver" is returned for the same Windows ID "Pacific Standard Time" and + * region "CA". + * + *

Not all Windows time zones can be mapped to system time zones. When the input + * Windows time zone ID is unknown or unmappable to a system time zone, then this + * method returns null. + * + *

This implementation utilizes + * Zone-Tzid mapping data. The mapping data is updated time to time. To get the latest changes, + * please read the ICU user guide section + * Updating the Time Zone Data. + * + * @param winid A Windows time zone ID + * @param region A region code, or null if no regional preference. + * @return A system time zone ID mapped from the input Windows time zone ID, + * or null when the input ID is unknown or unmappable. + * @see #getWindowsID(String) + * + * @draft ICU 52 + * @provisional This API might change or be removed in a future release. + */ + public static String getIDForWindowsID(String winid, String region) { + String id = null; + + UResourceBundle top = UResourceBundle.getBundleInstance( + ICUResourceBundle.ICU_BASE_NAME, "windowsZones", ICUResourceBundle.ICU_DATA_CLASS_LOADER); + UResourceBundle mapTimezones = top.get("mapTimezones"); + + try { + UResourceBundle zones = mapTimezones.get(winid); + if (region != null) { + try { + id = zones.getString(region); + if (id != null) { + // first ID delimited by space is the default one + int endIdx = id.indexOf(' '); + if (endIdx > 0) { + id = id.substring(0, endIdx); + } + } + } catch (MissingResourceException e) { + // no explicit region mapping found + } + } + if (id == null) { + id = zones.getString("001"); + } + } catch (MissingResourceException e) { + // no mapping data found + } + + return id; + } + // Freezable stuffs /** diff --git a/icu4j/main/tests/core/src/com/ibm/icu/dev/test/timezone/TimeZoneTest.java b/icu4j/main/tests/core/src/com/ibm/icu/dev/test/timezone/TimeZoneTest.java index 8802254551..526bdf3208 100644 --- a/icu4j/main/tests/core/src/com/ibm/icu/dev/test/timezone/TimeZoneTest.java +++ b/icu4j/main/tests/core/src/com/ibm/icu/dev/test/timezone/TimeZoneTest.java @@ -2159,6 +2159,47 @@ public class TimeZoneTest extends TestFmwk } return rbtz; } + + public void TestGetWindowsID() { + String[][] TESTDATA = { + {"America/New_York", "Eastern Standard Time"}, + {"America/Montreal", "Eastern Standard Time"}, + {"America/Los_Angeles", "Pacific Standard Time"}, + {"America/Vancouver", "Pacific Standard Time"}, + {"Asia/Shanghai", "China Standard Time"}, + {"Asia/Chongqing", "China Standard Time"}, + {"America/Indianapolis", "US Eastern Standard Time"}, // CLDR canonical name + {"America/Indiana/Indianapolis", "US Eastern Standard Time"}, // tzdb canonical name + {"Asia/Khandyga", "Yakutsk Standard Time"}, + {"Australia/Eucla", null}, // No Windows ID mapping + {"Bogus", null}, + }; + + for (String[] data : TESTDATA) { + String winID = TimeZone.getWindowsID(data[0]); + assertEquals("Fail: ID=" + data[0], data[1], winID); + } + } + + public void TestGetIDForWindowsID() { + final String[][] TESTDATA = { + {"Eastern Standard Time", null, "America/New_York"}, + {"Eastern Standard Time", "US", "America/New_York"}, + {"Eastern Standard Time", "CA", "America/Toronto"}, + {"Eastern Standard Time", "CN", "America/New_York"}, + {"China Standard Time", null, "Asia/Shanghai"}, + {"China Standard Time", "CN", "Asia/Shanghai"}, + {"China Standard Time", "HK", "Asia/Hong_Kong"}, + {"Mid-Atlantic Standard Time", null, null}, // No tz database mapping + {"Bogus", null, null}, + }; + + for (String[] data : TESTDATA) { + String id = TimeZone.getIDForWindowsID(data[0], data[1]); + assertEquals("Fail: Windows ID=" + data[0] + ", Region=" + data[1], + data[2], id); + } + } } //eof