All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.ibm.icu.impl.ZoneMeta Maven / Gradle / Ivy

Go to download

International Component for Unicode for Java (ICU4J) is a mature, widely used Java library providing Unicode and Globalization support

There is a newer version: 76.1
Show newest version
// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
**********************************************************************
* Copyright (c) 2003-2016 International Business Machines
* Corporation and others.  All Rights Reserved.
**********************************************************************
* Author: Alan Liu
* Created: September 4 2003
* Since: ICU 2.8
**********************************************************************
*/
package com.ibm.icu.impl;

import java.lang.ref.SoftReference;
import java.text.ParsePosition;
import java.util.Collections;
import java.util.Locale;
import java.util.MissingResourceException;
import java.util.Set;
import java.util.TreeSet;

import com.ibm.icu.text.NumberFormat;
import com.ibm.icu.util.Output;
import com.ibm.icu.util.SimpleTimeZone;
import com.ibm.icu.util.TimeZone;
import com.ibm.icu.util.TimeZone.SystemTimeZoneType;
import com.ibm.icu.util.UResourceBundle;

/**
 * This class, not to be instantiated, implements the meta-data
 * missing from the underlying core JDK implementation of time zones.
 * There are two missing features: Obtaining a list of available zones
 * for a given country (as defined by the Olson database), and
 * obtaining a list of equivalent zones for a given zone (as defined
 * by Olson links).
 *
 * This class uses a data class, ZoneMetaData, which is created by the
 * tool tz2icu.
 *
 * @author Alan Liu
 * @since ICU 2.8
 */
public final class ZoneMeta {
    private static final boolean ASSERT = false;

    private static final String ZONEINFORESNAME = "zoneinfo64";
    private static final String kREGIONS  = "Regions";
    private static final String kZONES    = "Zones";
    private static final String kNAMES    = "Names";

    private static final String kGMT_ID   = "GMT";
    private static final String kCUSTOM_TZ_PREFIX = "GMT";

    private static final String kWorld = "001";

    private static SoftReference> REF_SYSTEM_ZONES;
    private static SoftReference> REF_CANONICAL_SYSTEM_ZONES;
    private static SoftReference> REF_CANONICAL_SYSTEM_LOCATION_ZONES;

    /**
     * Returns an immutable set of system time zone IDs.
     * Etc/Unknown is excluded.
     * @return An immutable set of system time zone IDs.
     */
    private static synchronized Set getSystemZIDs() {
        Set systemZones = null;
        if (REF_SYSTEM_ZONES != null) {
            systemZones = REF_SYSTEM_ZONES.get();
        }
        if (systemZones == null) {
            Set systemIDs = new TreeSet();
            String[] allIDs = getZoneIDs();
            for (String id : allIDs) {
                // exclude Etc/Unknown
                if (id.equals(TimeZone.UNKNOWN_ZONE_ID)) {
                    continue;
                }
                systemIDs.add(id);
            }
            systemZones = Collections.unmodifiableSet(systemIDs);
            REF_SYSTEM_ZONES = new SoftReference>(systemZones);
        }
        return systemZones;
    }

    /**
     * Returns an immutable set of canonical system time zone IDs.
     * The result set is a subset of {@link #getSystemZIDs()}, but not
     * including aliases, such as "US/Eastern".
     * @return An immutable set of canonical system time zone IDs.
     */
    private static synchronized Set getCanonicalSystemZIDs() {
        Set canonicalSystemZones = null;
        if (REF_CANONICAL_SYSTEM_ZONES != null) {
            canonicalSystemZones = REF_CANONICAL_SYSTEM_ZONES.get();
        }
        if (canonicalSystemZones == null) {
            Set canonicalSystemIDs = new TreeSet();
            String[] allIDs = getZoneIDs();
            for (String id : allIDs) {
                // exclude Etc/Unknown
                if (id.equals(TimeZone.UNKNOWN_ZONE_ID)) {
                    continue;
                }
                String canonicalID = getCanonicalCLDRID(id);
                if (id.equals(canonicalID)) {
                    canonicalSystemIDs.add(id);
                }
            }
            canonicalSystemZones = Collections.unmodifiableSet(canonicalSystemIDs);
            REF_CANONICAL_SYSTEM_ZONES = new SoftReference>(canonicalSystemZones);
        }
        return canonicalSystemZones;
    }

    /**
     * Returns an immutable set of canonical system time zone IDs that
     * are associated with actual locations.
     * The result set is a subset of {@link #getCanonicalSystemZIDs()}, but not
     * including IDs, such as "Etc/GTM+5".
     * @return An immutable set of canonical system time zone IDs that
     * are associated with actual locations.
     */
    private static synchronized Set getCanonicalSystemLocationZIDs() {
        Set canonicalSystemLocationZones = null;
        if (REF_CANONICAL_SYSTEM_LOCATION_ZONES != null) {
            canonicalSystemLocationZones = REF_CANONICAL_SYSTEM_LOCATION_ZONES.get();
        }
        if (canonicalSystemLocationZones == null) {
            Set canonicalSystemLocationIDs = new TreeSet();
            String[] allIDs = getZoneIDs();
            for (String id : allIDs) {
                // exclude Etc/Unknown
                if (id.equals(TimeZone.UNKNOWN_ZONE_ID)) {
                    continue;
                }
                String canonicalID = getCanonicalCLDRID(id);
                if (id.equals(canonicalID)) {
                    String region = getRegion(id);
                    if (region != null && !region.equals(kWorld)) {
                        canonicalSystemLocationIDs.add(id);
                    }
                }
            }
            canonicalSystemLocationZones = Collections.unmodifiableSet(canonicalSystemLocationIDs);
            REF_CANONICAL_SYSTEM_LOCATION_ZONES = new SoftReference>(canonicalSystemLocationZones);
        }
        return canonicalSystemLocationZones;
    }

    /**
     * Returns an immutable set of system IDs for the given conditions.
     * @param type      a system time zone type.
     * @param region    a region, or null.
     * @param rawOffset a zone raw offset or null.
     * @return An immutable set of system IDs for the given conditions.
     */
    public static Set getAvailableIDs(SystemTimeZoneType type, String region, Integer rawOffset) {
        Set baseSet = null;
        switch (type) {
        case ANY:
            baseSet = getSystemZIDs();
            break;
        case CANONICAL:
            baseSet = getCanonicalSystemZIDs();
            break;
        case CANONICAL_LOCATION:
            baseSet = getCanonicalSystemLocationZIDs();
            break;
        default:
            // never occur
            throw new IllegalArgumentException("Unknown SystemTimeZoneType");
        }

        if (region == null && rawOffset == null) {
            return baseSet;
        }

        if (region != null) {
            region = region.toUpperCase(Locale.ENGLISH);
        }

        // Filter by region/rawOffset
        Set result = new TreeSet();
        for (String id : baseSet) {
            if (region != null) {
                String r = getRegion(id);
                if (!region.equals(r)) {
                    continue;
                }
            }
            if (rawOffset != null) {
                // This is VERY inefficient.
                TimeZone z = getSystemTimeZone(id);
                if (z == null || !rawOffset.equals(z.getRawOffset())) {
                    continue;
                }
            }
            result.add(id);
        }
        if (result.isEmpty()) {
            return Collections.emptySet();
        }

        return Collections.unmodifiableSet(result);
    }

    /**
     * Returns the number of IDs in the equivalency group that
     * includes the given ID.  An equivalency group contains zones
     * that behave identically to the given zone.
     *
     * 

If there are no equivalent zones, then this method returns * 0. This means either the given ID is not a valid zone, or it * is and there are no other equivalent zones. * @param id a system time zone ID * @return the number of zones in the equivalency group containing * 'id', or zero if there are no equivalent zones. * @see #getEquivalentID */ public static synchronized int countEquivalentIDs(String id) { int count = 0; UResourceBundle res = openOlsonResource(null, id); if (res != null) { try { UResourceBundle links = res.get("links"); int[] v = links.getIntVector(); count = v.length; } catch (MissingResourceException ex) { // throw away } } return count; } /** * Returns an ID in the equivalency group that includes the given * ID. An equivalency group contains zones that behave * identically to the given zone. * *

The given index must be in the range 0..n-1, where n is the * value returned by countEquivalentIDs(id). For * some value of 'index', the returned value will be equal to the * given id. If the given id is not a valid system time zone, or * if 'index' is out of range, then returns an empty string. * @param id a system time zone ID * @param index a value from 0 to n-1, where n is the value * returned by countEquivalentIDs(id) * @return the ID of the index-th zone in the equivalency group * containing 'id', or an empty string if 'id' is not a valid * system ID or 'index' is out of range * @see #countEquivalentIDs */ public static synchronized String getEquivalentID(String id, int index) { String result = ""; if (index >= 0) { UResourceBundle res = openOlsonResource(null, id); if (res != null) { int zoneIdx = -1; try { UResourceBundle links = res.get("links"); int[] zones = links.getIntVector(); if (index < zones.length) { zoneIdx = zones[index]; } } catch (MissingResourceException ex) { // throw away } if (zoneIdx >= 0) { String tmp = getZoneID(zoneIdx); if (tmp != null) { result = tmp; } } } } return result; } private static String[] ZONEIDS = null; /* * ICU frequently refers the zone ID array in zoneinfo resource */ private static synchronized String[] getZoneIDs() { if (ZONEIDS == null) { try { UResourceBundle top = UResourceBundle.getBundleInstance( ICUData.ICU_BASE_NAME, ZONEINFORESNAME, ICUResourceBundle.ICU_DATA_CLASS_LOADER); ZONEIDS = top.getStringArray(kNAMES); } catch (MissingResourceException ex) { // throw away.. } } if (ZONEIDS == null) { ZONEIDS = new String[0]; } return ZONEIDS; } private static String getZoneID(int idx) { if (idx >= 0) { String[] ids = getZoneIDs(); if (idx < ids.length) { return ids[idx]; } } return null; } private static int getZoneIndex(String zid) { int zoneIdx = -1; String[] all = getZoneIDs(); if (all.length > 0) { int start = 0; int limit = all.length; int lastMid = Integer.MAX_VALUE; for (;;) { int mid = (start + limit) / 2; if (lastMid == mid) { /* Have we moved? */ break; /* We haven't moved, and it wasn't found. */ } lastMid = mid; int r = zid.compareTo(all[mid]); if (r == 0) { zoneIdx = mid; break; } else if(r < 0) { limit = mid; } else { start = mid; } } } return zoneIdx; } private static ICUCache CANONICAL_ID_CACHE = new SimpleCache(); private static ICUCache REGION_CACHE = new SimpleCache(); private static ICUCache SINGLE_COUNTRY_CACHE = new SimpleCache(); public static String getCanonicalCLDRID(TimeZone tz) { if (tz instanceof OlsonTimeZone) { return ((OlsonTimeZone)tz).getCanonicalID(); } return getCanonicalCLDRID(tz.getID()); } /** * Return the canonical id for this tzid defined by CLDR, which might be * the id itself. If the given tzid is not known, return null. * * Note: This internal API supports all known system IDs and "Etc/Unknown" (which is * NOT a system ID). */ public static String getCanonicalCLDRID(String tzid) { String canonical = CANONICAL_ID_CACHE.get(tzid); if (canonical == null) { canonical = findCLDRCanonicalID(tzid); if (canonical == null) { // Resolve Olson link and try it again if necessary try { int zoneIdx = getZoneIndex(tzid); if (zoneIdx >= 0) { UResourceBundle top = UResourceBundle.getBundleInstance(ICUData.ICU_BASE_NAME, ZONEINFORESNAME, ICUResourceBundle.ICU_DATA_CLASS_LOADER); UResourceBundle zones = top.get(kZONES); UResourceBundle zone = zones.get(zoneIdx); if (zone.getType() == UResourceBundle.INT) { // It's a link - resolve link and lookup tzid = getZoneID(zone.getInt()); canonical = findCLDRCanonicalID(tzid); } if (canonical == null) { canonical = tzid; } } } catch (MissingResourceException e) { // fall through } } if (canonical != null) { CANONICAL_ID_CACHE.put(tzid, canonical); } } return canonical; } private static String findCLDRCanonicalID(String tzid) { String canonical = null; String tzidKey = tzid.replace('/', ':'); try { // First, try check if the given ID is canonical UResourceBundle keyTypeData = UResourceBundle.getBundleInstance(ICUData.ICU_BASE_NAME, "keyTypeData", ICUResourceBundle.ICU_DATA_CLASS_LOADER); UResourceBundle typeMap = keyTypeData.get("typeMap"); UResourceBundle typeKeys = typeMap.get("timezone"); try { /* UResourceBundle canonicalEntry = */ typeKeys.get(tzidKey); // The given tzid is available in the canonical list canonical = tzid; } catch (MissingResourceException e) { // fall through } if (canonical == null) { // Try alias map UResourceBundle typeAlias = keyTypeData.get("typeAlias"); UResourceBundle aliasesForKey = typeAlias.get("timezone"); canonical = aliasesForKey.getString(tzidKey); } } catch (MissingResourceException e) { // fall through } return canonical; } /** * Return the region code for this tzid. * If tzid is not a system zone ID, this method returns null. */ public static String getRegion(String tzid) { String region = REGION_CACHE.get(tzid); if (region == null) { int zoneIdx = getZoneIndex(tzid); if (zoneIdx >= 0) { try { UResourceBundle top = UResourceBundle.getBundleInstance( ICUData.ICU_BASE_NAME, ZONEINFORESNAME, ICUResourceBundle.ICU_DATA_CLASS_LOADER); UResourceBundle regions = top.get(kREGIONS); if (zoneIdx < regions.getSize()) { region = regions.getString(zoneIdx); } } catch (MissingResourceException e) { // throw away } if (region != null) { REGION_CACHE.put(tzid, region); } } } return region; } /** * Return the canonical country code for this tzid. If we have none, or if the time zone * is not associated with a country or unknown, return null. */ public static String getCanonicalCountry(String tzid) { String country = getRegion(tzid); if (country != null && country.equals(kWorld)) { country = null; } return country; } /** * Return the canonical country code for this tzid. If we have none, or if the time zone * is not associated with a country or unknown, return null. When the given zone is the * primary zone of the country, true is set to isPrimary. */ public static String getCanonicalCountry(String tzid, Output isPrimary) { isPrimary.value = Boolean.FALSE; String country = getRegion(tzid); if (country != null && country.equals(kWorld)) { return null; } // Check the cache Boolean singleZone = SINGLE_COUNTRY_CACHE.get(tzid); if (singleZone == null) { Set ids = TimeZone.getAvailableIDs(SystemTimeZoneType.CANONICAL_LOCATION, country, null); assert(ids.size() >= 1); singleZone = Boolean.valueOf(ids.size() <= 1); SINGLE_COUNTRY_CACHE.put(tzid, singleZone); } if (singleZone) { isPrimary.value = Boolean.TRUE; } else { // Note: We may cache the primary zone map in future. // Even a country has multiple zones, one of them might be // dominant and treated as a primary zone. try { UResourceBundle bundle = UResourceBundle.getBundleInstance(ICUData.ICU_BASE_NAME, "metaZones"); UResourceBundle primaryZones = bundle.get("primaryZones"); String primaryZone = primaryZones.getString(country); if (tzid.equals(primaryZone)) { isPrimary.value = Boolean.TRUE; } else { // The given ID might not be a canonical ID String canonicalID = getCanonicalCLDRID(tzid); if (canonicalID != null && canonicalID.equals(primaryZone)) { isPrimary.value = Boolean.TRUE; } } } catch (MissingResourceException e) { // ignore } } return country; } /** * Given an ID and the top-level resource of the zoneinfo resource, * open the appropriate resource for the given time zone. * Dereference links if necessary. * @param top the top level resource of the zoneinfo resource or null. * @param id zone id * @return the corresponding zone resource or null if not found */ public static UResourceBundle openOlsonResource(UResourceBundle top, String id) { UResourceBundle res = null; int zoneIdx = getZoneIndex(id); if (zoneIdx >= 0) { try { if (top == null) { top = UResourceBundle.getBundleInstance( ICUData.ICU_BASE_NAME, ZONEINFORESNAME, ICUResourceBundle.ICU_DATA_CLASS_LOADER); } UResourceBundle zones = top.get(kZONES); UResourceBundle zone = zones.get(zoneIdx); if (zone.getType() == UResourceBundle.INT) { // resolve link zone = zones.get(zone.getInt()); } res = zone; } catch (MissingResourceException e) { res = null; } } return res; } /** * System time zone object cache */ private static class SystemTimeZoneCache extends SoftCache { /* (non-Javadoc) * @see com.ibm.icu.impl.CacheBase#createInstance(java.lang.Object, java.lang.Object) */ @Override protected OlsonTimeZone createInstance(String key, String data) { OlsonTimeZone tz = null; try { UResourceBundle top = UResourceBundle.getBundleInstance(ICUData.ICU_BASE_NAME, ZONEINFORESNAME, ICUResourceBundle.ICU_DATA_CLASS_LOADER); UResourceBundle res = openOlsonResource(top, data); if (res != null) { tz = new OlsonTimeZone(top, res, data); tz.freeze(); } } catch (MissingResourceException e) { // do nothing } return tz; } } private static final SystemTimeZoneCache SYSTEM_ZONE_CACHE = new SystemTimeZoneCache(); /** * Returns a frozen OlsonTimeZone instance for the given ID. * This method returns null when the given ID is unknown. */ public static OlsonTimeZone getSystemTimeZone(String id) { return SYSTEM_ZONE_CACHE.getInstance(id, id); } // Maximum value of valid custom time zone hour/min private static final int kMAX_CUSTOM_HOUR = 23; private static final int kMAX_CUSTOM_MIN = 59; private static final int kMAX_CUSTOM_SEC = 59; /** * Custom time zone object cache */ private static class CustomTimeZoneCache extends SoftCache { /* (non-Javadoc) * @see com.ibm.icu.impl.CacheBase#createInstance(java.lang.Object, java.lang.Object) */ @Override protected SimpleTimeZone createInstance(Integer key, int[] data) { assert (data.length == 4); assert (data[0] == 1 || data[0] == -1); assert (data[1] >= 0 && data[1] <= kMAX_CUSTOM_HOUR); assert (data[2] >= 0 && data[2] <= kMAX_CUSTOM_MIN); assert (data[3] >= 0 && data[3] <= kMAX_CUSTOM_SEC); String id = formatCustomID(data[1], data[2], data[3], data[0] < 0); int offset = data[0] * ((data[1] * 60 + data[2]) * 60 + data[3]) * 1000; SimpleTimeZone tz = new SimpleTimeZone(offset, id); tz.freeze(); return tz; } } private static final CustomTimeZoneCache CUSTOM_ZONE_CACHE = new CustomTimeZoneCache(); /** * Parse a custom time zone identifier and return a corresponding zone. * @param id a string of the form GMT[+-]hh:mm, GMT[+-]hhmm, or * GMT[+-]hh. * @return a frozen SimpleTimeZone with the given offset and * no Daylight Savings Time, or null if the id cannot be parsed. */ public static SimpleTimeZone getCustomTimeZone(String id){ int[] fields = new int[4]; if (parseCustomID(id, fields)) { // fields[0] - sign // fields[1] - hour / 5-bit // fields[2] - min / 6-bit // fields[3] - sec / 6-bit Integer key = Integer.valueOf( fields[0] * (fields[1] | fields[2] << 5 | fields[3] << 11)); return CUSTOM_ZONE_CACHE.getInstance(key, fields); } 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. */ static boolean parseCustomID(String id, int[] fields) { NumberFormat numberFormat = null; if (id != null && id.length() > kGMT_ID.length() && id.toUpperCase(Locale.ENGLISH).startsWith(kGMT_ID)) { ParsePosition pos = new ParsePosition(kGMT_ID.length()); int sign = 1; int hour = 0; int min = 0; int sec = 0; if (id.charAt(pos.getIndex()) == 0x002D /*'-'*/) { sign = -1; } else if (id.charAt(pos.getIndex()) != 0x002B /*'+'*/) { return false; } pos.setIndex(pos.getIndex() + 1); numberFormat = NumberFormat.getInstance(); numberFormat.setParseIntegerOnly(true); // Look for either hh:mm, hhmm, or hh int start = pos.getIndex(); Number n = numberFormat.parse(id, pos); if (pos.getIndex() == start) { return false; } hour = n.intValue(); if (pos.getIndex() < id.length()){ if (pos.getIndex() - start > 2 || id.charAt(pos.getIndex()) != 0x003A /*':'*/) { return false; } // hh:mm pos.setIndex(pos.getIndex() + 1); int oldPos = pos.getIndex(); n = numberFormat.parse(id, pos); if ((pos.getIndex() - oldPos) != 2) { // must be 2 digits return false; } min = n.intValue(); if (pos.getIndex() < id.length()) { if (id.charAt(pos.getIndex()) != 0x003A /*':'*/) { return false; } // [:ss] pos.setIndex(pos.getIndex() + 1); oldPos = pos.getIndex(); n = numberFormat.parse(id, pos); if (pos.getIndex() != id.length() || (pos.getIndex() - oldPos) != 2) { return false; } sec = n.intValue(); } } else { // Supported formats are below - // // HHmmss // Hmmss // HHmm // Hmm // HH // H int length = pos.getIndex() - start; if (length <= 0 || 6 < length) { // invalid length return false; } switch (length) { case 1: case 2: // already set to hour break; case 3: case 4: min = hour % 100; hour /= 100; break; case 5: case 6: sec = hour % 100; min = (hour/100) % 100; hour /= 10000; break; } } if (hour <= kMAX_CUSTOM_HOUR && min <= kMAX_CUSTOM_MIN && sec <= kMAX_CUSTOM_SEC) { if (fields != null) { if (fields.length >= 1) { fields[0] = sign; } if (fields.length >= 2) { fields[1] = hour; } if (fields.length >= 3) { fields[2] = min; } if (fields.length >= 4) { fields[3] = sec; } } return true; } } return false; } /** * Creates a custom zone for the offset * @param offset GMT offset in milliseconds * @return A custom TimeZone for the offset with normalized time zone id */ public static SimpleTimeZone getCustomTimeZone(int offset) { boolean negative = false; int tmp = offset; if (offset < 0) { negative = true; tmp = -offset; } int hour, min, sec; if (ASSERT) { Assert.assrt("millis!=0", tmp % 1000 != 0); } tmp /= 1000; sec = tmp % 60; tmp /= 60; min = tmp % 60; hour = tmp / 60; // Note: No millisecond part included in TZID for now String zid = formatCustomID(hour, min, sec, negative); return new SimpleTimeZone(offset, zid); } /* * Returns the normalized custom TimeZone ID */ static String formatCustomID(int hour, int min, int sec, boolean negative) { // Create normalized time zone ID - GMT[+|-]hh:mm[:ss] StringBuilder zid = new StringBuilder(kCUSTOM_TZ_PREFIX); if (hour != 0 || min != 0) { if(negative) { zid.append('-'); } else { zid.append('+'); } // Always use US-ASCII digits if (hour < 10) { zid.append('0'); } zid.append(hour); zid.append(':'); if (min < 10) { zid.append('0'); } zid.append(min); if (sec != 0) { // Optional second field zid.append(':'); if (sec < 10) { zid.append('0'); } zid.append(sec); } } return zid.toString(); } /** * Returns the time zone's short ID for the zone. * For example, "uslax" for zone "America/Los_Angeles". * @param tz the time zone * @return the short ID of the time zone, or null if the short ID is not available. */ public static String getShortID(TimeZone tz) { String canonicalID = null; if (tz instanceof OlsonTimeZone) { canonicalID = ((OlsonTimeZone)tz).getCanonicalID(); } else { canonicalID = getCanonicalCLDRID(tz.getID()); } if (canonicalID == null) { return null; } return getShortIDFromCanonical(canonicalID); } /** * Returns the time zone's short ID for the zone ID. * For example, "uslax" for zone ID "America/Los_Angeles". * @param id the time zone ID * @return the short ID of the time zone ID, or null if the short ID is not available. */ public static String getShortID(String id) { String canonicalID = getCanonicalCLDRID(id); if (canonicalID == null) { return null; } return getShortIDFromCanonical(canonicalID); } private static String getShortIDFromCanonical(String canonicalID) { String shortID = null; String tzidKey = canonicalID.replace('/', ':'); try { // First, try check if the given ID is canonical UResourceBundle keyTypeData = UResourceBundle.getBundleInstance(ICUData.ICU_BASE_NAME, "keyTypeData", ICUResourceBundle.ICU_DATA_CLASS_LOADER); UResourceBundle typeMap = keyTypeData.get("typeMap"); UResourceBundle typeKeys = typeMap.get("timezone"); shortID = typeKeys.getString(tzidKey); } catch (MissingResourceException e) { // fall through } return shortID; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy