ICU-10934 The tz database abbreviaion support in ICU4J

X-SVN-Rev: 36081
This commit is contained in:
Yoshito Umaoka 2014-07-23 21:53:03 +00:00
parent ae3f6f13a4
commit a53477ee99
10 changed files with 747 additions and 39 deletions

1
.gitattributes vendored
View File

@ -263,6 +263,7 @@ icu4j/main/classes/core/.settings/edu.umd.cs.findbugs.core.prefs -text
icu4j/main/classes/core/.settings/org.eclipse.core.resources.prefs -text
icu4j/main/classes/core/.settings/org.eclipse.jdt.core.prefs -text
icu4j/main/classes/core/manifest.stub -text
icu4j/main/classes/core/src/com/ibm/icu/impl/TZDBTimeZoneNames.java -text
icu4j/main/classes/currdata/.externalToolBuilders/copy-data-currdata.launch -text
icu4j/main/classes/currdata/.settings/org.eclipse.core.resources.prefs -text
icu4j/main/classes/currdata/.settings/org.eclipse.jdt.core.prefs -text

View File

@ -0,0 +1,396 @@
/*
*******************************************************************************
* Copyright (C) 2014, International Business Machines Corporation and
* others. All Rights Reserved.
*******************************************************************************
*/
package com.ibm.icu.impl;
import java.util.Collection;
import java.util.Collections;
import java.util.EnumSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.MissingResourceException;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import com.ibm.icu.impl.TextTrieMap.ResultHandler;
import com.ibm.icu.text.TimeZoneNames;
import com.ibm.icu.util.ULocale;
import com.ibm.icu.util.UResourceBundle;
/**
* Yet another TimeZoneNames implementation based on the tz database.
* This implementation contains only tz abbreviations (short standard
* and daylight names) for each metazone.
*
* The data file $ICU4C_ROOT/source/data/zone/tzdbNames.txt contains
* the metazone - abbreviations mapping data (manually edited).
*
* Note: The abbreviations in the tz database are not necessarily
* unique. For example, parsing abbreviation "IST" is ambiguous
* (can be parsed as India Standard Time or Israel Standard Time).
* The data file (tzdbNames.txt) contains regional mapping, and
* the locale in the constructor is used as a hint for resolving
* these ambiguous names.
*/
public class TZDBTimeZoneNames extends TimeZoneNames {
private static final long serialVersionUID = 1L;
private static final ConcurrentHashMap<String, TZDBNames> TZDB_NAMES_MAP =
new ConcurrentHashMap<String, TZDBNames>();
private static volatile TextTrieMap<TZDBNameInfo> TZDB_NAMES_TRIE = null;
private static final ICUResourceBundle ZONESTRINGS;
static {
UResourceBundle bundle = ICUResourceBundle
.getBundleInstance(ICUResourceBundle.ICU_ZONE_BASE_NAME, "tzdbNames");
ZONESTRINGS = (ICUResourceBundle)bundle.get("zoneStrings");
}
private ULocale _locale;
private transient volatile String _region;
public TZDBTimeZoneNames(ULocale loc) {
_locale = loc;
}
/* (non-Javadoc)
* @see com.ibm.icu.text.TimeZoneNames#getAvailableMetaZoneIDs()
*/
@Override
public Set<String> getAvailableMetaZoneIDs() {
return TimeZoneNamesImpl._getAvailableMetaZoneIDs();
}
/* (non-Javadoc)
* @see com.ibm.icu.text.TimeZoneNames#getAvailableMetaZoneIDs(java.lang.String)
*/
@Override
public Set<String> getAvailableMetaZoneIDs(String tzID) {
return TimeZoneNamesImpl._getAvailableMetaZoneIDs(tzID);
}
/* (non-Javadoc)
* @see com.ibm.icu.text.TimeZoneNames#getMetaZoneID(java.lang.String, long)
*/
@Override
public String getMetaZoneID(String tzID, long date) {
return TimeZoneNamesImpl._getMetaZoneID(tzID, date);
}
/* (non-Javadoc)
* @see com.ibm.icu.text.TimeZoneNames#getReferenceZoneID(java.lang.String, java.lang.String)
*/
@Override
public String getReferenceZoneID(String mzID, String region) {
return TimeZoneNamesImpl._getReferenceZoneID(mzID, region);
}
/* (non-Javadoc)
* @see com.ibm.icu.text.TimeZoneNames#getMetaZoneDisplayName(java.lang.String,
* com.ibm.icu.text.TimeZoneNames.NameType)
*/
@Override
public String getMetaZoneDisplayName(String mzID, NameType type) {
if (mzID == null || mzID.length() == 0 ||
(type != NameType.SHORT_STANDARD && type != NameType.SHORT_DAYLIGHT)) {
return null;
}
return getMetaZoneNames(mzID).getName(type);
}
/* (non-Javadoc)
* @see com.ibm.icu.text.TimeZoneNames#getTimeZoneDisplayName(java.lang.String,
* com.ibm.icu.text.TimeZoneNames.NameType)
*/
@Override
public String getTimeZoneDisplayName(String tzID, NameType type) {
// No abbreviations associated a zone directly for now.
return null;
}
// /* (non-Javadoc)
// * @see com.ibm.icu.text.TimeZoneNames#getExemplarLocationName(java.lang.String)
// */
// public String getExemplarLocationName(String tzID) {
// return super.getExemplarLocationName(tzID);
// }
/* (non-Javadoc)
* @see com.ibm.icu.text.TimeZoneNames#find(java.lang.CharSequence, int, java.util.EnumSet)
*/
@Override
public Collection<MatchInfo> find(CharSequence text, int start, EnumSet<NameType> nameTypes) {
if (text == null || text.length() == 0 || start < 0 || start >= text.length()) {
throw new IllegalArgumentException("bad input text or range");
}
prepareFind();
TZDBNameSearchHandler handler = new TZDBNameSearchHandler(nameTypes, getTargetRegion());
TZDB_NAMES_TRIE.find(text, start, handler);
return handler.getMatches();
}
private static class TZDBNames {
public static final TZDBNames EMPTY_TZDBNAMES = new TZDBNames(null, null);
private String[] _names;
private String[] _parseRegions;
private static final String[] KEYS = {"ss", "sd"};
private TZDBNames(String[] names, String[] parseRegions) {
_names = names;
_parseRegions = parseRegions;
}
static TZDBNames getInstance(ICUResourceBundle zoneStrings, String key) {
if (zoneStrings == null || key == null || key.length() == 0) {
return EMPTY_TZDBNAMES;
}
ICUResourceBundle table = null;
try {
table = (ICUResourceBundle)zoneStrings.get(key);
} catch (MissingResourceException e) {
return EMPTY_TZDBNAMES;
}
boolean isEmpty = true;
String[] names = new String[KEYS.length];
for (int i = 0; i < names.length; i++) {
try {
names[i] = table.getString(KEYS[i]);
isEmpty = false;
} catch (MissingResourceException e) {
names[i] = null;
}
}
if (isEmpty) {
return EMPTY_TZDBNAMES;
}
String[] parseRegions = null;
try {
ICUResourceBundle regionsRes = (ICUResourceBundle)table.get("parseRegions");
if (regionsRes.getType() == UResourceBundle.STRING) {
parseRegions = new String[1];
parseRegions[0] = regionsRes.getString();
} else if (regionsRes.getType() == UResourceBundle.ARRAY) {
parseRegions = regionsRes.getStringArray();
}
} catch (MissingResourceException e) {
// fall through
}
return new TZDBNames(names, parseRegions);
}
String getName(NameType type) {
if (_names == null) {
return null;
}
String name = null;
switch (type) {
case SHORT_STANDARD:
name = _names[0];
break;
case SHORT_DAYLIGHT:
name = _names[1];
break;
}
return name;
}
String[] getParseRegions() {
return _parseRegions;
}
}
private static class TZDBNameInfo {
String mzID;
NameType type;
boolean ambiguousType;
String[] parseRegions;
}
private static class TZDBNameSearchHandler implements ResultHandler<TZDBNameInfo> {
private EnumSet<NameType> _nameTypes;
private Collection<MatchInfo> _matches;
private String _region;
TZDBNameSearchHandler(EnumSet<NameType> nameTypes, String region) {
_nameTypes = nameTypes;
assert region != null;
_region = region;
}
/* (non-Javadoc)
* @see com.ibm.icu.impl.TextTrieMap.ResultHandler#handlePrefixMatch(int,
* java.util.Iterator)
*/
public boolean handlePrefixMatch(int matchLength, Iterator<TZDBNameInfo> values) {
TZDBNameInfo match = null;
TZDBNameInfo defaultRegionMatch = null;
while (values.hasNext()) {
TZDBNameInfo ninfo = values.next();
if (_nameTypes != null && !_nameTypes.contains(ninfo.type)) {
continue;
}
// Some tz database abbreviations are ambiguous. For example,
// CST means either Central Standard Time or China Standard Time.
// Unlike CLDR time zone display names, this implementation
// does not use unique names. And TimeZoneFormat does not expect
// multiple results returned for the same time zone type.
// For this reason, this implementation resolve one among same
// zone type with a same name at this level.
if (ninfo.parseRegions == null) {
// parseRegions == null means this is the default metazone
// mapping for the abbreviation.
if (defaultRegionMatch == null) {
match = defaultRegionMatch = ninfo;
}
} else {
boolean matchRegion = false;
// non-default metazone mapping for an abbreviation
// comes with applicable regions. For example, the default
// metazone mapping for "CST" is America_Central,
// but if region is one of CN/MO/TW, "CST" is parsed
// as metazone China (China Standard Time).
for (String region : ninfo.parseRegions) {
if (_region.equals(region)) {
match = ninfo;
matchRegion = true;
break;
}
}
if (matchRegion) {
break;
}
if (match == null) {
match = ninfo;
}
}
}
if (match != null) {
NameType ntype = match.type;
// Note: Workaround for duplicated standard/daylight names
// The tz database contains a few zones sharing a
// same name for both standard time and daylight saving
// time. For example, Australia/Sydney observes DST,
// but "EST" is used for both standard and daylight.
// When both SHORT_STANDARD and SHORT_DAYLIGHT are included
// in the find operation, we cannot tell which one was
// actually matched.
// TimeZoneFormat#parse returns a matched name type (standard
// or daylight) and DateFormat implementation uses the info to
// to adjust actual time. To avoid false type information,
// this implementation replaces the name type with SHORT_GENERIC.
if (match.ambiguousType
&& (ntype == NameType.SHORT_STANDARD || ntype == NameType.SHORT_DAYLIGHT)
&& _nameTypes.contains(NameType.SHORT_STANDARD)
&& _nameTypes.contains(NameType.SHORT_DAYLIGHT)) {
ntype = NameType.SHORT_GENERIC;
}
MatchInfo minfo = new MatchInfo(ntype, null, match.mzID, matchLength);
if (_matches == null) {
_matches = new LinkedList<MatchInfo>();
}
_matches.add(minfo);
}
return true;
}
/**
* Returns the match results
* @return the match results
*/
public Collection<MatchInfo> getMatches() {
if (_matches == null) {
return Collections.emptyList();
}
return _matches;
}
}
private static TZDBNames getMetaZoneNames(String mzID) {
TZDBNames names = TZDB_NAMES_MAP.get(mzID);
if (names == null) {
names = TZDBNames.getInstance(ZONESTRINGS, "meta:" + mzID);
mzID = mzID.intern();
TZDBNames tmpNames = TZDB_NAMES_MAP.putIfAbsent(mzID, names);
names = (tmpNames == null) ? names : tmpNames;
}
return names;
}
private static void prepareFind() {
if (TZDB_NAMES_TRIE == null) {
synchronized(TZDBTimeZoneNames.class) {
if (TZDB_NAMES_TRIE == null) {
// loading all names into trie
TZDB_NAMES_TRIE = new TextTrieMap<TZDBNameInfo>(true);
Set<String> mzIDs = TimeZoneNamesImpl._getAvailableMetaZoneIDs();
for (String mzID : mzIDs) {
TZDBNames names = getMetaZoneNames(mzID);
String std = names.getName(NameType.SHORT_STANDARD);
String dst = names.getName(NameType.SHORT_DAYLIGHT);
if (std == null && dst == null) {
continue;
}
String[] parseRegions = names.getParseRegions();
mzID = mzID.intern();
// The tz database contains a few zones sharing a
// same name for both standard time and daylight saving
// time. For example, Australia/Sydney observes DST,
// but "EST" is used for both standard and daylight.
// we need to store the information for later processing.
boolean ambiguousType = (std != null && dst != null && std.equals(dst));
if (std != null) {
TZDBNameInfo stdInf = new TZDBNameInfo();
stdInf.mzID = mzID;
stdInf.type = NameType.SHORT_STANDARD;
stdInf.ambiguousType = ambiguousType;
stdInf.parseRegions = parseRegions;
TZDB_NAMES_TRIE.put(std, stdInf);
}
if (dst != null) {
TZDBNameInfo dstInf = new TZDBNameInfo();
dstInf.mzID = mzID;
dstInf.type = NameType.SHORT_DAYLIGHT;
dstInf.ambiguousType = ambiguousType;
dstInf.parseRegions = parseRegions;
TZDB_NAMES_TRIE.put(dst, dstInf);
}
}
}
}
}
}
private String getTargetRegion() {
if (_region == null) {
String region = _locale.getCountry();
if (region.length() == 0) {
ULocale tmp = ULocale.addLikelySubtags(_locale);
region = tmp.getCountry();
if (region.length() == 0) {
region = "001";
}
}
_region = region;
}
return _region;
}
}

View File

@ -1,6 +1,6 @@
/*
*******************************************************************************
* Copyright (C) 2011-2013, International Business Machines Corporation and *
* Copyright (C) 2011-2014, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*/
@ -41,7 +41,7 @@ public class TimeZoneNamesImpl extends TimeZoneNames {
private static final String ZONE_STRINGS_BUNDLE = "zoneStrings";
private static final String MZ_PREFIX = "meta:";
private static Set<String> METAZONE_IDS;
private static volatile Set<String> METAZONE_IDS;
private static final TZ2MZsCache TZ_TO_MZS_CACHE = new TZ2MZsCache();
private static final MZ2TZsCache MZ_TO_TZS_CACHE = new MZ2TZsCache();
@ -65,12 +65,20 @@ public class TimeZoneNamesImpl extends TimeZoneNames {
* @see com.ibm.icu.text.TimeZoneNames#getAvailableMetaZoneIDs()
*/
@Override
public synchronized Set<String> getAvailableMetaZoneIDs() {
public Set<String> getAvailableMetaZoneIDs() {
return _getAvailableMetaZoneIDs();
}
static Set<String> _getAvailableMetaZoneIDs() {
if (METAZONE_IDS == null) {
UResourceBundle bundle = UResourceBundle.getBundleInstance(ICUResourceBundle.ICU_BASE_NAME, "metaZones");
UResourceBundle mapTimezones = bundle.get("mapTimezones");
Set<String> keys = mapTimezones.keySet();
METAZONE_IDS = Collections.unmodifiableSet(keys);
synchronized (TimeZoneNamesImpl.class) {
if (METAZONE_IDS == null) {
UResourceBundle bundle = UResourceBundle.getBundleInstance(ICUResourceBundle.ICU_BASE_NAME, "metaZones");
UResourceBundle mapTimezones = bundle.get("mapTimezones");
Set<String> keys = mapTimezones.keySet();
METAZONE_IDS = Collections.unmodifiableSet(keys);
}
}
}
return METAZONE_IDS;
}
@ -80,6 +88,10 @@ public class TimeZoneNamesImpl extends TimeZoneNames {
*/
@Override
public Set<String> getAvailableMetaZoneIDs(String tzID) {
return _getAvailableMetaZoneIDs(tzID);
}
static Set<String> _getAvailableMetaZoneIDs(String tzID) {
if (tzID == null || tzID.length() == 0) {
return Collections.emptySet();
}
@ -100,6 +112,10 @@ public class TimeZoneNamesImpl extends TimeZoneNames {
*/
@Override
public String getMetaZoneID(String tzID, long date) {
return _getMetaZoneID(tzID, date);
}
static String _getMetaZoneID(String tzID, long date) {
if (tzID == null || tzID.length() == 0) {
return null;
}
@ -119,6 +135,10 @@ public class TimeZoneNamesImpl extends TimeZoneNames {
*/
@Override
public String getReferenceZoneID(String mzID, String region) {
return _getReferenceZoneID(mzID, region);
}
static String _getReferenceZoneID(String mzID, String region) {
if (mzID == null || mzID.length() == 0) {
return null;
}

View File

@ -30,6 +30,7 @@ import java.util.Set;
import com.ibm.icu.impl.ICUResourceBundle;
import com.ibm.icu.impl.SoftCache;
import com.ibm.icu.impl.TZDBTimeZoneNames;
import com.ibm.icu.impl.TextTrieMap;
import com.ibm.icu.impl.TimeZoneGenericNames;
import com.ibm.icu.impl.TimeZoneGenericNames.GenericMatchInfo;
@ -309,8 +310,17 @@ public class TimeZoneFormat extends UFormat implements Freezable<TimeZoneFormat>
* by other styles.
* @stable ICU 49
*/
ALL_STYLES;
}
ALL_STYLES,
/**
* When parsing a time zone display name in {@link Style#SPECIFIC_SHORT},
* look for the IANA tz database compatible zone abbreviations in addition
* to the localized names coming from the {@link TimeZoneNames} currently
* used by the {@link TimeZoneFormat}.
* @draft ICU 54
* @provisional This API might change or be removed in a future release.
*/
TZ_DATABASE_ABBREVIATIONS;
}
/*
* fields to be serialized
@ -322,6 +332,7 @@ public class TimeZoneFormat extends UFormat implements Freezable<TimeZoneFormat>
private String[] _gmtOffsetDigits;
private String _gmtZeroFormat;
private boolean _parseAllStyles;
private boolean _parseTZDBNames;
/*
* Transient fields
@ -338,6 +349,7 @@ public class TimeZoneFormat extends UFormat implements Freezable<TimeZoneFormat>
private transient boolean _frozen;
private transient volatile TimeZoneNames _tzdbNames;
/*
* Static final fields
@ -524,6 +536,23 @@ public class TimeZoneFormat extends UFormat implements Freezable<TimeZoneFormat>
return _gnames;
}
/**
* Private method returning the instance of TZDBTimeZoneNames.
* The instance if used only for parsing when {@link ParseOption#TZ_DATABASE_ABBREVIATIONS}
* is enabled.
* @return an instance of TZDBTimeZoneNames.
*/
private TimeZoneNames getTZDBTimeZoneNames() {
if (_tzdbNames == null) {
synchronized(this) {
if (_tzdbNames == null) {
_tzdbNames = new TZDBTimeZoneNames(_locale);
}
}
}
return _tzdbNames;
}
/**
* Sets the time zone display name data to this instance.
*
@ -699,8 +728,8 @@ public class TimeZoneFormat extends UFormat implements Freezable<TimeZoneFormat>
* @stable ICU 49
*/
public TimeZoneFormat setDefaultParseOptions(EnumSet<ParseOption> options) {
// Currently, only ALL_STYLES is supported
_parseAllStyles = options.contains(ParseOption.ALL_STYLES);
_parseTZDBNames = options.contains(ParseOption.TZ_DATABASE_ABBREVIATIONS);
return this;
}
@ -711,8 +740,12 @@ public class TimeZoneFormat extends UFormat implements Freezable<TimeZoneFormat>
* @stable ICU 49
*/
public EnumSet<ParseOption> getDefaultParseOptions() {
if (_parseAllStyles) {
if (_parseAllStyles && _parseTZDBNames) {
return EnumSet.of(ParseOption.ALL_STYLES, ParseOption.TZ_DATABASE_ABBREVIATIONS);
} else if (_parseAllStyles) {
return EnumSet.of(ParseOption.ALL_STYLES);
} else if (_parseTZDBNames) {
return EnumSet.of(ParseOption.TZ_DATABASE_ABBREVIATIONS);
}
return EnumSet.noneOf(ParseOption.class);
}
@ -1078,6 +1111,10 @@ public class TimeZoneFormat extends UFormat implements Freezable<TimeZoneFormat>
evaluated |= (Style.LOCALIZED_GMT.flag | Style.LOCALIZED_GMT_SHORT.flag);
}
boolean parseTZDBAbbrev = (options == null) ?
getDefaultParseOptions().contains(ParseOption.TZ_DATABASE_ABBREVIATIONS)
: options.contains(ParseOption.TZ_DATABASE_ABBREVIATIONS);
// Try the specified style
switch (style) {
case LOCALIZED_GMT:
@ -1173,6 +1210,28 @@ public class TimeZoneFormat extends UFormat implements Freezable<TimeZoneFormat>
return TimeZone.getTimeZone(getTimeZoneID(specificMatch.tzID(), specificMatch.mzID()));
}
}
if (parseTZDBAbbrev && style == Style.SPECIFIC_SHORT) {
assert nameTypes.contains(NameType.SHORT_STANDARD);
assert nameTypes.contains(NameType.SHORT_DAYLIGHT);
Collection<MatchInfo> tzdbNameMatches =
getTZDBTimeZoneNames().find(text, startIdx, nameTypes);
if (tzdbNameMatches != null) {
MatchInfo tzdbNameMatch = null;
for (MatchInfo match : tzdbNameMatches) {
if (startIdx + match.matchLength() > parsedPos) {
tzdbNameMatch = match;
parsedPos = startIdx + match.matchLength();
}
}
if (tzdbNameMatch != null) {
timeType.value = getTimeType(tzdbNameMatch.nameType());
pos.setIndex(parsedPos);
return TimeZone.getTimeZone(getTimeZoneID(tzdbNameMatch.tzID(), tzdbNameMatch.mzID()));
}
}
}
break;
}
case GENERIC_LONG:
@ -1367,7 +1426,27 @@ public class TimeZoneFormat extends UFormat implements Freezable<TimeZoneFormat>
parsedTimeType = getTimeType(specificMatch.nameType());
parsedOffset = UNKNOWN_OFFSET;
}
}
if (parseTZDBAbbrev && parsedPos < maxPos && (evaluated & Style.SPECIFIC_SHORT.flag) == 0) {
Collection<MatchInfo> tzdbNameMatches =
getTZDBTimeZoneNames().find(text, startIdx, ALL_SIMPLE_NAME_TYPES);
MatchInfo tzdbNameMatch = null;
int matchPos = -1;
if (tzdbNameMatches != null) {
for (MatchInfo match : tzdbNameMatches) {
if (startIdx + match.matchLength() > matchPos) {
tzdbNameMatch = match;
matchPos = startIdx + match.matchLength();
}
}
if (parsedPos < matchPos) {
parsedPos = matchPos;
parsedID = getTimeZoneID(tzdbNameMatch.tzID(), tzdbNameMatch.mzID());
parsedTimeType = getTimeType(tzdbNameMatch.nameType());
parsedOffset = UNKNOWN_OFFSET;
}
}
}
// Try generic names
if (parsedPos < maxPos) {

View File

@ -15,6 +15,7 @@ import java.util.Set;
import com.ibm.icu.impl.ICUConfig;
import com.ibm.icu.impl.SoftCache;
import com.ibm.icu.impl.TZDBTimeZoneNames;
import com.ibm.icu.impl.TimeZoneNamesImpl;
import com.ibm.icu.util.TimeZone;
import com.ibm.icu.util.ULocale;
@ -160,11 +161,11 @@ public abstract class TimeZoneNames implements Serializable {
}
/**
* Returns an instance of <code>TimeZoneDisplayNames</code> for the specified locale.
* Returns an instance of <code>TimeZoneNames</code> for the specified locale.
*
* @param locale
* The locale.
* @return An instance of <code>TimeZoneDisplayNames</code>
* @return An instance of <code>TimeZoneNames</code>
* @stable ICU 49
*/
public static TimeZoneNames getInstance(ULocale locale) {
@ -173,7 +174,7 @@ public abstract class TimeZoneNames implements Serializable {
}
/**
* Returns an instance of <code>TimeZoneDisplayNames</code> for the specified JDK locale.
* Returns an instance of <code>TimeZoneNames</code> for the specified JDK locale.
*
* @param locale
* The JDK locale.
@ -185,6 +186,22 @@ public abstract class TimeZoneNames implements Serializable {
return getInstance(ULocale.forLocale(locale));
}
/**
* Returns an instance of <code>TimeZoneNames</code> containing only short specific
* zone names ({@link NameType#SHORT_STANDARD} and {@link NameType#SHORT_DAYLIGHT}),
* compatible with the IANA tz database's zone abbreviations (not localized).
* <br>
* Note: The input locale is used for resolving ambiguous names (e.g. "IST" is parsed
* as Israel Standard Time for Israel, while it is parsed as India Standard Time for
* all other regions). The zone names returned by this instance are not localized.
*
* @draft ICU 54
* @provisional This API might change or be removed in a future release.
*/
public static TimeZoneNames getTZDBInstance(ULocale locale) {
return new TZDBTimeZoneNames(locale);
}
/**
* Returns an immutable set of all available meta zone IDs.
* @return An immutable set of all available meta zone IDs.

View File

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:df42e127c7c6127bce3a0a44577d33d8457fc073f5fa131f6916c039b374932c
size 10503267
oid sha256:3d46efbf5fced8f73fd8e352902259aa0ba4c89fdf9fcbee24862044a09c56b8
size 10505785

View File

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:33523d17a26aa17b47fafbd6242592cd070436cd988b32d67230612a31432ca8
oid sha256:d3137adf135a24c2bb8f5fcbbbdea86e07a79f3eb8f4dab3734e88afa7a2dc7a
size 91046

View File

@ -25,6 +25,7 @@ import com.ibm.icu.text.TimeZoneFormat;
import com.ibm.icu.text.TimeZoneFormat.ParseOption;
import com.ibm.icu.text.TimeZoneFormat.Style;
import com.ibm.icu.text.TimeZoneFormat.TimeType;
import com.ibm.icu.text.TimeZoneNames;
import com.ibm.icu.util.BasicTimeZone;
import com.ibm.icu.util.Calendar;
import com.ibm.icu.util.Output;
@ -498,25 +499,91 @@ public class TimeZoneFormatTest extends com.ibm.icu.dev.test.TestFmwk {
public void TestParse() {
final Object[][] DATA = {
// text inpos locale style parseAll? expected outpos time type
{"Z", 0, "en_US", Style.ISO_EXTENDED_FULL, false, "Etc/GMT", 1, TimeType.UNKNOWN},
{"Z", 0, "en_US", Style.SPECIFIC_LONG, false, "Etc/GMT", 1, TimeType.UNKNOWN},
{"Zambia time", 0, "en_US", Style.ISO_EXTENDED_FULL, true, "Etc/GMT", 1, TimeType.UNKNOWN},
{"Zambia time", 0, "en_US", Style.GENERIC_LOCATION, false, "Africa/Lusaka", 11, TimeType.UNKNOWN},
{"Zambia time", 0, "en_US", Style.ISO_BASIC_LOCAL_FULL, true, "Africa/Lusaka", 11, TimeType.UNKNOWN},
{"+00:00", 0, "en_US", Style.ISO_EXTENDED_FULL, false, "Etc/GMT", 6, TimeType.UNKNOWN},
{"-01:30:45", 0, "en_US", Style.ISO_EXTENDED_FULL, false, "GMT-01:30:45", 9, TimeType.UNKNOWN},
{"-7", 0, "en_US", Style.ISO_BASIC_LOCAL_FULL, false, "GMT-07:00", 2, TimeType.UNKNOWN},
{"-2222", 0, "en_US", Style.ISO_BASIC_LOCAL_FULL, false, "GMT-22:22", 5, TimeType.UNKNOWN},
{"-3333", 0, "en_US", Style.ISO_BASIC_LOCAL_FULL, false, "GMT-03:33", 4, TimeType.UNKNOWN},
{"XXX+01:30YYY", 3, "en_US", Style.LOCALIZED_GMT, false, "GMT+01:30", 9, TimeType.UNKNOWN},
{"GMT0", 0, "en_US", Style.SPECIFIC_SHORT, false, "Etc/GMT", 3, TimeType.UNKNOWN},
{"EST", 0, "en_US", Style.SPECIFIC_SHORT, false, "America/New_York", 3, TimeType.STANDARD},
{"ESTx", 0, "en_US", Style.SPECIFIC_SHORT, false, "America/New_York", 3, TimeType.STANDARD},
{"EDTx", 0, "en_US", Style.SPECIFIC_SHORT, false, "America/New_York", 3, TimeType.DAYLIGHT},
{"EST", 0, "en_US", Style.SPECIFIC_LONG, false, null, 0, TimeType.UNKNOWN},
{"EST", 0, "en_US", Style.SPECIFIC_LONG, true, "America/New_York", 3, TimeType.STANDARD},
{"EST", 0, "en_CA", Style.SPECIFIC_SHORT, false, "America/Toronto", 3, TimeType.STANDARD},
// text inpos locale style
// parseOptions expected outpos time type
{"Z", 0, "en_US", Style.ISO_EXTENDED_FULL,
null, "Etc/GMT", 1, TimeType.UNKNOWN},
{"Z", 0, "en_US", Style.SPECIFIC_LONG,
null, "Etc/GMT", 1, TimeType.UNKNOWN},
{"Zambia time", 0, "en_US", Style.ISO_EXTENDED_FULL,
EnumSet.of(ParseOption.ALL_STYLES), "Etc/GMT", 1, TimeType.UNKNOWN},
{"Zambia time", 0, "en_US", Style.GENERIC_LOCATION,
null, "Africa/Lusaka", 11, TimeType.UNKNOWN},
{"Zambia time", 0, "en_US", Style.ISO_BASIC_LOCAL_FULL,
EnumSet.of(ParseOption.ALL_STYLES), "Africa/Lusaka", 11, TimeType.UNKNOWN},
{"+00:00", 0, "en_US", Style.ISO_EXTENDED_FULL,
null, "Etc/GMT", 6, TimeType.UNKNOWN},
{"-01:30:45", 0, "en_US", Style.ISO_EXTENDED_FULL,
null, "GMT-01:30:45", 9, TimeType.UNKNOWN},
{"-7", 0, "en_US", Style.ISO_BASIC_LOCAL_FULL,
null, "GMT-07:00", 2, TimeType.UNKNOWN},
{"-2222", 0, "en_US", Style.ISO_BASIC_LOCAL_FULL,
null, "GMT-22:22", 5, TimeType.UNKNOWN},
{"-3333", 0, "en_US", Style.ISO_BASIC_LOCAL_FULL,
null, "GMT-03:33", 4, TimeType.UNKNOWN},
{"XXX+01:30YYY", 3, "en_US", Style.LOCALIZED_GMT,
null, "GMT+01:30", 9, TimeType.UNKNOWN},
{"GMT0", 0, "en_US", Style.SPECIFIC_SHORT,
null, "Etc/GMT", 3, TimeType.UNKNOWN},
{"EST", 0, "en_US", Style.SPECIFIC_SHORT,
null, "America/New_York", 3, TimeType.STANDARD},
{"ESTx", 0, "en_US", Style.SPECIFIC_SHORT,
null, "America/New_York", 3, TimeType.STANDARD},
{"EDTx", 0, "en_US", Style.SPECIFIC_SHORT,
null, "America/New_York", 3, TimeType.DAYLIGHT},
{"EST", 0, "en_US", Style.SPECIFIC_LONG,
null, null, 0, TimeType.UNKNOWN},
{"EST", 0, "en_US", Style.SPECIFIC_LONG,
EnumSet.of(ParseOption.ALL_STYLES), "America/New_York", 3, TimeType.STANDARD},
{"EST", 0, "en_CA", Style.SPECIFIC_SHORT,
null, "America/Toronto", 3, TimeType.STANDARD},
{"CST", 0, "en_US", Style.SPECIFIC_SHORT,
null, "America/Chicago", 3, TimeType.STANDARD},
{"CST", 0, "en_GB", Style.SPECIFIC_SHORT,
null, null, 0, TimeType.UNKNOWN},
{"CST", 0, "en_GB", Style.SPECIFIC_SHORT,
EnumSet.of(ParseOption.TZ_DATABASE_ABBREVIATIONS), "America/Chicago", 3, TimeType.STANDARD},
{"--CST--", 2, "en_GB", Style.SPECIFIC_SHORT,
EnumSet.of(ParseOption.TZ_DATABASE_ABBREVIATIONS), "America/Chicago", 5, TimeType.STANDARD},
{"CST", 0, "zh_CN", Style.SPECIFIC_SHORT,
EnumSet.of(ParseOption.TZ_DATABASE_ABBREVIATIONS), "Asia/Shanghai", 3, TimeType.STANDARD},
{"EST", 0, "en_AU", Style.SPECIFIC_SHORT,
EnumSet.of(ParseOption.TZ_DATABASE_ABBREVIATIONS), "Australia/Sydney", 3, TimeType.UNKNOWN},
{"AST", 0, "ar_SA", Style.SPECIFIC_SHORT,
EnumSet.of(ParseOption.TZ_DATABASE_ABBREVIATIONS), "Asia/Riyadh", 3, TimeType.STANDARD},
{"AQTST", 0, "en", Style.SPECIFIC_LONG,
null, null, 0, TimeType.UNKNOWN},
{"AQTST", 0, "en", Style.SPECIFIC_LONG,
EnumSet.of(ParseOption.ALL_STYLES), null, 0, TimeType.UNKNOWN},
{"AQTST", 0, "en", Style.SPECIFIC_LONG,
EnumSet.of(ParseOption.ALL_STYLES, ParseOption.TZ_DATABASE_ABBREVIATIONS), "Asia/Aqtobe", 5, TimeType.DAYLIGHT},
};
for (Object[] test : DATA) {
@ -524,7 +591,7 @@ public class TimeZoneFormatTest extends com.ibm.icu.dev.test.TestFmwk {
int inPos = (Integer)test[1];
ULocale loc = new ULocale((String)test[2]);
Style style = (Style)test[3];
EnumSet<ParseOption> options = (Boolean)test[4] ? EnumSet.of(ParseOption.ALL_STYLES) : null;
EnumSet<ParseOption> options = (EnumSet<ParseOption>)test[4];
String expID = (String)test[5];
int expPos = (Integer)test[6];
TimeType expType = (TimeType)test[7];
@ -798,4 +865,85 @@ public class TimeZoneFormatTest extends com.ibm.icu.dev.test.TestFmwk {
}
}
}
public void TestFormatTZDBNames() {
final Date dateJan = new Date(1358208000000L); // 2013-01-15T00:00:00Z
final Date dateJul = new Date(1373846400000L); // 2013-07-15T00:00:00Z
final Object[][] TESTDATA = {
{
"en",
"America/Chicago",
dateJan,
Style.SPECIFIC_SHORT,
"CST",
TimeType.STANDARD
},
{
"en",
"Asia/Shanghai",
dateJan,
Style.SPECIFIC_SHORT,
"CST",
TimeType.STANDARD
},
{
"zh_Hans",
"Asia/Shanghai",
dateJan,
Style.SPECIFIC_SHORT,
"CST",
TimeType.STANDARD
},
{
"en",
"America/Los_Angeles",
dateJul,
Style.SPECIFIC_LONG,
"GMT-07:00", // No long display names
TimeType.DAYLIGHT
},
{
"ja",
"America/Los_Angeles",
dateJul,
Style.SPECIFIC_SHORT,
"PDT",
TimeType.DAYLIGHT
},
{
"en",
"Australia/Sydney",
dateJan,
Style.SPECIFIC_SHORT,
"EST",
TimeType.DAYLIGHT
},
{
"en",
"Australia/Sydney",
dateJul,
Style.SPECIFIC_SHORT,
"EST",
TimeType.STANDARD
},
};
for (Object[] testCase : TESTDATA) {
ULocale loc = new ULocale((String)testCase[0]);
TimeZoneFormat tzfmt = TimeZoneFormat.getInstance(loc).cloneAsThawed();
TimeZoneNames tzdbNames = TimeZoneNames.getTZDBInstance(loc);
tzfmt.setTimeZoneNames(tzdbNames);
TimeZone tz = TimeZone.getTimeZone((String)testCase[1]);
Output<TimeType> timeType = new Output<TimeType>();
String out = tzfmt.format((Style)testCase[3], tz, ((Date)testCase[2]).getTime(), timeType);
if (!out.equals((String)testCase[4]) || timeType.value != testCase[5]) {
errln("Format result for [locale=" + testCase[0] + ",tzid=" + testCase[1] + ",date=" + testCase[2]
+ ",style=" + testCase[3] + "]: expected [output=" + testCase[4] + ",type=" + testCase[5]
+ "]; actual [output=" + out + ",type=" + timeType.value + "]");
}
}
}
}

View File

@ -1,6 +1,6 @@
/*
*******************************************************************************
* Copyright (c) 2004-2013, International Business Machines
* Copyright (c) 2004-2014, International Business Machines
* Corporation and others. All Rights Reserved.
*******************************************************************************
*
@ -13,6 +13,7 @@ import java.util.HashMap;
import java.util.Locale;
import com.ibm.icu.impl.DateNumberFormat;
import com.ibm.icu.impl.TZDBTimeZoneNames;
import com.ibm.icu.impl.TimeZoneGenericNames;
import com.ibm.icu.impl.TimeZoneGenericNames.GenericNameType;
import com.ibm.icu.impl.Utility;
@ -38,6 +39,7 @@ import com.ibm.icu.text.TimeUnitFormat;
import com.ibm.icu.text.TimeZoneFormat;
import com.ibm.icu.text.TimeZoneFormat.Style;
import com.ibm.icu.text.TimeZoneNames;
import com.ibm.icu.text.TimeZoneNames.NameType;
import com.ibm.icu.util.Calendar;
import com.ibm.icu.util.DateInterval;
import com.ibm.icu.util.GregorianCalendar;
@ -2297,6 +2299,50 @@ public class FormatTests
}
}
public static class TZDBTimeZoneNamesHandler implements SerializableTest.Handler {
public Object[] getTestObjects() {
return new Object[] {
TimeZoneNames.getTZDBInstance(ULocale.ENGLISH),
TimeZoneNames.getTZDBInstance(ULocale.JAPAN)
};
}
public boolean hasSameBehavior(Object a, Object b) {
TZDBTimeZoneNames tzdbna = (TZDBTimeZoneNames)a;
TZDBTimeZoneNames tzdbnb = (TZDBTimeZoneNames)b;
final String[] TZIDS = {
"America/Los_Angeles",
"America/Argentina/Buenos_Aires",
"Asia/Shanghai",
"Etc/GMT"
};
final long[] DATES = {
1277942400000L, // 2010-07-01 00:00:00 GMT
1293840000000L, // 2011-01-01 00:00:00 GMT
};
final NameType[] nTypes = {
NameType.SHORT_STANDARD,
NameType.SHORT_DAYLIGHT
};
for (String tzid : TZIDS) {
for (NameType nt : nTypes) {
for (long date : DATES) {
String nameA = tzdbna.getDisplayName(tzid, nt, date);
String nameB = tzdbnb.getDisplayName(tzid, nt, date);
if (!Utility.objectEquals(nameA, nameB)) {
return false;
}
}
}
}
return true;
}
}
public static class TimeZoneFormatHandler implements SerializableTest.Handler {
static final String CUSTOM_GMT_PATTERN = "Offset {0} from UTC";

View File

@ -736,6 +736,7 @@ public class SerializableTest extends TestFmwk.TestGroup
map.put("com.ibm.icu.impl.TimeZoneNamesImpl", new FormatTests.TimeZoneNamesHandler());
map.put("com.ibm.icu.text.TimeZoneFormat", new FormatTests.TimeZoneFormatHandler());
map.put("com.ibm.icu.impl.TimeZoneGenericNames", new FormatTests.TimeZoneGenericNamesHandler());
map.put("com.ibm.icu.impl.TZDBTimeZoneNames", new FormatTests.TZDBTimeZoneNamesHandler());
map.put("com.ibm.icu.util.Calendar", new CalendarTests.CalendarHandler());
map.put("com.ibm.icu.util.BuddhistCalendar", new CalendarTests.BuddhistCalendarHandler());