ICU-10934 The tz database abbreviation support in ICU4C

X-SVN-Rev: 36080
This commit is contained in:
Yoshito Umaoka 2014-07-23 21:51:09 +00:00
parent 133a0ebab9
commit ae3f6f13a4
13 changed files with 1732 additions and 40 deletions

1
.gitattributes vendored
View file

@ -70,6 +70,7 @@ icu4c/source/data/makedata.vcxproj -text
icu4c/source/data/makedata.vcxproj.filters -text
icu4c/source/data/region/pool.res -text
icu4c/source/data/zone/pool.res -text
icu4c/source/data/zone/tzdbNames.txt -text
icu4c/source/extra/uconv/uconv.vcxproj -text
icu4c/source/extra/uconv/uconv.vcxproj.filters -text
icu4c/source/i18n/i18n.vcxproj -text

View file

@ -322,7 +322,7 @@ REGION_SRC_FILES = $(REGION_SRC:%=$(REGIONSRCDIR)/%)
INSTALLED_REGION_FILES = $(REGION_SOURCE:%.txt=%) $(REGION_SOURCE_LOCAL:%.txt=%)
endif
ifdef ZONE_SOURCE
ZONE_SRC= root.txt $(ZONE_SOURCE) $(ZONE_ALIAS_SOURCE) $(ZONE_SOURCE_LOCAL)
ZONE_SRC= root.txt $(ZONE_SOURCE) $(ZONE_ALIAS_SOURCE) $(ZONE_SOURCE_LOCAL) tzdbNames.txt
ZONE_SRC_FILES = $(ZONE_SRC:%=$(ZONESRCDIR)/%)
INSTALLED_ZONE_FILES = $(ZONE_SOURCE:%.txt=%) $(ZONE_SOURCE_LOCAL:%.txt=%)
endif

View file

@ -116,5 +116,6 @@ ZONE_SOURCE = af.txt agq.txt ak.txt am.txt\
vai.txt vai_Latn.txt vai_Vaii.txt vi.txt vun.txt\
xog.txt yav.txt yo.txt zgh.txt zh.txt\
zh_Hans.txt zh_Hans_HK.txt zh_Hans_MO.txt zh_Hans_SG.txt zh_Hant.txt\
zh_Hant_HK.txt zh_Hant_MO.txt zu.txt
zh_Hant_HK.txt zh_Hant_MO.txt zu.txt\
tzdbNames.txt

View file

@ -0,0 +1,709 @@
// ***************************************************************************
// *
// * Copyright (C) 2014 International Business Machines
// * Corporation and others. All Rights Reserved.
// *
// * This file is manually edited for supporting the tz database name
// * compatibility.
// *
// ***************************************************************************#
tzdbNames{
zoneStrings{
"meta:Acre"{
sd{"ACST"}
ss{"ACT"}
}
"meta:Afghanistan"{
ss{"AFT"}
}
"meta:Africa_Central"{
sd{"CAST"}
ss{"CAT"}
}
"meta:Africa_Eastern"{
sd{"EAST"}
ss{"EAT"}
}
"meta:Africa_FarWestern"{
ss{"WAT"}
parseRegions{""} // this metazone is never used for parsing
}
"meta:Africa_Southern"{
ss{"SAST"}
}
"meta:Africa_Western"{
sd{"WAST"}
ss{"WAT"}
}
"meta:Aktyubinsk"{
sd{"AKTST"}
ss{"AKTT"}
}
"meta:Alaska"{
sd{"AKDT"}
ss{"AKST"}
}
"meta:Alaska_Hawaii"{
sd{"AHDT"}
ss{"AHST"}
}
"meta:Almaty"{
sd{"ALMST"}
ss{"ALMT"}
parseRegions{""} // this metazone is never used for parsing
}
"meta:Amazon"{
sd{"AMST"}
ss{"AMT"}
}
"meta:America_Central"{
sd{"CDT"}
ss{"CST"}
}
"meta:America_Eastern"{
sd{"EDT"}
ss{"EST"}
}
"meta:America_Mountain"{
sd{"MDT"}
ss{"MST"}
}
"meta:America_Pacific"{
sd{"PDT"}
ss{"PST"}
}
"meta:Anadyr"{
sd{"ANAST"}
ss{"ANAT"}
}
"meta:Aqtau"{
sd{"AQTST"}
ss{"AQTT"}
parseRegions{""} // this metazone is never used for parsing
}
"meta:Aqtobe"{
sd{"AQTST"}
ss{"AQTT"}
parseRegions{""} // this metazone is never used for parsing
}
"meta:Arabian"{
sd{"ADT"}
ss{"AST"}
parseRegions{"BH", "IQ", "KW", "QA", "SA", "YE"}
}
"meta:Argentina"{
sd{"ARST"}
ss{"ART"}
}
"meta:Argentina_Western"{
sd{"WARST"}
ss{"WART"}
}
"meta:Armenia"{
sd{"AMST"}
ss{"AMT"}
parseRegions{"AM"}
}
"meta:Ashkhabad"{
sd{"ASHST"}
ss{"ASHT"}
}
"meta:Atlantic"{
sd{"ADT"}
ss{"AST"}
}
"meta:Australia_Central"{
sd{"CST"}
ss{"CST"}
parseRegions{"AU"}
}
"meta:Australia_CentralWestern"{
sd{"CWST"}
ss{"CWST"}
}
"meta:Australia_Eastern"{
sd{"EST"}
ss{"EST"}
parseRegions{"AU"}
}
"meta:Australia_Western"{
sd{"WST"}
ss{"WST"}
}
"meta:Azerbaijan"{
sd{"AZT"}
ss{"AZST"}
}
"meta:Azores"{
sd{"AZOST"}
ss{"AZOT"}
}
"meta:Baku"{
sd{"BAKST"}
ss{"BAKT"}
}
"meta:Bangladesh"{
sd{"BDST"}
ss{"BDT"}
}
"meta:Bering"{
sd{"BDT"}
ss{"BST"}
parseRegions{""} // this metazone is never used for parsing
}
"meta:Bhutan"{
ss{"BTT"}
}
"meta:Bolivia"{
ss{"BOT"}
}
"meta:Borneo"{
ss{"BORT"}
}
"meta:Brasilia"{
sd{"BRST"}
ss{"BRT"}
}
"meta:British"{
sd{"BST"}
parseRegions{""} // this metazone is never used for parsing
}
"meta:Brunei"{
ss{"BNT"}
}
"meta:Cape_Verde"{
sd{"CVST"}
ss{"CVT"}
}
"meta:Casey"{
ss{"CAST"}
parseRegions{"AQ"}
}
"meta:Chamorro"{
ss{"ChST"}
}
"meta:Changbai"{
ss{"CHAT"}
}
"meta:Chatham"{
sd{"CHAST"}
ss{"CHADT"}
}
"meta:Chile"{
sd{"CLST"}
ss{"CLT"}
}
"meta:China"{
sd{"CDT"}
ss{"CST"}
parseRegions{"CN", "MO", "TW"}
}
"meta:Choibalsan"{
sd{"CHOST"}
ss{"CHOT"}
}
"meta:Christmas"{
ss{"CXT"}
}
"meta:Cocos"{
ss{"CCT"}
}
"meta:Colombia"{
sd{"COST"}
ss{"COT"}
}
"meta:Cook"{
sd{"CKHST"}
ss{"CKT"}
}
"meta:Cuba"{
sd{"CDT"}
ss{"CST"}
parseRegions{"CU"}
}
"meta:Dacca"{
ss{"DACT"}
}
"meta:Davis"{
ss{"DAVT"}
}
"meta:Dominican"{
sd{"EHDT"}
ss{"EST"}
}
"meta:DumontDUrville"{
ss{"DDUT"}
}
"meta:Dushanbe"{
sd{"DUSST"}
ss{"DUST"}
}
"meta:Dutch_Guiana"{
ss{"NEGT"}
}
"meta:East_Timor"{
ss{"TLT"}
}
"meta:Easter"{
sd{"EASST"}
ss{"EAST"}
parseRegions{"CL"}
}
"meta:Ecuador"{
ss{"ECT"}
}
"meta:Europe_Central"{
sd{"CEST"}
ss{"CET"}
}
"meta:Europe_Eastern"{
sd{"EEST"}
ss{"EET"}
}
"meta:Europe_Western"{
sd{"WEST"}
ss{"WET"}
}
"meta:Falkland"{
ss{"FKST"}
}
"meta:Fiji"{
sd{"FJST"}
ss{"FJT"}
}
"meta:French_Guiana"{
ss{"GFT"}
}
"meta:French_Southern"{
ss{"TFT"}
}
"meta:Frunze"{
sd{"FRUST"}
ss{"FRUT"}
}
"meta:GMT"{
ss{"GMT"}
}
"meta:Galapagos"{
ss{"GALT"}
}
"meta:Gambier"{
ss{"GAMT"}
}
"meta:Georgia"{
sd{"GEST"}
ss{"GET"}
}
"meta:Gilbert_Islands"{
ss{"GILT"}
}
"meta:Goose_Bay"{
sd{"ADT"}
ss{"AST"}
parseRegions{"CA"}
}
"meta:Greenland_Central"{
sd{"CGST"}
ss{"CGT"}
}
"meta:Greenland_Eastern"{
sd{"EGST"}
ss{"EGT"}
}
"meta:Greenland_Western"{
sd{"WGST"}
ss{"WGT"}
}
"meta:Guam"{
ss{"GST"}
parseRegions{""} // this metazone is never used for parsing
}
"meta:Gulf"{
ss{"GST"}
}
"meta:Guyana"{
ss{"GYT"}
}
"meta:Hawaii_Aleutian"{
sd{"HDT"}
ss{"HST"}
}
"meta:Hong_Kong"{
sd{"HKST"}
ss{"HKT"}
}
"meta:Hovd"{
sd{"HOVST"}
ss{"HOVT"}
}
"meta:India"{
ss{"IST"}
}
"meta:Indian_Ocean"{
ss{"IOT"}
}
"meta:Indochina"{
ss{"ICT"}
}
"meta:Indonesia_Central"{
ss{"WITA"}
}
"meta:Indonesia_Eastern"{
ss{"WIT"}
}
"meta:Indonesia_Western"{
ss{"WIB"}
}
"meta:Iran"{
sd{"IRDT"}
ss{"IRST"}
}
"meta:Irkutsk"{
sd{"IRKST"}
ss{"IRKT"}
}
"meta:Israel"{
sd{"IDT"}
ss{"IST"}
parseRegions{"IL", "PS"}
}
"meta:Japan"{
sd{"JDT"}
ss{"JST"}
}
"meta:Kamchatka"{
sd{"PETST"}
ss{"PETT"}
}
"meta:Karachi"{
ss{"KART"}
}
"meta:Kashgar"{
ss{"KAST"}
}
"meta:Kazakhstan_Eastern"{
sd{"ALMST"}
ss{"ALMT"}
}
"meta:Kazakhstan_Western"{
sd{"AQTST"}
ss{"AQTT"}
}
"meta:Kizilorda"{
sd{"KIZST"}
ss{"KIZT"}
}
"meta:Korea"{
sd{"KDT"}
ss{"KST"}
}
"meta:Kosrae"{
ss{"KOST"}
}
"meta:Krasnoyarsk"{
sd{"KRAST"}
ss{"KRAT"}
}
"meta:Kuybyshev"{
sd{"KUYST"}
ss{"KUYT"}
}
"meta:Kwajalein"{
ss{"KWAT"}
}
"meta:Kyrgystan"{
sd{"KGST"}
ss{"KGT"}
}
"meta:Lanka"{
ss{"LKT"}
}
"meta:Liberia"{
ss{"LRT"}
}
"meta:Line_Islands"{
ss{"LINT"}
}
"meta:Long_Shu"{
ss{"LONT"}
}
"meta:Lord_Howe"{
ss{"LHST"}
}
"meta:Macau"{
sd{"MOST"}
ss{"MOT"}
}
"meta:Macquarie"{
ss{"MIST"}
}
"meta:Magadan"{
sd{"MAGST"}
ss{"MAGT"}
}
"meta:Malaya"{
ss{"MALT"}
}
"meta:Malaysia"{
ss{"MYT"}
}
"meta:Maldives"{
ss{"MVT"}
}
"meta:Marquesas"{
ss{"MART"}
}
"meta:Marshall_Islands"{
ss{"MHT"}
}
"meta:Mauritius"{
sd{"MUST"}
ss{"MUT"}
}
"meta:Mawson"{
ss{"MAWT"}
}
"meta:Mexico_Northwest"{
sd{"PDT"}
ss{"PST"}
}
"meta:Mexico_Pacific"{
sd{"MDT"}
ss{"MST"}
parseRegions{"MX"}
}
"meta:Mongolia"{
sd{"ULAST"}
ss{"ULAT"}
}
"meta:Moscow"{
sd{"MSD"}
ss{"MSK"}
}
"meta:Myanmar"{
ss{"MMT"}
}
"meta:Nauru"{
ss{"NRT"}
}
"meta:Nepal"{
ss{"NPT"}
}
"meta:New_Caledonia"{
sd{"NCST"}
ss{"NCT"}
}
"meta:New_Zealand"{
sd{"NZDT"}
ss{"NZST"}
}
"meta:Newfoundland"{
sd{"NDT"}
ss{"NST"}
}
"meta:Niue"{
ss{"NUT"}
}
"meta:Norfolk"{
ss{"NFT"}
}
"meta:Noronha"{
sd{"FNST"}
ss{"FNT"}
}
"meta:North_Mariana"{
ss{"MPT"}
}
"meta:Novosibirsk"{
sd{"NOVST"}
ss{"NOVT"}
}
"meta:Omsk"{
sd{"OMSST"}
ss{"OMST"}
}
"meta:Oral"{
sd{"ORAST"}
ss{"ORAT"}
}
"meta:Pakistan"{
sd{"PKST"}
ss{"PKT"}
}
"meta:Palau"{
ss{"PWT"}
}
"meta:Papua_New_Guinea"{
ss{"PGT"}
}
"meta:Paraguay"{
sd{"PYST"}
ss{"PYT"}
}
"meta:Peru"{
sd{"PEST"}
ss{"PET"}
}
"meta:Philippines"{
sd{"PHST"}
ss{"PHT"}
}
"meta:Phoenix_Islands"{
ss{"PHOT"}
}
"meta:Pierre_Miquelon"{
sd{"PMDT"}
ss{"PMST"}
}
"meta:Pitcairn"{
ss{"PST"}
parseRegions{"PN"}
}
"meta:Ponape"{
ss{"PONT"}
}
"meta:Qyzylorda"{
sd{"QYZST"}
ss{"QYZT"}
}
"meta:Reunion"{
ss{"RET"}
}
"meta:Rothera"{
ss{"ROTT"}
}
"meta:Sakhalin"{
sd{"SAKST"}
ss{"SAKT"}
}
"meta:Samara"{
sd{"SAMST"}
ss{"SAMT"}
}
"meta:Samarkand"{
sd{"SAMST"}
ss{"SAMT"}
parseRegions{"UZ"}
}
"meta:Samoa"{
ss{"SST"}
}
"meta:Seychelles"{
ss{"SCT"}
}
"meta:Shevchenko"{
sd{"SHEST"}
ss{"SHET"}
}
"meta:Singapore"{
ss{"SGT"}
}
"meta:Solomon"{
ss{"SBT"}
}
"meta:South_Georgia"{
ss{"GST"}
parseRegions{"GS"}
}
"meta:Suriname"{
ss{"SRT"}
}
"meta:Syowa"{
ss{"SYOT"}
}
"meta:Tahiti"{
ss{"TAHT"}
}
"meta:Taipei"{
sd{"CDT"}
ss{"CST"}
}
"meta:Tajikistan"{
ss{"TJT"}
}
"meta:Tashkent"{
sd{"TASST"}
ss{"TAST"}
}
"meta:Tbilisi"{
sd{"TBIST"}
ss{"TBIT"}
}
"meta:Tokelau"{
ss{"TKT"}
}
"meta:Tonga"{
sd{"TOST"}
ss{"TOT"}
}
"meta:Truk"{
ss{"CHUT"}
}
"meta:Turkey"{
sd{"TRST"}
ss{"TRT"}
}
"meta:Turkmenistan"{
sd{"TMST"}
ss{"TMT"}
}
"meta:Tuvalu"{
ss{"TVT"}
}
"meta:Uralsk"{
sd{"URAST"}
ss{"URAT"}
}
"meta:Uruguay"{
sd{"UYST"}
ss{"UYT"}
}
"meta:Urumqi"{
ss{"URUT"}
}
"meta:Uzbekistan"{
sd{"UZST"}
ss{"UZT"}
}
"meta:Vanuatu"{
sd{"VUST"}
ss{"VUT"}
}
"meta:Venezuela"{
ss{"VET"}
}
"meta:Vladivostok"{
sd{"VLAST"}
ss{"VLAT"}
}
"meta:Volgograd"{
sd{"VOLST"}
ss{"VOLT"}
}
"meta:Vostok"{
ss{"VOST"}
}
"meta:Wake"{
ss{"WAKT"}
}
"meta:Wallis"{
ss{"WFT"}
}
"meta:Yakutsk"{
sd{"YAKST"}
ss{"YAKT"}
}
"meta:Yekaterinburg"{
sd{"YEKST"}
ss{"YEKT"}
}
"meta:Yerevan"{
sd{"YERST"}
ss{"YERT"}
}
"meta:Yukon"{
sd{"YDT"}
ss{"YST"}
}
}
}

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.
*******************************************************************************
*/
@ -308,7 +308,8 @@ U_CDECL_END
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(TimeZoneFormat)
TimeZoneFormat::TimeZoneFormat(const Locale& locale, UErrorCode& status)
: fLocale(locale), fTimeZoneNames(NULL), fTimeZoneGenericNames(NULL), fDefParseOptionFlags(0) {
: fLocale(locale), fTimeZoneNames(NULL), fTimeZoneGenericNames(NULL),
fDefParseOptionFlags(0), fTZDBTimeZoneNames(NULL) {
for (int32_t i = 0; i < UTZFMT_PAT_COUNT; i++) {
fGMTOffsetPatternItems[i] = NULL;
@ -418,6 +419,7 @@ TimeZoneFormat::TimeZoneFormat(const TimeZoneFormat& other)
TimeZoneFormat::~TimeZoneFormat() {
delete fTimeZoneNames;
delete fTimeZoneGenericNames;
delete fTZDBTimeZoneNames;
for (int32_t i = 0; i < UTZFMT_PAT_COUNT; i++) {
delete fGMTOffsetPatternItems[i];
}
@ -846,6 +848,8 @@ TimeZoneFormat::parse(UTimeZoneFormatStyle style, const UnicodeString& text, Par
UErrorCode status = U_ZERO_ERROR;
UnicodeString tzID;
UBool parseTZDBAbbrev = ((parseOptions & UTZFMT_PARSE_OPTION_TZ_DATABASE_ABBREVIATIONS) != 0);
// Try the specified style
switch (style) {
case UTZFMT_STYLE_LOCALIZED_GMT:
@ -956,6 +960,41 @@ TimeZoneFormat::parse(UTimeZoneFormatStyle style, const UnicodeString& text, Par
return TimeZone::createTimeZone(tzID);
}
}
if (parseTZDBAbbrev && style == UTZFMT_STYLE_SPECIFIC_SHORT) {
U_ASSERT((nameTypes & UTZNM_SHORT_STANDARD) != 0);
U_ASSERT((nameTypes & UTZNM_SHORT_DAYLIGHT) != 0);
const TZDBTimeZoneNames *tzdbTimeZoneNames = getTZDBTimeZoneNames(status);
if (U_SUCCESS(status)) {
LocalPointer<TimeZoneNames::MatchInfoCollection> tzdbNameMatches(
tzdbTimeZoneNames->find(text, startIdx, nameTypes, status));
if (U_FAILURE(status)) {
pos.setErrorIndex(startIdx);
return NULL;
}
if (!tzdbNameMatches.isNull()) {
int32_t matchIdx = -1;
int32_t matchPos = -1;
for (int32_t i = 0; i < tzdbNameMatches->size(); i++) {
matchPos = startIdx + tzdbNameMatches->getMatchLengthAt(i);
if (matchPos > parsedPos) {
matchIdx = i;
parsedPos = matchPos;
}
}
if (matchIdx >= 0) {
if (timeType) {
*timeType = getTimeType(tzdbNameMatches->getNameTypeAt(matchIdx));
}
pos.setIndex(matchPos);
getTimeZoneID(tzdbNameMatches.getAlias(), matchIdx, tzID);
U_ASSERT(!tzID.isEmpty());
return TimeZone::createTimeZone(tzID);
}
}
}
}
break;
}
case UTZFMT_STYLE_GENERIC_LONG:
@ -1168,6 +1207,34 @@ TimeZoneFormat::parse(UTimeZoneFormatStyle style, const UnicodeString& text, Par
parsedOffset = UNKNOWN_OFFSET;
}
}
if (parseTZDBAbbrev && parsedPos < maxPos && (evaluated & STYLE_PARSE_FLAGS[UTZFMT_STYLE_SPECIFIC_SHORT]) == 0) {
const TZDBTimeZoneNames *tzdbTimeZoneNames = getTZDBTimeZoneNames(status);
if (U_SUCCESS(status)) {
LocalPointer<TimeZoneNames::MatchInfoCollection> tzdbNameMatches(
tzdbTimeZoneNames->find(text, startIdx, ALL_SIMPLE_NAME_TYPES, status));
if (U_FAILURE(status)) {
pos.setErrorIndex(startIdx);
return NULL;
}
int32_t tzdbNameMatchIdx = -1;
int32_t matchPos = -1;
if (!tzdbNameMatches.isNull()) {
for (int32_t i = 0; i < tzdbNameMatches->size(); i++) {
if (startIdx + tzdbNameMatches->getMatchLengthAt(i) > matchPos) {
tzdbNameMatchIdx = i;
matchPos = startIdx + tzdbNameMatches->getMatchLengthAt(i);
}
}
}
if (parsedPos < matchPos) {
U_ASSERT(tzdbNameMatchIdx >= 0);
parsedPos = matchPos;
getTimeZoneID(tzdbNameMatches.getAlias(), tzdbNameMatchIdx, parsedID);
parsedTimeType = getTimeType(tzdbNameMatches->getNameTypeAt(tzdbNameMatchIdx));
parsedOffset = UNKNOWN_OFFSET;
}
}
}
// Try generic names
if (parsedPos < maxPos) {
int32_t genMatchLen = -1;
@ -1182,7 +1249,7 @@ TimeZoneFormat::parse(UTimeZoneFormatStyle style, const UnicodeString& text, Par
return NULL;
}
if (parsedPos < startIdx + genMatchLen) {
if (genMatchLen > 0 && parsedPos < startIdx + genMatchLen) {
parsedPos = startIdx + genMatchLen;
parsedID.setTo(tzID);
parsedTimeType = tt;
@ -1313,6 +1380,27 @@ TimeZoneFormat::getTimeZoneGenericNames(UErrorCode& status) const {
return fTimeZoneGenericNames;
}
const TZDBTimeZoneNames*
TimeZoneFormat::getTZDBTimeZoneNames(UErrorCode& status) const {
if (U_FAILURE(status)) {
return NULL;
}
umtx_lock(&gLock);
if (fTZDBTimeZoneNames == NULL) {
TZDBTimeZoneNames *tzdbNames = new TZDBTimeZoneNames(fLocale);
if (tzdbNames == NULL) {
status = U_MEMORY_ALLOCATION_ERROR;
} else {
TimeZoneFormat *nonConstThis = const_cast<TimeZoneFormat *>(this);
nonConstThis->fTZDBTimeZoneNames = tzdbNames;
}
}
umtx_unlock(&gLock);
return fTZDBTimeZoneNames;
}
UnicodeString&
TimeZoneFormat::formatExemplarLocation(const TimeZone& tz, UnicodeString& name) const {
UnicodeString location;
@ -2576,9 +2664,8 @@ TimeZoneFormat::getTimeType(UTimeZoneNameType nameType) {
return UTZFMT_TIME_TYPE_DAYLIGHT;
default:
U_ASSERT(FALSE);
return UTZFMT_TIME_TYPE_UNKNOWN;
}
return UTZFMT_TIME_TYPE_UNKNOWN;
}
UnicodeString&

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. *
*******************************************************************************
*/
@ -291,9 +291,30 @@ TimeZoneNames::~TimeZoneNames() {
TimeZoneNames*
TimeZoneNames::createInstance(const Locale& locale, UErrorCode& status) {
return new TimeZoneNamesDelegate(locale, status);
TimeZoneNames *instance = NULL;
if (U_SUCCESS(status)) {
instance = new TimeZoneNamesDelegate(locale, status);
if (instance == NULL && U_SUCCESS(status)) {
status = U_MEMORY_ALLOCATION_ERROR;
}
}
return instance;
}
#ifndef U_HIDE_DRAFT_API
TimeZoneNames*
TimeZoneNames::createTZDBInstance(const Locale& locale, UErrorCode& status) {
TimeZoneNames *instance = NULL;
if (U_SUCCESS(status)) {
instance = new TZDBTimeZoneNames(locale);
if (instance == NULL && U_SUCCESS(status)) {
status = U_MEMORY_ALLOCATION_ERROR;
}
}
return instance;
}
#endif /* U_HIDE_DRAFT_API */
UnicodeString&
TimeZoneNames::getExemplarLocationName(const UnicodeString& tzID, UnicodeString& name) const {
return TimeZoneNamesImpl::getDefaultExemplarLocationName(tzID, name);

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.
*******************************************************************************
*
@ -51,6 +51,36 @@ static const UTimeZoneNameType ALL_NAME_TYPES[] = {
UTZNM_UNKNOWN // unknown as the last one
};
// stuff for TZDBTimeZoneNames
static const char* TZDBNAMES_KEYS[] = {"ss", "sd"};
static const int32_t TZDBNAMES_KEYS_SIZE = (sizeof TZDBNAMES_KEYS / sizeof TZDBNAMES_KEYS[0]);
static UMutex gTZDBNamesMapLock = U_MUTEX_INITIALIZER;
static UHashtable* gTZDBNamesMap = NULL;
static icu::UInitOnce gTZDBNamesMapInitOnce = U_INITONCE_INITIALIZER;
static TextTrieMap* gTZDBNamesTrie = NULL;
static icu::UInitOnce gTZDBNamesTrieInitOnce = U_INITONCE_INITIALIZER;
U_CDECL_BEGIN
static UBool U_CALLCONV tzdbTimeZoneNames_cleanup(void) {
if (gTZDBNamesMap != NULL) {
uhash_close(gTZDBNamesMap);
gTZDBNamesMap = NULL;
}
gTZDBNamesMapInitOnce.reset();
if (gTZDBNamesTrie != NULL) {
delete gTZDBNamesTrie;
gTZDBNamesTrie = NULL;
}
gTZDBNamesTrieInitOnce.reset();
return TRUE;
}
U_CDECL_END
#define DEFAULT_CHARACTERNODE_CAPACITY 1
// ---------------------------------------------------
@ -799,7 +829,7 @@ ZNameSearchHandler::handleMatch(int32_t matchLength, const CharacterNode *node,
for (int32_t i = 0; i < valuesCount; i++) {
ZNameInfo *nameinfo = (ZNameInfo *)node->getValue(i);
if (nameinfo == NULL) {
break;
continue;
}
if ((nameinfo->type & fTypes) != 0) {
// matches a requested type
@ -986,6 +1016,12 @@ TimeZoneNamesImpl::clone() const {
StringEnumeration*
TimeZoneNamesImpl::getAvailableMetaZoneIDs(UErrorCode& status) const {
return TimeZoneNamesImpl::_getAvailableMetaZoneIDs(status);
}
// static implementation of getAvailableMetaZoneIDs(UErrorCode&)
StringEnumeration*
TimeZoneNamesImpl::_getAvailableMetaZoneIDs(UErrorCode& status) {
if (U_FAILURE(status)) {
return NULL;
}
@ -998,6 +1034,12 @@ TimeZoneNamesImpl::getAvailableMetaZoneIDs(UErrorCode& status) const {
StringEnumeration*
TimeZoneNamesImpl::getAvailableMetaZoneIDs(const UnicodeString& tzID, UErrorCode& status) const {
return TimeZoneNamesImpl::_getAvailableMetaZoneIDs(tzID, status);
}
// static implementation of getAvailableMetaZoneIDs(const UnicodeString&, UErrorCode&)
StringEnumeration*
TimeZoneNamesImpl::_getAvailableMetaZoneIDs(const UnicodeString& tzID, UErrorCode& status) {
if (U_FAILURE(status)) {
return NULL;
}
@ -1032,16 +1074,29 @@ TimeZoneNamesImpl::getAvailableMetaZoneIDs(const UnicodeString& tzID, UErrorCode
UnicodeString&
TimeZoneNamesImpl::getMetaZoneID(const UnicodeString& tzID, UDate date, UnicodeString& mzID) const {
return TimeZoneNamesImpl::_getMetaZoneID(tzID, date, mzID);
}
// static implementation of getMetaZoneID
UnicodeString&
TimeZoneNamesImpl::_getMetaZoneID(const UnicodeString& tzID, UDate date, UnicodeString& mzID) {
ZoneMeta::getMetazoneID(tzID, date, mzID);
return mzID;
}
UnicodeString&
TimeZoneNamesImpl::getReferenceZoneID(const UnicodeString& mzID, const char* region, UnicodeString& tzID) const {
return TimeZoneNamesImpl::_getReferenceZoneID(mzID, region, tzID);
}
// static implementaion of getReferenceZoneID
UnicodeString&
TimeZoneNamesImpl::_getReferenceZoneID(const UnicodeString& mzID, const char* region, UnicodeString& tzID) {
ZoneMeta::getZoneIdByMetazone(mzID, UnicodeString(region, -1, US_INV), tzID);
return tzID;
}
UnicodeString&
TimeZoneNamesImpl::getMetaZoneDisplayName(const UnicodeString& mzID,
UTimeZoneNameType type,
@ -1170,6 +1225,7 @@ TimeZoneNamesImpl::loadMetaZoneNames(const UnicodeString& mzID) {
if (U_FAILURE(status)) {
if (znames != NULL) {
delete znames;
znames = NULL;
}
} else if (znames != NULL) {
// put the name info into the trie
@ -1247,6 +1303,7 @@ TimeZoneNamesImpl::loadTimeZoneNames(const UnicodeString& tzID) {
if (U_FAILURE(status)) {
if (tznames != NULL) {
delete tznames;
tznames = NULL;
}
} else if (tznames != NULL) {
// put the name info into the trie
@ -1371,6 +1428,589 @@ TimeZoneNamesImpl::getDefaultExemplarLocationName(const UnicodeString& tzID, Uni
return name;
}
// ---------------------------------------------------
// TZDBTimeZoneNames and its supporting classes
//
// TZDBTimeZoneNames is an implementation class of
// TimeZoneNames holding the IANA tz database abbreviations.
// ---------------------------------------------------
class TZDBNames : public UMemory {
public:
virtual ~TZDBNames();
static TZDBNames* createInstance(UResourceBundle* rb, const char* key);
const UChar* getName(UTimeZoneNameType type) const;
const char** getParseRegions(int32_t& numRegions) const;
protected:
TZDBNames(const UChar** names, char** regions, int32_t numRegions);
private:
const UChar** fNames;
char** fRegions;
int32_t fNumRegions;
};
TZDBNames::TZDBNames(const UChar** names, char** regions, int32_t numRegions)
: fNames(names),
fRegions(regions),
fNumRegions(numRegions) {
}
TZDBNames::~TZDBNames() {
if (fNames != NULL) {
uprv_free(fNames);
}
if (fRegions != NULL) {
char **p = fRegions;
for (int32_t i = 0; i < fNumRegions; p++, i++) {
uprv_free(*p);
}
uprv_free(fRegions);
}
}
TZDBNames*
TZDBNames::createInstance(UResourceBundle* rb, const char* key) {
if (rb == NULL || key == NULL || *key == 0) {
return NULL;
}
UErrorCode status = U_ZERO_ERROR;
const UChar **names = NULL;
char** regions = NULL;
int32_t numRegions = 0;
int32_t len = 0;
UResourceBundle* rbTable = NULL;
rbTable = ures_getByKey(rb, key, rbTable, &status);
if (U_FAILURE(status)) {
return NULL;
}
names = (const UChar **)uprv_malloc(sizeof(const UChar*) * TZDBNAMES_KEYS_SIZE);
UBool isEmpty = TRUE;
if (names != NULL) {
for (int32_t i = 0; i < TZDBNAMES_KEYS_SIZE; i++) {
status = U_ZERO_ERROR;
const UChar *value = ures_getStringByKey(rbTable, TZDBNAMES_KEYS[i], &len, &status);
if (U_FAILURE(status) || len == 0) {
names[i] = NULL;
} else {
names[i] = value;
isEmpty = FALSE;
}
}
}
if (isEmpty) {
if (names != NULL) {
uprv_free(names);
}
return NULL;
}
UResourceBundle *regionsRes = ures_getByKey(rbTable, "parseRegions", NULL, &status);
UBool regionError = FALSE;
if (U_SUCCESS(status)) {
numRegions = ures_getSize(regionsRes);
if (numRegions > 0) {
regions = (char**)uprv_malloc(sizeof(char*) * numRegions);
if (regions != NULL) {
char **pRegion = regions;
for (int32_t i = 0; i < numRegions; i++, pRegion++) {
*pRegion = NULL;
}
// filling regions
pRegion = regions;
for (int32_t i = 0; i < numRegions; i++, pRegion++) {
status = U_ZERO_ERROR;
const UChar *uregion = ures_getStringByIndex(regionsRes, i, &len, &status);
if (U_FAILURE(status)) {
regionError = TRUE;
break;
}
*pRegion = (char*)uprv_malloc(sizeof(char) * (len + 1));
if (*pRegion == NULL) {
regionError = TRUE;
break;
}
u_UCharsToChars(uregion, *pRegion, len);
(*pRegion)[len] = 0;
}
}
}
}
ures_close(regionsRes);
ures_close(rbTable);
if (regionError) {
if (names != NULL) {
uprv_free(names);
}
if (regions != NULL) {
char **p = regions;
for (int32_t i = 0; i < numRegions; p++, i++) {
uprv_free(p);
}
uprv_free(regions);
}
return NULL;
}
return new TZDBNames(names, regions, numRegions);
}
const UChar*
TZDBNames::getName(UTimeZoneNameType type) const {
if (fNames == NULL) {
return NULL;
}
const UChar *name = NULL;
switch(type) {
case UTZNM_SHORT_STANDARD:
name = fNames[0];
break;
case UTZNM_SHORT_DAYLIGHT:
name = fNames[1];
break;
default:
name = NULL;
}
return name;
}
const char**
TZDBNames::getParseRegions(int32_t& numRegions) const {
if (fRegions == NULL) {
numRegions = 0;
} else {
numRegions = fNumRegions;
}
return (const char**)fRegions;
}
U_CDECL_BEGIN
/**
* TZDBNameInfo stores metazone name information for the IANA abbreviations
* in the trie
*/
typedef struct TZDBNameInfo {
const UChar* mzID;
UTimeZoneNameType type;
UBool ambiguousType;
const char** parseRegions;
int32_t nRegions;
} TZDBNameInfo;
U_CDECL_END
class TZDBNameSearchHandler : public TextTrieMapSearchResultHandler {
public:
TZDBNameSearchHandler(uint32_t types, const char* region);
virtual ~TZDBNameSearchHandler();
UBool handleMatch(int32_t matchLength, const CharacterNode *node, UErrorCode &status);
TimeZoneNames::MatchInfoCollection* getMatches(int32_t& maxMatchLen);
private:
uint32_t fTypes;
int32_t fMaxMatchLen;
TimeZoneNames::MatchInfoCollection* fResults;
const char* fRegion;
};
TZDBNameSearchHandler::TZDBNameSearchHandler(uint32_t types, const char* region)
: fTypes(types), fMaxMatchLen(0), fResults(NULL), fRegion(region) {
}
TZDBNameSearchHandler::~TZDBNameSearchHandler() {
if (fResults != NULL) {
delete fResults;
}
}
UBool
TZDBNameSearchHandler::handleMatch(int32_t matchLength, const CharacterNode *node, UErrorCode &status) {
if (U_FAILURE(status)) {
return FALSE;
}
TZDBNameInfo *match = NULL;
TZDBNameInfo *defaultRegionMatch = NULL;
if (node->hasValues()) {
int32_t valuesCount = node->countValues();
for (int32_t i = 0; i < valuesCount; i++) {
TZDBNameInfo *ninfo = (TZDBNameInfo *)node->getValue(i);
if (ninfo == NULL) {
continue;
}
if ((ninfo->type & fTypes) != 0) {
// 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 {
UBool 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 (int32_t i = 0; i < ninfo->nRegions; i++) {
const char *region = ninfo->parseRegions[i];
if (uprv_strcmp(fRegion, region) == 0) {
match = ninfo;
matchRegion = TRUE;
break;
}
}
if (matchRegion) {
break;
}
if (match == NULL) {
match = ninfo;
}
}
}
}
if (match != NULL) {
UTimeZoneNameType 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 == UTZNM_SHORT_STANDARD || ntype == UTZNM_SHORT_DAYLIGHT)
&& (fTypes & UTZNM_SHORT_STANDARD) != 0
&& (fTypes & UTZNM_SHORT_DAYLIGHT) != 0) {
ntype = UTZNM_SHORT_GENERIC;
}
if (fResults == NULL) {
fResults = new TimeZoneNames::MatchInfoCollection();
if (fResults == NULL) {
status = U_MEMORY_ALLOCATION_ERROR;
}
}
if (U_SUCCESS(status)) {
U_ASSERT(fResults != NULL);
U_ASSERT(match->mzID != NULL);
fResults->addMetaZone(ntype, matchLength, UnicodeString(match->mzID, -1), status);
if (U_SUCCESS(status) && matchLength > fMaxMatchLen) {
fMaxMatchLen = matchLength;
}
}
}
}
return TRUE;
}
TimeZoneNames::MatchInfoCollection*
TZDBNameSearchHandler::getMatches(int32_t& maxMatchLen) {
// give the ownership to the caller
TimeZoneNames::MatchInfoCollection* results = fResults;
maxMatchLen = fMaxMatchLen;
// reset
fResults = NULL;
fMaxMatchLen = 0;
return results;
}
U_CDECL_BEGIN
/**
* Deleter for TZDBNames
*/
static void U_CALLCONV
deleteTZDBNames(void *obj) {
if (obj != EMPTY) {
delete (TZDBNames *)obj;
}
}
static void U_CALLCONV initTZDBNamesMap(UErrorCode &status) {
gTZDBNamesMap = uhash_open(uhash_hashUChars, uhash_compareUChars, NULL, &status);
if (U_FAILURE(status)) {
gTZDBNamesMap = NULL;
return;
}
// no key deleters for tzdb name maps
uhash_setValueDeleter(gTZDBNamesMap, deleteTZDBNames);
ucln_i18n_registerCleanup(UCLN_I18N_TZDBTIMEZONENAMES, tzdbTimeZoneNames_cleanup);
}
/**
* Deleter for TZDBNameInfo
*/
static void U_CALLCONV
deleteTZDBNameInfo(void *obj) {
if (obj != NULL) {
uprv_free(obj);
}
}
static void U_CALLCONV prepareFind(UErrorCode &status) {
if (U_FAILURE(status)) {
return;
}
gTZDBNamesTrie = new TextTrieMap(TRUE, deleteTZDBNameInfo);
if (gTZDBNamesTrie == NULL) {
status = U_MEMORY_ALLOCATION_ERROR;
return;
}
const UnicodeString *mzID;
StringEnumeration *mzIDs = TimeZoneNamesImpl::_getAvailableMetaZoneIDs(status);
if (U_SUCCESS(status)) {
while ((mzID = mzIDs->snext(status)) && U_SUCCESS(status)) {
const TZDBNames *names = TZDBTimeZoneNames::getMetaZoneNames(*mzID, status);
if (names == NULL) {
continue;
}
const UChar *std = names->getName(UTZNM_SHORT_STANDARD);
const UChar *dst = names->getName(UTZNM_SHORT_DAYLIGHT);
if (std == NULL && dst == NULL) {
continue;
}
int32_t numRegions = 0;
const char **parseRegions = names->getParseRegions(numRegions);
// 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.
UBool ambiguousType = (std != NULL && dst != NULL && u_strcmp(std, dst) == 0);
const UChar *uMzID = ZoneMeta::findMetaZoneID(*mzID);
if (std != NULL) {
TZDBNameInfo *stdInf = (TZDBNameInfo *)uprv_malloc(sizeof(TZDBNameInfo));
if (stdInf == NULL) {
status = U_MEMORY_ALLOCATION_ERROR;
break;
}
stdInf->mzID = uMzID;
stdInf->type = UTZNM_SHORT_STANDARD;
stdInf->ambiguousType = ambiguousType;
stdInf->parseRegions = parseRegions;
stdInf->nRegions = numRegions;
gTZDBNamesTrie->put(std, stdInf, status);
}
if (U_SUCCESS(status) && dst != NULL) {
TZDBNameInfo *dstInf = (TZDBNameInfo *)uprv_malloc(sizeof(TZDBNameInfo));
if (dstInf == NULL) {
status = U_MEMORY_ALLOCATION_ERROR;
break;
}
dstInf->mzID = uMzID;
dstInf->type = UTZNM_SHORT_DAYLIGHT;
dstInf->ambiguousType = ambiguousType;
dstInf->parseRegions = parseRegions;
dstInf->nRegions = numRegions;
gTZDBNamesTrie->put(dst, dstInf, status);
}
}
}
delete mzIDs;
if (U_FAILURE(status)) {
delete gTZDBNamesTrie;
gTZDBNamesTrie = NULL;
return;
}
ucln_i18n_registerCleanup(UCLN_I18N_TZDBTIMEZONENAMES, tzdbTimeZoneNames_cleanup);
}
U_CDECL_END
TZDBTimeZoneNames::TZDBTimeZoneNames(const Locale& locale)
: fLocale(locale) {
UBool useWorld = TRUE;
const char* region = fLocale.getCountry();
int32_t regionLen = uprv_strlen(region);
if (regionLen == 0) {
UErrorCode status = U_ZERO_ERROR;
char loc[ULOC_FULLNAME_CAPACITY];
uloc_addLikelySubtags(fLocale.getName(), loc, sizeof(loc), &status);
regionLen = uloc_getCountry(loc, fRegion, sizeof(fRegion), &status);
if (U_SUCCESS(status) && regionLen < (int32_t)sizeof(fRegion)) {
useWorld = FALSE;
}
} else if (regionLen < (int32_t)sizeof(fRegion)) {
uprv_strcpy(fRegion, region);
useWorld = FALSE;
}
if (useWorld) {
uprv_strcpy(fRegion, "001");
}
}
TZDBTimeZoneNames::~TZDBTimeZoneNames() {
}
UBool
TZDBTimeZoneNames::operator==(const TimeZoneNames& other) const {
if (this == &other) {
return TRUE;
}
// No implementation for now
return FALSE;
}
TimeZoneNames*
TZDBTimeZoneNames::clone() const {
return new TZDBTimeZoneNames(fLocale);
}
StringEnumeration*
TZDBTimeZoneNames::getAvailableMetaZoneIDs(UErrorCode& status) const {
return TimeZoneNamesImpl::_getAvailableMetaZoneIDs(status);
}
StringEnumeration*
TZDBTimeZoneNames::getAvailableMetaZoneIDs(const UnicodeString& tzID, UErrorCode& status) const {
return TimeZoneNamesImpl::_getAvailableMetaZoneIDs(tzID, status);
}
UnicodeString&
TZDBTimeZoneNames::getMetaZoneID(const UnicodeString& tzID, UDate date, UnicodeString& mzID) const {
return TimeZoneNamesImpl::_getMetaZoneID(tzID, date, mzID);
}
UnicodeString&
TZDBTimeZoneNames::getReferenceZoneID(const UnicodeString& mzID, const char* region, UnicodeString& tzID) const {
return TimeZoneNamesImpl::_getReferenceZoneID(mzID, region, tzID);
}
UnicodeString&
TZDBTimeZoneNames::getMetaZoneDisplayName(const UnicodeString& mzID,
UTimeZoneNameType type,
UnicodeString& name) const {
name.setToBogus();
if (mzID.isEmpty()) {
return name;
}
UErrorCode status = U_ZERO_ERROR;
const TZDBNames *tzdbNames = TZDBTimeZoneNames::getMetaZoneNames(mzID, status);
if (U_SUCCESS(status)) {
const UChar *s = tzdbNames->getName(type);
if (s != NULL) {
name.setTo(TRUE, s, -1);
}
}
return name;
}
UnicodeString&
TZDBTimeZoneNames::getTimeZoneDisplayName(const UnicodeString& /* tzID */, UTimeZoneNameType /* type */, UnicodeString& name) const {
// No abbreviations associated a zone directly for now.
name.setToBogus();
return name;
}
TZDBTimeZoneNames::MatchInfoCollection*
TZDBTimeZoneNames::find(const UnicodeString& text, int32_t start, uint32_t types, UErrorCode& status) const {
umtx_initOnce(gTZDBNamesTrieInitOnce, &prepareFind, status);
if (U_FAILURE(status)) {
return NULL;
}
TZDBNameSearchHandler handler(types, fRegion);
gTZDBNamesTrie->search(text, start, (TextTrieMapSearchResultHandler *)&handler, status);
if (U_FAILURE(status)) {
return NULL;
}
int32_t maxLen = 0;
return handler.getMatches(maxLen);
}
const TZDBNames*
TZDBTimeZoneNames::getMetaZoneNames(const UnicodeString& mzID, UErrorCode& status) {
umtx_initOnce(gTZDBNamesMapInitOnce, &initTZDBNamesMap, status);
if (U_FAILURE(status)) {
return NULL;
}
TZDBNames* tzdbNames = NULL;
UChar mzIDKey[ZID_KEY_MAX + 1];
mzID.extract(mzIDKey, ZID_KEY_MAX + 1, status);
U_ASSERT(status == U_ZERO_ERROR); // already checked length above
mzIDKey[mzID.length()] = 0;
umtx_lock(&gTZDBNamesMapLock);
{
void *cacheVal = uhash_get(gTZDBNamesMap, mzIDKey);
if (cacheVal == NULL) {
UResourceBundle *zoneStringsRes = ures_openDirect(U_ICUDATA_ZONE, "tzdbNames", &status);
zoneStringsRes = ures_getByKey(zoneStringsRes, gZoneStrings, zoneStringsRes, &status);
if (U_SUCCESS(status)) {
char key[ZID_KEY_MAX + 1];
mergeTimeZoneKey(mzID, key);
tzdbNames = TZDBNames::createInstance(zoneStringsRes, key);
if (tzdbNames == NULL) {
cacheVal = (void *)EMPTY;
} else {
cacheVal = tzdbNames;
}
// Use the persistent ID as the resource key, so we can
// avoid duplications.
const UChar* newKey = ZoneMeta::findMetaZoneID(mzID);
if (newKey != NULL) {
uhash_put(gTZDBNamesMap, (void *)newKey, cacheVal, &status);
if (U_FAILURE(status)) {
if (tzdbNames != NULL) {
delete tzdbNames;
tzdbNames = NULL;
}
}
} else {
// Should never happen with a valid input
if (tzdbNames != NULL) {
// It's not possible that we get a valid tzdbNames with unknown ID.
// But just in case..
delete tzdbNames;
tzdbNames = NULL;
}
}
}
ures_close(zoneStringsRes);
} else if (cacheVal != EMPTY) {
tzdbNames = (TZDBNames *)cacheVal;
}
}
umtx_unlock(&gTZDBNamesMapLock);
return tzdbNames;
}
U_NAMESPACE_END

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. *
*******************************************************************************
*/
@ -186,6 +186,11 @@ public:
static UnicodeString& getDefaultExemplarLocationName(const UnicodeString& tzID, UnicodeString& name);
static StringEnumeration* _getAvailableMetaZoneIDs(UErrorCode& status);
static StringEnumeration* _getAvailableMetaZoneIDs(const UnicodeString& tzID, UErrorCode& status);
static UnicodeString& _getMetaZoneID(const UnicodeString& tzID, UDate date, UnicodeString& mzID);
static UnicodeString& _getReferenceZoneID(const UnicodeString& mzID, const char* region, UnicodeString& tzID);
private:
Locale fLocale;
@ -207,6 +212,34 @@ private:
TZNames* loadTimeZoneNames(const UnicodeString& mzId);
};
class TZDBNames;
class TZDBTimeZoneNames : public TimeZoneNames {
public:
TZDBTimeZoneNames(const Locale& locale);
virtual ~TZDBTimeZoneNames();
virtual UBool operator==(const TimeZoneNames& other) const;
virtual TimeZoneNames* clone() const;
StringEnumeration* getAvailableMetaZoneIDs(UErrorCode& status) const;
StringEnumeration* getAvailableMetaZoneIDs(const UnicodeString& tzID, UErrorCode& status) const;
UnicodeString& getMetaZoneID(const UnicodeString& tzID, UDate date, UnicodeString& mzID) const;
UnicodeString& getReferenceZoneID(const UnicodeString& mzID, const char* region, UnicodeString& tzID) const;
UnicodeString& getMetaZoneDisplayName(const UnicodeString& mzID, UTimeZoneNameType type, UnicodeString& name) const;
UnicodeString& getTimeZoneDisplayName(const UnicodeString& tzID, UTimeZoneNameType type, UnicodeString& name) const;
TimeZoneNames::MatchInfoCollection* find(const UnicodeString& text, int32_t start, uint32_t types, UErrorCode& status) const;
static const TZDBNames* getMetaZoneNames(const UnicodeString& mzId, UErrorCode& status);
private:
Locale fLocale;
char fRegion[ULOC_COUNTRY_CAPACITY];
};
U_NAMESPACE_END
#endif /* #if !UCONFIG_NO_FORMATTING */

View file

@ -35,6 +35,7 @@ typedef enum ECleanupI18NType {
UCLN_I18N_DANGI_CALENDAR,
UCLN_I18N_CALENDAR,
UCLN_I18N_TIMEZONEFORMAT,
UCLN_I18N_TZDBTIMEZONENAMES,
UCLN_I18N_TIMEZONEGENERICNAMES,
UCLN_I18N_TIMEZONENAMES,
UCLN_I18N_ZONEMETA,

View file

@ -233,7 +233,15 @@ typedef enum UTimeZoneFormatParseOption {
* by other styles.
* @stable ICU 50
*/
UTZFMT_PARSE_OPTION_ALL_STYLES = 0x01
UTZFMT_PARSE_OPTION_ALL_STYLES = 0x01,
/**
* When parsing a time zone display name in UTZFMT_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
*/
UTZFMT_PARSE_OPTION_TZ_DATABASE_ABBREVIATIONS = 0x02
} UTimeZoneFormatParseOption;
U_CDECL_END
@ -241,6 +249,7 @@ U_CDECL_END
U_NAMESPACE_BEGIN
class TimeZoneGenericNames;
class TZDBTimeZoneNames;
class UVector;
/**
@ -697,6 +706,9 @@ private:
UBool fAbuttingOffsetHoursAndMinutes;
/* TZDBTimeZoneNames object used for parsing */
TZDBTimeZoneNames* fTZDBTimeZoneNames;
/**
* Returns the time zone's specific format string.
* @param tz the time zone
@ -727,6 +739,13 @@ private:
*/
const TimeZoneGenericNames* getTimeZoneGenericNames(UErrorCode& status) const;
/**
* Lazily create a TZDBTimeZoneNames instance
* @param status receives the status
* @return the cached TZDBTimeZoneNames.
*/
const TZDBTimeZoneNames* getTZDBTimeZoneNames(UErrorCode& status) const;
/**
* Private method returning the time zone's exemplar location string.
* This method will never return empty.

View file

@ -158,15 +158,28 @@ public:
virtual TimeZoneNames* clone() const = 0;
/**
* 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.
* @param status Receives the status.
* @return An instance of <code>TimeZoneDisplayNames</code>
* @return An instance of <code>TimeZoneNames</code>
* @stable ICU 50
*/
static TimeZoneNames* U_EXPORT2 createInstance(const Locale& locale, UErrorCode& status);
#ifndef U_HIDE_DRAFT_API
/**
* Returns an instance of <code>TimeZoneNames</code> containing only short specific
* zone names (SHORT_STANDARD and 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.
*/
static TimeZoneNames* U_EXPORT2 createTZDBInstance(const Locale& locale, UErrorCode& status);
#endif /* U_HIDE_DRAFT_API */
/**
* Returns an enumeration of all available meta zone IDs.
* @param status Receives the status.

View file

@ -1,6 +1,6 @@
/*
*******************************************************************************
* Copyright (C) 2007-2013, International Business Machines Corporation and *
* Copyright (C) 2007-2014, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*/
@ -76,6 +76,7 @@ TimeZoneFormatTest::runIndexedTest( int32_t index, UBool exec, const char* &name
TESTCASE(2, TestParse);
TESTCASE(3, TestISOFormat);
TESTCASE(4, TestFormat);
TESTCASE(5, TestFormatTZDBNames);
default: name = ""; break;
}
}
@ -685,7 +686,7 @@ typedef struct {
int32_t inPos;
const char* locale;
UTimeZoneFormatStyle style;
UBool parseAll;
uint32_t parseOptions;
const char* expected;
int32_t outPos;
UTimeZoneFormatTimeType timeType;
@ -694,26 +695,94 @@ typedef struct {
void
TimeZoneFormatTest::TestParse(void) {
const ParseTestData DATA[] = {
// text inPos locale style parseAll expected outPos timeType
{"Z", 0, "en_US", UTZFMT_STYLE_ISO_EXTENDED_FULL, false, "Etc/GMT", 1, UTZFMT_TIME_TYPE_UNKNOWN},
{"Z", 0, "en_US", UTZFMT_STYLE_SPECIFIC_LONG, false, "Etc/GMT", 1, UTZFMT_TIME_TYPE_UNKNOWN},
{"Zambia time", 0, "en_US", UTZFMT_STYLE_ISO_EXTENDED_FULL, true, "Etc/GMT", 1, UTZFMT_TIME_TYPE_UNKNOWN},
{"Zambia time", 0, "en_US", UTZFMT_STYLE_GENERIC_LOCATION, false, "Africa/Lusaka", 11, UTZFMT_TIME_TYPE_UNKNOWN},
{"Zambia time", 0, "en_US", UTZFMT_STYLE_ISO_BASIC_LOCAL_FULL, true, "Africa/Lusaka", 11, UTZFMT_TIME_TYPE_UNKNOWN},
{"+00:00", 0, "en_US", UTZFMT_STYLE_ISO_EXTENDED_FULL, false, "Etc/GMT", 6, UTZFMT_TIME_TYPE_UNKNOWN},
{"-01:30:45", 0, "en_US", UTZFMT_STYLE_ISO_EXTENDED_FULL, false, "GMT-01:30:45", 9, UTZFMT_TIME_TYPE_UNKNOWN},
{"-7", 0, "en_US", UTZFMT_STYLE_ISO_BASIC_LOCAL_FULL, false, "GMT-07:00", 2, UTZFMT_TIME_TYPE_UNKNOWN},
{"-2222", 0, "en_US", UTZFMT_STYLE_ISO_BASIC_LOCAL_FULL, false, "GMT-22:22", 5, UTZFMT_TIME_TYPE_UNKNOWN},
{"-3333", 0, "en_US", UTZFMT_STYLE_ISO_BASIC_LOCAL_FULL, false, "GMT-03:33", 4, UTZFMT_TIME_TYPE_UNKNOWN},
{"XXX+01:30YYY", 3, "en_US", UTZFMT_STYLE_LOCALIZED_GMT, false, "GMT+01:30", 9, UTZFMT_TIME_TYPE_UNKNOWN},
{"GMT0", 0, "en_US", UTZFMT_STYLE_SPECIFIC_SHORT, false, "Etc/GMT", 3, UTZFMT_TIME_TYPE_UNKNOWN},
{"EST", 0, "en_US", UTZFMT_STYLE_SPECIFIC_SHORT, false, "America/New_York", 3, UTZFMT_TIME_TYPE_STANDARD},
{"ESTx", 0, "en_US", UTZFMT_STYLE_SPECIFIC_SHORT, false, "America/New_York", 3, UTZFMT_TIME_TYPE_STANDARD},
{"EDTx", 0, "en_US", UTZFMT_STYLE_SPECIFIC_SHORT, false, "America/New_York", 3, UTZFMT_TIME_TYPE_DAYLIGHT},
{"EST", 0, "en_US", UTZFMT_STYLE_SPECIFIC_LONG, false, NULL, 0, UTZFMT_TIME_TYPE_UNKNOWN},
{"EST", 0, "en_US", UTZFMT_STYLE_SPECIFIC_LONG, true, "America/New_York", 3, UTZFMT_TIME_TYPE_STANDARD},
{"EST", 0, "en_CA", UTZFMT_STYLE_SPECIFIC_SHORT, false, "America/Toronto", 3, UTZFMT_TIME_TYPE_STANDARD},
{NULL, 0, NULL, UTZFMT_STYLE_GENERIC_LOCATION, false, NULL, 0, UTZFMT_TIME_TYPE_UNKNOWN}
// text inPos locale style
// parseOptions expected outPos timeType
{"Z", 0, "en_US", UTZFMT_STYLE_ISO_EXTENDED_FULL,
UTZFMT_PARSE_OPTION_NONE, "Etc/GMT", 1, UTZFMT_TIME_TYPE_UNKNOWN},
{"Z", 0, "en_US", UTZFMT_STYLE_SPECIFIC_LONG,
UTZFMT_PARSE_OPTION_NONE, "Etc/GMT", 1, UTZFMT_TIME_TYPE_UNKNOWN},
{"Zambia time", 0, "en_US", UTZFMT_STYLE_ISO_EXTENDED_FULL,
UTZFMT_PARSE_OPTION_ALL_STYLES, "Etc/GMT", 1, UTZFMT_TIME_TYPE_UNKNOWN},
{"Zambia time", 0, "en_US", UTZFMT_STYLE_GENERIC_LOCATION,
UTZFMT_PARSE_OPTION_NONE, "Africa/Lusaka", 11, UTZFMT_TIME_TYPE_UNKNOWN},
{"Zambia time", 0, "en_US", UTZFMT_STYLE_ISO_BASIC_LOCAL_FULL,
UTZFMT_PARSE_OPTION_ALL_STYLES, "Africa/Lusaka", 11, UTZFMT_TIME_TYPE_UNKNOWN},
{"+00:00", 0, "en_US", UTZFMT_STYLE_ISO_EXTENDED_FULL,
UTZFMT_PARSE_OPTION_NONE, "Etc/GMT", 6, UTZFMT_TIME_TYPE_UNKNOWN},
{"-01:30:45", 0, "en_US", UTZFMT_STYLE_ISO_EXTENDED_FULL,
UTZFMT_PARSE_OPTION_NONE, "GMT-01:30:45", 9, UTZFMT_TIME_TYPE_UNKNOWN},
{"-7", 0, "en_US", UTZFMT_STYLE_ISO_BASIC_LOCAL_FULL,
UTZFMT_PARSE_OPTION_NONE, "GMT-07:00", 2, UTZFMT_TIME_TYPE_UNKNOWN},
{"-2222", 0, "en_US", UTZFMT_STYLE_ISO_BASIC_LOCAL_FULL,
UTZFMT_PARSE_OPTION_NONE, "GMT-22:22", 5, UTZFMT_TIME_TYPE_UNKNOWN},
{"-3333", 0, "en_US", UTZFMT_STYLE_ISO_BASIC_LOCAL_FULL,
UTZFMT_PARSE_OPTION_NONE, "GMT-03:33", 4, UTZFMT_TIME_TYPE_UNKNOWN},
{"XXX+01:30YYY", 3, "en_US", UTZFMT_STYLE_LOCALIZED_GMT,
UTZFMT_PARSE_OPTION_NONE, "GMT+01:30", 9, UTZFMT_TIME_TYPE_UNKNOWN},
{"GMT0", 0, "en_US", UTZFMT_STYLE_SPECIFIC_SHORT,
UTZFMT_PARSE_OPTION_NONE, "Etc/GMT", 3, UTZFMT_TIME_TYPE_UNKNOWN},
{"EST", 0, "en_US", UTZFMT_STYLE_SPECIFIC_SHORT,
UTZFMT_PARSE_OPTION_NONE, "America/New_York", 3, UTZFMT_TIME_TYPE_STANDARD},
{"ESTx", 0, "en_US", UTZFMT_STYLE_SPECIFIC_SHORT,
UTZFMT_PARSE_OPTION_NONE, "America/New_York", 3, UTZFMT_TIME_TYPE_STANDARD},
{"EDTx", 0, "en_US", UTZFMT_STYLE_SPECIFIC_SHORT,
UTZFMT_PARSE_OPTION_NONE, "America/New_York", 3, UTZFMT_TIME_TYPE_DAYLIGHT},
{"EST", 0, "en_US", UTZFMT_STYLE_SPECIFIC_LONG,
UTZFMT_PARSE_OPTION_NONE, NULL, 0, UTZFMT_TIME_TYPE_UNKNOWN},
{"EST", 0, "en_US", UTZFMT_STYLE_SPECIFIC_LONG,
UTZFMT_PARSE_OPTION_ALL_STYLES, "America/New_York", 3, UTZFMT_TIME_TYPE_STANDARD},
{"EST", 0, "en_CA", UTZFMT_STYLE_SPECIFIC_SHORT,
UTZFMT_PARSE_OPTION_NONE, "America/Toronto", 3, UTZFMT_TIME_TYPE_STANDARD},
{"CST", 0, "en_US", UTZFMT_STYLE_SPECIFIC_SHORT,
UTZFMT_PARSE_OPTION_NONE, "America/Chicago", 3, UTZFMT_TIME_TYPE_STANDARD},
{"CST", 0, "en_GB", UTZFMT_STYLE_SPECIFIC_SHORT,
UTZFMT_PARSE_OPTION_NONE, NULL, 0, UTZFMT_TIME_TYPE_UNKNOWN},
{"CST", 0, "en_GB", UTZFMT_STYLE_SPECIFIC_SHORT,
UTZFMT_PARSE_OPTION_TZ_DATABASE_ABBREVIATIONS, "America/Chicago", 3, UTZFMT_TIME_TYPE_STANDARD},
{"--CST--", 2, "en_GB", UTZFMT_STYLE_SPECIFIC_SHORT,
UTZFMT_PARSE_OPTION_TZ_DATABASE_ABBREVIATIONS, "America/Chicago", 5, UTZFMT_TIME_TYPE_STANDARD},
{"CST", 0, "zh_CN", UTZFMT_STYLE_SPECIFIC_SHORT,
UTZFMT_PARSE_OPTION_TZ_DATABASE_ABBREVIATIONS, "Asia/Shanghai", 3, UTZFMT_TIME_TYPE_STANDARD},
{"EST", 0, "en_AU", UTZFMT_STYLE_SPECIFIC_SHORT,
UTZFMT_PARSE_OPTION_TZ_DATABASE_ABBREVIATIONS, "Australia/Sydney", 3, UTZFMT_TIME_TYPE_UNKNOWN},
{"AST", 0, "ar_SA", UTZFMT_STYLE_SPECIFIC_SHORT,
UTZFMT_PARSE_OPTION_TZ_DATABASE_ABBREVIATIONS, "Asia/Riyadh", 3, UTZFMT_TIME_TYPE_STANDARD},
{"AQTST", 0, "en", UTZFMT_STYLE_SPECIFIC_LONG,
UTZFMT_PARSE_OPTION_NONE, NULL, 0, UTZFMT_TIME_TYPE_UNKNOWN},
{"AQTST", 0, "en", UTZFMT_STYLE_SPECIFIC_LONG,
UTZFMT_PARSE_OPTION_ALL_STYLES, NULL, 0, UTZFMT_TIME_TYPE_UNKNOWN},
{"AQTST", 0, "en", UTZFMT_STYLE_SPECIFIC_LONG,
UTZFMT_PARSE_OPTION_ALL_STYLES | UTZFMT_PARSE_OPTION_TZ_DATABASE_ABBREVIATIONS, "Asia/Aqtobe", 5, UTZFMT_TIME_TYPE_DAYLIGHT},
{NULL, 0, NULL, UTZFMT_STYLE_GENERIC_LOCATION,
UTZFMT_PARSE_OPTION_NONE, NULL, 0, UTZFMT_TIME_TYPE_UNKNOWN}
};
for (int32_t i = 0; DATA[i].text; i++) {
@ -725,8 +794,7 @@ TimeZoneFormatTest::TestParse(void) {
}
UTimeZoneFormatTimeType ttype = UTZFMT_TIME_TYPE_UNKNOWN;
ParsePosition pos(DATA[i].inPos);
int32_t parseOptions = DATA[i].parseAll ? UTZFMT_PARSE_OPTION_ALL_STYLES : UTZFMT_PARSE_OPTION_NONE;
TimeZone* tz = tzfmt->parse(DATA[i].style, DATA[i].text, pos, parseOptions, &ttype);
TimeZone* tz = tzfmt->parse(DATA[i].style, DATA[i].text, pos, DATA[i].parseOptions, &ttype);
UnicodeString errMsg;
if (tz) {
@ -1025,4 +1093,102 @@ TimeZoneFormatTest::TestFormat(void) {
}
}
void
TimeZoneFormatTest::TestFormatTZDBNames(void) {
UDate dateJan = 1358208000000.0; // 2013-01-15T00:00:00Z
UDate dateJul = 1373846400000.0; // 2013-07-15T00:00:00Z
const FormatTestData DATA[] = {
{
"en",
"America/Chicago",
dateJan,
UTZFMT_STYLE_SPECIFIC_SHORT,
"CST",
UTZFMT_TIME_TYPE_STANDARD
},
{
"en",
"Asia/Shanghai",
dateJan,
UTZFMT_STYLE_SPECIFIC_SHORT,
"CST",
UTZFMT_TIME_TYPE_STANDARD
},
{
"zh_Hans",
"Asia/Shanghai",
dateJan,
UTZFMT_STYLE_SPECIFIC_SHORT,
"CST",
UTZFMT_TIME_TYPE_STANDARD
},
{
"en",
"America/Los_Angeles",
dateJul,
UTZFMT_STYLE_SPECIFIC_LONG,
"GMT-07:00", // No long display names
UTZFMT_TIME_TYPE_DAYLIGHT
},
{
"ja",
"America/Los_Angeles",
dateJul,
UTZFMT_STYLE_SPECIFIC_SHORT,
"PDT",
UTZFMT_TIME_TYPE_DAYLIGHT
},
{
"en",
"Australia/Sydney",
dateJan,
UTZFMT_STYLE_SPECIFIC_SHORT,
"EST",
UTZFMT_TIME_TYPE_DAYLIGHT
},
{
"en",
"Australia/Sydney",
dateJul,
UTZFMT_STYLE_SPECIFIC_SHORT,
"EST",
UTZFMT_TIME_TYPE_STANDARD
},
{0, 0, 0.0, UTZFMT_STYLE_GENERIC_LOCATION, 0, UTZFMT_TIME_TYPE_UNKNOWN}
};
for (int32_t i = 0; DATA[i].locale; i++) {
UErrorCode status = U_ZERO_ERROR;
Locale loc(DATA[i].locale);
LocalPointer<TimeZoneFormat> tzfmt(TimeZoneFormat::createInstance(loc, status));
if (U_FAILURE(status)) {
dataerrln("Fail TimeZoneFormat::createInstance: %s", u_errorName(status));
continue;
}
TimeZoneNames *tzdbNames = TimeZoneNames::createTZDBInstance(loc, status);
if (U_FAILURE(status)) {
dataerrln("Fail TimeZoneNames::createTZDBInstance: %s", u_errorName(status));
continue;
}
tzfmt->adoptTimeZoneNames(tzdbNames);
LocalPointer<TimeZone> tz(TimeZone::createTimeZone(DATA[i].tzid));
UnicodeString out;
UTimeZoneFormatTimeType timeType;
tzfmt->format(DATA[i].style, *(tz.getAlias()), DATA[i].date, out, &timeType);
UnicodeString expected(DATA[i].expected, -1, US_INV);
expected = expected.unescape();
assertEquals(UnicodeString("Format result for ") + DATA[i].tzid + " (Test Case " + i + ")", expected, out);
if (DATA[i].timeType != timeType) {
dataerrln(UnicodeString("Formatted time zone type (Test Case ") + i + "), returned="
+ timeType + ", expected=" + DATA[i].timeType);
}
}
}
#endif /* #if !UCONFIG_NO_FORMATTING */

View file

@ -1,6 +1,6 @@
/*
*******************************************************************************
* Copyright (C) 2007-2013, International Business Machines Corporation and *
* Copyright (C) 2007-2014, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*/
@ -23,6 +23,7 @@ class TimeZoneFormatTest : public IntlTest {
void TestParse(void);
void TestISOFormat(void);
void TestFormat(void);
void TestFormatTZDBNames(void);
};
#endif /* #if !UCONFIG_NO_FORMATTING */