(&tz) != NULL) {
+ // short cut for OlsonTimeZone
+ const OlsonTimeZone *otz = (const OlsonTimeZone*)&tz;
+ const UChar* uID = otz->getCanonicalID();
+ if (uID != NULL) {
+ canonicalID.setTo(TRUE, uID, -1);
+ } else {
+ canonicalID.setToBogus();
+ }
+ } else {
+ UErrorCode status = U_ZERO_ERROR;
+ UnicodeString tzID;
+ ZoneMeta::getCanonicalCLDRID(tz.getID(tzID), canonicalID, status);
+ if (U_FAILURE(status)) {
+ canonicalID.setToBogus();
+ }
+ }
+ return canonicalID;
+}
+
+
+U_NAMESPACE_END
+
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+//eof
diff --git a/icu4c/source/i18n/tznames_impl.h b/icu4c/source/i18n/tznames_impl.h
new file mode 100644
index 00000000000..909a2926d58
--- /dev/null
+++ b/icu4c/source/i18n/tznames_impl.h
@@ -0,0 +1,212 @@
+/*
+ *******************************************************************************
+ * Copyright (C) 2011, International Business Machines Corporation and *
+ * others. All Rights Reserved. *
+ *******************************************************************************
+ */
+
+#ifndef __TZNAMES_IMPL_H__
+#define __TZNAMES_IMPL_H__
+
+
+/**
+ * \file
+ * \brief C++ API: TimeZoneNames object
+ */
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "tznames.h"
+#include "unicode/ures.h"
+#include "unicode/locid.h"
+#include "uhash.h"
+#include "uvector.h"
+#include "umutex.h"
+
+U_NAMESPACE_BEGIN
+
+/*
+ * ZNStringPool Pool of (UChar *) strings. Provides for sharing of repeated
+ * zone strings.
+ */
+struct ZNStringPoolChunk;
+class U_I18N_API ZNStringPool: public UMemory {
+ public:
+ ZNStringPool(UErrorCode &status);
+ ~ZNStringPool();
+
+ /* Get the pooled string that is equal to the supplied string s.
+ * Copy the string into the pool if it is not already present.
+ *
+ * Life time of the returned string is that of the pool.
+ */
+ const UChar *get(const UChar *s, UErrorCode &status);
+
+ /* Get the pooled string that is equal to the supplied string s.
+ * Copy the string into the pool if it is not already present.
+ */
+ const UChar *get(const UnicodeString &s, UErrorCode &status);
+
+ /* Adopt a string into the pool, without copying it.
+ * Used for strings from resource bundles, which will persist without copying.
+ */
+ const UChar *adopt(const UChar *s, UErrorCode &status);
+
+ /* Freeze the string pool. Discards the hash table that is used
+ * for looking up a string. All pointers to pooled strings remain valid.
+ */
+ void freeze();
+
+ private:
+ ZNStringPoolChunk *fChunks;
+ UHashtable *fHash;
+};
+
+/*
+ * Character node used by TextTrieMap
+ */
+struct CharacterNode {
+ // No constructor or destructor.
+ // We malloc and free an uninitalized array of CharacterNode objects
+ // and clear and delete them ourselves.
+
+ void clear();
+ void deleteValues(UObjectDeleter *valueDeleter);
+
+ void addValue(void *value, UObjectDeleter *valueDeleter, UErrorCode &status);
+ inline UBool hasValues() const;
+ inline int32_t countValues() const;
+ inline const void *getValue(int32_t index) const;
+
+ void *fValues; // Union of one single value vs. UVector of values.
+ UChar fCharacter; // UTF-16 code unit.
+ uint16_t fFirstChild; // 0 if no children.
+ uint16_t fNextSibling; // 0 terminates the list.
+ UBool fHasValuesVector;
+ UBool fPadding;
+
+ // No value: fValues == NULL and fHasValuesVector == FALSE
+ // One value: fValues == value and fHasValuesVector == FALSE
+ // >=2 values: fValues == UVector of values and fHasValuesVector == TRUE
+};
+
+inline UBool CharacterNode::hasValues() const {
+ return (UBool)(fValues != NULL);
+}
+
+inline int32_t CharacterNode::countValues() const {
+ return
+ fValues == NULL ? 0 :
+ !fHasValuesVector ? 1 :
+ ((const UVector *)fValues)->size();
+}
+
+inline const void *CharacterNode::getValue(int32_t index) const {
+ if (!fHasValuesVector) {
+ return fValues; // Assume index == 0.
+ } else {
+ return ((const UVector *)fValues)->elementAt(index);
+ }
+}
+
+/*
+ * Search result handler callback interface used by TextTrieMap search.
+ */
+class TextTrieMapSearchResultHandler : public UMemory {
+public:
+ virtual UBool handleMatch(int32_t matchLength,
+ const CharacterNode *node, UErrorCode& status) = 0;
+ virtual ~TextTrieMapSearchResultHandler(); //added to avoid warning
+};
+
+/**
+ * TextTrieMap is a trie implementation for supporting
+ * fast prefix match for the string key.
+ */
+class U_I18N_API TextTrieMap : public UMemory {
+public:
+ TextTrieMap(UBool ignoreCase, UObjectDeleter *valeDeleter);
+ virtual ~TextTrieMap();
+
+ void put(const UnicodeString &key, void *value, ZNStringPool &sp, UErrorCode &status);
+ void put(const UChar*, void *value, UErrorCode &status);
+ void search(const UnicodeString &text, int32_t start,
+ TextTrieMapSearchResultHandler *handler, UErrorCode& status) const;
+ int32_t isEmpty() const;
+
+private:
+ UBool fIgnoreCase;
+ CharacterNode *fNodes;
+ int32_t fNodesCapacity;
+ int32_t fNodesCount;
+
+ UVector *fLazyContents;
+ UBool fIsEmpty;
+ UObjectDeleter *fValueDeleter;
+
+ UBool growNodes();
+ CharacterNode* addChildNode(CharacterNode *parent, UChar c, UErrorCode &status);
+ CharacterNode* getChildNode(CharacterNode *parent, UChar c) const;
+
+ void putImpl(const UnicodeString &key, void *value, UErrorCode &status);
+ void buildTrie(UErrorCode &status);
+ void search(CharacterNode *node, const UnicodeString &text, int32_t start,
+ int32_t index, TextTrieMapSearchResultHandler *handler, UErrorCode &status) const;
+};
+
+
+
+class ZNames;
+class TZNames;
+class TextTrieMap;
+
+class TimeZoneNamesImpl : public TimeZoneNames {
+public:
+ TimeZoneNamesImpl(const Locale& locale, UErrorCode& status);
+
+ virtual ~TimeZoneNamesImpl();
+
+ 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;
+
+ UnicodeString& getExemplarLocationName(const UnicodeString& tzID, UnicodeString& name) const;
+
+ TimeZoneNameMatchInfo* find(const UnicodeString& text, int32_t start, uint32_t types, UErrorCode& status) const;
+
+private:
+
+ Locale fLocale;
+ UMTX fLock;
+
+ UResourceBundle* fZoneStrings;
+
+ UHashtable* fTZNamesMap;
+ UHashtable* fMZNamesMap;
+
+ UBool fNamesTrieFullyLoaded;
+ TextTrieMap fNamesTrie;
+
+ void initialize(const Locale& locale, UErrorCode& status);
+ void cleanup();
+
+ void loadStrings(const UnicodeString& tzCanonicalID);
+
+ ZNames* loadMetaZoneNames(const UnicodeString& mzId);
+ TZNames* loadTimeZoneNames(const UnicodeString& mzId);
+};
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif // __TZNAMES_IMPL_H__
+//eof
+//
diff --git a/icu4c/source/i18n/ucln_in.h b/icu4c/source/i18n/ucln_in.h
index b128bebeb4c..72db0bdab3e 100644
--- a/icu4c/source/i18n/ucln_in.h
+++ b/icu4c/source/i18n/ucln_in.h
@@ -33,8 +33,9 @@ typedef enum ECleanupI18NType {
UCLN_I18N_HEBREW_CALENDAR,
UCLN_I18N_ASTRO_CALENDAR,
UCLN_I18N_CALENDAR,
+ UCLN_I18N_TIMEZONEFORMAT,
+ UCLN_I18N_TIMEZONENAMES,
UCLN_I18N_ZONEMETA,
- UCLN_I18N_ZSFORMAT,
UCLN_I18N_TIMEZONE,
UCLN_I18N_PLURAL_RULE,
UCLN_I18N_CURRENCY,
diff --git a/icu4c/source/i18n/unicode/dtfmtsym.h b/icu4c/source/i18n/unicode/dtfmtsym.h
index d858ba9aca1..f552b0e6f0a 100644
--- a/icu4c/source/i18n/unicode/dtfmtsym.h
+++ b/icu4c/source/i18n/unicode/dtfmtsym.h
@@ -1,6 +1,6 @@
/*
********************************************************************************
-* Copyright (C) 1997-2010, International Business Machines
+* Copyright (C) 1997-2011, International Business Machines
* Corporation and others. All Rights Reserved.
********************************************************************************
*
@@ -37,8 +37,6 @@ U_NAMESPACE_BEGIN
/* forward declaration */
class SimpleDateFormat;
class Hashtable;
-class ZoneStringFormat;
-class SafeZoneStringFormatPtr;
/**
* DateFormatSymbols is a public class for encapsulating localizable date-time
@@ -409,6 +407,10 @@ public:
/**
* Sets timezone strings. These strings are stored in a 2-dimensional array.
+ * Note: SimpleDateFormat no longer use the zone strings stored in
+ * a DateFormatSymbols. Therefore, the time zone strings set by this mthod
+ * have no effects in an instance of SimpleDateFormat for formatting time
+ * zones.
* @param strings The timezone strings as a 2-d array to be copied. (not adopted; caller retains ownership)
* @param rowCount The number of rows (count of first index).
* @param columnCount The number of columns (count of second index).
@@ -631,11 +633,13 @@ private:
int32_t fZoneStringsRowCount;
int32_t fZoneStringsColCount;
- const ZoneStringFormat *fZoneStringFormat;
- ZoneStringFormat *fZSFLocal; // Local ZoneStringFormat instance
- SafeZoneStringFormatPtr *fZSFCachePtr; // Cached ZoneStringFormat
Locale fZSFLocale; // Locale used for getting ZoneStringFormat
+ /**
+ * String used for localized GMT. For example, "GMT"
+ */
+ UnicodeString fGmtZero;
+
/**
* Pattern string used for localized time zone GMT format. For example, "GMT{0}"
*/
@@ -725,17 +729,6 @@ private:
*/
void copyData(const DateFormatSymbols& other);
-
- /**
- * Returns a ZoneStringFormat, used only by SimpleDateFormat for now.
- */
- const ZoneStringFormat* getZoneStringFormat(void) const;
-
- /**
- * Create a ZoneStringFormat by locale if not yet availble
- */
- void initZoneStringFormat(void);
-
/**
* Create zone strings array by locale if not yet available
*/
diff --git a/icu4c/source/i18n/unicode/smpdtfmt.h b/icu4c/source/i18n/unicode/smpdtfmt.h
index 79745e18231..7c0e0a21f1a 100644
--- a/icu4c/source/i18n/unicode/smpdtfmt.h
+++ b/icu4c/source/i18n/unicode/smpdtfmt.h
@@ -41,6 +41,7 @@ class DateFormatSymbols;
class DateFormat;
class MessageFormat;
class FieldPositionHandler;
+class TimeZoneFormat;
/**
*
@@ -1038,6 +1039,11 @@ private:
*/
static const UDateFormatField fgPatternIndexToDateFormatField[];
+ /**
+ * Lazy TimeZoneFormat instantiation, semantically const
+ */
+ TimeZoneFormat *tzFormat() const;
+
/**
* Used to map Calendar field to field level.
* The larger the level, the smaller the field unit.
@@ -1074,6 +1080,11 @@ private:
*/
DateFormatSymbols* fSymbols; // Owned
+ /**
+ * The time zone formatter
+ */
+ TimeZoneFormat* fTimeZoneFormat;
+
/**
* If dates have ambiguous years, we map them into the century starting
* at defaultCenturyStart, which may be any date. If defaultCenturyStart is
diff --git a/icu4c/source/i18n/unicode/timezone.h b/icu4c/source/i18n/unicode/timezone.h
index 0be92d2848f..8a999926278 100644
--- a/icu4c/source/i18n/unicode/timezone.h
+++ b/icu4c/source/i18n/unicode/timezone.h
@@ -730,6 +730,16 @@ private:
static TimeZone* createCustomTimeZone(const UnicodeString&); // Creates a time zone based on the string.
+ /**
+ * Finds the given ID in the Olson tzdata. If the given ID is found in the tzdata,
+ * returns the pointer to the ID resource. This method is exposed through ZoneMeta class
+ * for ICU internal implementation and useful for building hashtable using a time zone
+ * ID as a key.
+ * @param id zone id string
+ * @return the pointer of the ID resource, or NULL.
+ */
+ static const UChar* findID(const UnicodeString& id);
+
/**
* Resolve a link in Olson tzdata. When the given id is known and it's not a link,
* the id itself is returned. When the given id is known and it is a link, then
diff --git a/icu4c/source/i18n/zonemeta.cpp b/icu4c/source/i18n/zonemeta.cpp
index 3aafdd14248..01de17cf062 100644
--- a/icu4c/source/i18n/zonemeta.cpp
+++ b/icu4c/source/i18n/zonemeta.cpp
@@ -22,13 +22,25 @@
#include "cstring.h"
#include "ucln_in.h"
#include "uassert.h"
+#include "uresimp.h"
+#include "uhash.h"
+#include "olsontz.h"
static UMTX gZoneMetaLock = NULL;
+// CLDR Canonical ID mapping table
+static UHashtable *gCanonicalIDCache = NULL;
+static UBool gCanonicalIDCacheInitialized = FALSE;
+
// Metazone mapping table
static UHashtable *gOlsonToMeta = NULL;
static UBool gOlsonToMetaInitialized = FALSE;
+// Available metazone IDs vector and table
+static U_NAMESPACE_QUALIFIER UVector *gMetaZoneIDs = NULL;
+static UHashtable *gMetaZoneIDTable = NULL;
+static UBool gMetaZoneIDsInitialized = FALSE;
+
// Country info vectors
static U_NAMESPACE_QUALIFIER UVector *gSingleZoneCountries = NULL;
static U_NAMESPACE_QUALIFIER UVector *gMultiZonesCountries = NULL;
@@ -36,13 +48,18 @@ static UBool gCountryInfoVectorsInitialized = FALSE;
U_CDECL_BEGIN
-
/**
* Cleanup callback func
*/
static UBool U_CALLCONV zoneMeta_cleanup(void)
{
- umtx_destroy(&gZoneMetaLock);
+ umtx_destroy(&gZoneMetaLock);
+
+ if (gCanonicalIDCache != NULL) {
+ uhash_close(gCanonicalIDCache);
+ gCanonicalIDCache = NULL;
+ }
+ gCanonicalIDCacheInitialized = FALSE;
if (gOlsonToMeta != NULL) {
uhash_close(gOlsonToMeta);
@@ -50,6 +67,14 @@ static UBool U_CALLCONV zoneMeta_cleanup(void)
}
gOlsonToMetaInitialized = FALSE;
+ if (gMetaZoneIDTable != NULL) {
+ uhash_close(gMetaZoneIDTable);
+ }
+ // delete after closing gMetaZoneIDTable, because it holds
+ // value objects held by the hashtable
+ delete gMetaZoneIDs;
+ gMetaZoneIDsInitialized = FALSE;
+
delete gSingleZoneCountries;
delete gMultiZonesCountries;
gCountryInfoVectorsInitialized = FALSE;
@@ -184,16 +209,63 @@ parseDate (const UChar *text, UErrorCode &status) {
return 0;
}
-UnicodeString& U_EXPORT2
-ZoneMeta::getCanonicalCLDRID(const UnicodeString &tzid, UnicodeString &systemID, UErrorCode& status) {
- int32_t len = tzid.length();
- if ( len >= ZID_KEY_MAX ) {
- status = U_ILLEGAL_ARGUMENT_ERROR;
- systemID.remove();
- return systemID;
+const UChar* U_EXPORT2
+ZoneMeta::getCanonicalCLDRID(const UnicodeString &tzid, UErrorCode& status) {
+ if (U_FAILURE(status)) {
+ return NULL;
}
- char id[ZID_KEY_MAX];
+ int32_t len = tzid.length();
+ if (len > ZID_KEY_MAX) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return NULL;
+ }
+
+ // Checking the cached results
+ UBool initialized;
+ UMTX_CHECK(&gZoneMetaLock, gCanonicalIDCacheInitialized, initialized);
+ if (!initialized) {
+ // Create empty hashtable
+ umtx_lock(&gZoneMetaLock);
+ {
+ if (!gCanonicalIDCacheInitialized) {
+ gCanonicalIDCache = uhash_open(uhash_hashUChars, uhash_compareUChars, NULL, &status);
+ if (gCanonicalIDCache == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ }
+ if (U_FAILURE(status)) {
+ gCanonicalIDCache = NULL;
+ return NULL;
+ }
+ // No key/value deleters - keys/values are from a resource bundle
+ gCanonicalIDCacheInitialized = TRUE;
+ ucln_i18n_registerCleanup(UCLN_I18N_ZONEMETA, zoneMeta_cleanup);
+ }
+ }
+ umtx_unlock(&gZoneMetaLock);
+ }
+
+ const UChar *canonicalID = NULL;
+
+ UErrorCode tmpStatus = U_ZERO_ERROR;
+ UChar utzid[ZID_KEY_MAX + 1];
+ tzid.extract(utzid, ZID_KEY_MAX + 1, tmpStatus);
+ U_ASSERT(tmpStatus == U_ZERO_ERROR); // we checked the length of tzid already
+
+ // Check if it was already cached
+ umtx_lock(&gZoneMetaLock);
+ {
+ canonicalID = (const UChar *)uhash_get(gCanonicalIDCache, utzid);
+ }
+ umtx_unlock(&gZoneMetaLock);
+
+ if (canonicalID != NULL) {
+ return canonicalID;
+ }
+
+ // If not, resolve CLDR canonical ID with resource data
+ UBool isInputCanonical = FALSE;
+ char id[ZID_KEY_MAX + 1];
const UChar* idChars = tzid.getBuffer();
u_UCharsToChars(idChars,id,len);
@@ -207,77 +279,126 @@ ZoneMeta::getCanonicalCLDRID(const UnicodeString &tzid, UnicodeString &systemID,
}
}
-
- UErrorCode tmpStatus = U_ZERO_ERROR;
UResourceBundle *top = ures_openDirect(NULL, gTimeZoneTypes, &tmpStatus);
UResourceBundle *rb = ures_getByKey(top, gTypeMapTag, NULL, &tmpStatus);
ures_getByKey(rb, gTimezoneTag, rb, &tmpStatus);
ures_getByKey(rb, id, rb, &tmpStatus);
if (U_SUCCESS(tmpStatus)) {
- // direct map found
- systemID.setTo(tzid);
- ures_close(rb);
- ures_close(top);
- return systemID;
+ // type entry (canonical) found
+ // the input is the canonical ID. resolve to const UChar*
+ canonicalID = TimeZone::findID(tzid);
+ isInputCanonical = TRUE;
}
- // If a map element not found, then look for an alias
- tmpStatus = U_ZERO_ERROR;
- ures_getByKey(top, gTypeAliasTag, rb, &tmpStatus);
- ures_getByKey(rb, gTimezoneTag, rb, &tmpStatus);
- const UChar *alias = ures_getStringByKey(rb,id,NULL,&tmpStatus);
- if (U_SUCCESS(tmpStatus)) {
- // alias found
- ures_close(rb);
- ures_close(top);
- systemID.setTo(alias);
- return systemID;
- }
+ if (canonicalID == NULL) {
+ // If a map element not found, then look for an alias
+ tmpStatus = U_ZERO_ERROR;
+ ures_getByKey(top, gTypeAliasTag, rb, &tmpStatus);
+ ures_getByKey(rb, gTimezoneTag, rb, &tmpStatus);
+ const UChar *canonical = ures_getStringByKey(rb,id,NULL,&tmpStatus);
+ if (U_SUCCESS(tmpStatus)) {
+ // canonical map found
+ canonicalID = canonical;
+ }
- // Dereference the input ID using the tz data
- const UChar *derefer = TimeZone::dereferOlsonLink(tzid);
- if (derefer == NULL) {
- systemID.remove();
- status = U_ILLEGAL_ARGUMENT_ERROR;
- } else {
+ if (canonicalID == NULL) {
+ // Dereference the input ID using the tz data
+ const UChar *derefer = TimeZone::dereferOlsonLink(tzid);
+ if (derefer == NULL) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ } else {
+ len = u_strlen(derefer);
+ u_UCharsToChars(derefer,id,len);
+ id[len] = (char) 0; // Make sure it is null terminated.
- len = u_strlen(derefer);
- u_UCharsToChars(derefer,id,len);
- id[len] = (char) 0; // Make sure it is null terminated.
+ // replace '/' with ':'
+ char *p = id;
+ while (*p++) {
+ if (*p == '/') {
+ *p = ':';
+ }
+ }
- // replace '/' with ':'
- char *p = id;
- while (*p++) {
- if (*p == '/') {
- *p = ':';
+ // If a dereference turned something up then look for an alias.
+ // rb still points to the alias table, so we don't have to go looking
+ // for it.
+ tmpStatus = U_ZERO_ERROR;
+ canonical = ures_getStringByKey(rb,id,NULL,&tmpStatus);
+ if (U_SUCCESS(tmpStatus)) {
+ // canonical map for the dereferenced ID found
+ canonicalID = canonical;
+ } else {
+ canonicalID = derefer;
+ isInputCanonical = TRUE;
+ }
}
}
+ }
+ ures_close(rb);
+ ures_close(top);
- // If a dereference turned something up then look for an alias.
- // rb still points to the alias table, so we don't have to go looking
- // for it.
- tmpStatus = U_ZERO_ERROR;
- const UChar *alias = ures_getStringByKey(rb,id,NULL,&tmpStatus);
- if (U_SUCCESS(tmpStatus)) {
- // alias found
- systemID.setTo(alias);
- } else {
- systemID.setTo(derefer);
+ if (U_SUCCESS(status)) {
+ U_ASSERT(canonicalID != NULL); // canocanilD must be non-NULL here
+
+ // Put the resolved canonical ID to the cache
+ umtx_lock(&gZoneMetaLock);
+ {
+ const UChar* idInCache = (const UChar *)uhash_get(gCanonicalIDCache, utzid);
+ if (idInCache == NULL) {
+ const UChar* key = ZoneMeta::findTimeZoneID(tzid);
+ U_ASSERT(key != NULL);
+ if (key != NULL) {
+ idInCache = (const UChar *)uhash_put(gCanonicalIDCache, (void *)key, (void *)canonicalID, &status);
+ U_ASSERT(idInCache == NULL);
+ }
+ }
+ if (U_SUCCESS(status) && isInputCanonical) {
+ // Also put canonical ID itself into the cache if not exist
+ const UChar *canonicalInCache = (const UChar*)uhash_get(gCanonicalIDCache, canonicalID);
+ if (canonicalInCache == NULL) {
+ canonicalInCache = (const UChar *)uhash_put(gCanonicalIDCache, (void *)canonicalID, (void *)canonicalID, &status);
+ U_ASSERT(canonicalInCache == NULL);
+ }
+ }
}
+ umtx_unlock(&gZoneMetaLock);
}
- ures_close(rb);
- ures_close(top);
- return systemID;
+ return canonicalID;
}
+UnicodeString& U_EXPORT2
+ZoneMeta::getCanonicalCLDRID(const UnicodeString &tzid, UnicodeString &systemID, UErrorCode& status) {
+ const UChar *canonicalID = getCanonicalCLDRID(tzid, status);
+ if (U_FAILURE(status) || canonicalID == NULL) {
+ systemID.setToBogus();
+ return systemID;
+ }
+ systemID.setTo(TRUE, canonicalID, -1);
+ return systemID;
+}
+
+const UChar* U_EXPORT2
+ZoneMeta::getCanonicalCLDRID(const TimeZone& tz) {
+ if (dynamic_cast(&tz) != NULL) {
+ // short cut for OlsonTimeZone
+ const OlsonTimeZone *otz = (const OlsonTimeZone*)&tz;
+ return otz->getCanonicalID();
+ }
+ UErrorCode status = U_ZERO_ERROR;
+ UnicodeString tzID;
+ return getCanonicalCLDRID(tz.getID(tzID), status);
+}
+
+
+
UnicodeString& U_EXPORT2
ZoneMeta::getCanonicalCountry(const UnicodeString &tzid, UnicodeString &canonicalCountry) {
const UChar *region = TimeZone::getRegion(tzid);
if (region != NULL && u_strcmp(gWorld, region) != 0) {
canonicalCountry.setTo(region, -1);
} else {
- canonicalCountry.remove();
+ canonicalCountry.setToBogus();
}
return canonicalCountry;
}
@@ -288,7 +409,7 @@ ZoneMeta::getSingleCountry(const UnicodeString &tzid, UnicodeString &country) {
const UChar *region = TimeZone::getRegion(tzid);
if (region == NULL || u_strcmp(gWorld, region) == 0) {
// special case - unknown or "001"
- country.remove();
+ country.setToBogus();
return country;
}
@@ -322,7 +443,7 @@ ZoneMeta::getSingleCountry(const UnicodeString &tzid, UnicodeString &country) {
umtx_unlock(&gZoneMetaLock);
if (U_FAILURE(status)) {
- country.remove();
+ country.setToBogus();
return country;
}
}
@@ -378,7 +499,7 @@ ZoneMeta::getSingleCountry(const UnicodeString &tzid, UnicodeString &country) {
}
if (multiZones) {
- country.remove();
+ country.setToBogus();
} else {
country.setTo(region, -1);
}
@@ -400,7 +521,7 @@ ZoneMeta::getMetazoneID(const UnicodeString &tzid, UDate date, UnicodeString &re
}
}
if (!isSet) {
- result.remove();
+ result.setToBogus();
}
return result;
}
@@ -408,8 +529,8 @@ ZoneMeta::getMetazoneID(const UnicodeString &tzid, UDate date, UnicodeString &re
const UVector* U_EXPORT2
ZoneMeta::getMetazoneMappings(const UnicodeString &tzid) {
UErrorCode status = U_ZERO_ERROR;
- UChar tzidUChars[ZID_KEY_MAX];
- tzid.extract(tzidUChars, ZID_KEY_MAX, status);
+ UChar tzidUChars[ZID_KEY_MAX + 1];
+ tzid.extract(tzidUChars, ZID_KEY_MAX + 1, status);
if (U_FAILURE(status) || status == U_STRING_NOT_TERMINATED_WARNING) {
return NULL;
}
@@ -506,8 +627,9 @@ ZoneMeta::createMetazoneMappings(const UnicodeString &tzid) {
getCanonicalCLDRID(tzid, canonicalID, status);
if (U_SUCCESS(status)) {
- char tzKey[ZID_KEY_MAX];
- canonicalID.extract(0, canonicalID.length(), tzKey, sizeof(tzKey), US_INV);
+ char tzKey[ZID_KEY_MAX + 1];
+ int32_t tzKeyLen = canonicalID.extract(0, canonicalID.length(), tzKey, sizeof(tzKey), US_INV);
+ tzKey[tzKeyLen] = 0;
// tzid keys are using ':' as separators
char *p = tzKey;
@@ -593,12 +715,13 @@ ZoneMeta::getZoneIdByMetazone(const UnicodeString &mzid, const UnicodeString &re
char keyBuf[ZID_KEY_MAX + 1];
int32_t keyLen = 0;
- if (mzid.length() >= ZID_KEY_MAX) {
- result.remove();
+ if (mzid.length() > ZID_KEY_MAX) {
+ result.setToBogus();
return result;
}
- keyLen = mzid.extract(0, mzid.length(), keyBuf, ZID_KEY_MAX, US_INV);
+ keyLen = mzid.extract(0, mzid.length(), keyBuf, ZID_KEY_MAX + 1, US_INV);
+ keyBuf[keyLen] = 0;
UResourceBundle *rb = ures_openDirect(NULL, gMetaZones, &status);
ures_getByKey(rb, gMapTimezonesTag, rb, &status);
@@ -607,7 +730,8 @@ ZoneMeta::getZoneIdByMetazone(const UnicodeString &mzid, const UnicodeString &re
if (U_SUCCESS(status)) {
// check region mapping
if (region.length() == 2 || region.length() == 3) {
- region.extract(0, region.length(), keyBuf, ZID_KEY_MAX, US_INV);
+ keyLen = region.extract(0, region.length(), keyBuf, ZID_KEY_MAX + 1, US_INV);
+ keyBuf[keyLen] = 0;
tzid = ures_getStringByKey(rb, keyBuf, &tzidLen, &status);
if (status == U_MISSING_RESOURCE_ERROR) {
status = U_ZERO_ERROR;
@@ -621,7 +745,7 @@ ZoneMeta::getZoneIdByMetazone(const UnicodeString &mzid, const UnicodeString &re
ures_close(rb);
if (tzid == NULL) {
- result.remove();
+ result.setToBogus();
} else {
result.setTo(tzid, tzidLen);
}
@@ -629,6 +753,92 @@ ZoneMeta::getZoneIdByMetazone(const UnicodeString &mzid, const UnicodeString &re
return result;
}
+void
+ZoneMeta::initAvailableMetaZoneIDs () {
+ UBool initialized;
+ UMTX_CHECK(&gZoneMetaLock, gMetaZoneIDsInitialized, initialized);
+ if (!initialized) {
+ umtx_lock(&gZoneMetaLock);
+ {
+ if (!gMetaZoneIDsInitialized) {
+ UErrorCode status = U_ZERO_ERROR;
+ UHashtable *metaZoneIDTable = uhash_open(uhash_hashUnicodeString, uhash_compareUnicodeString, NULL, &status);
+ uhash_setKeyDeleter(metaZoneIDTable, uhash_deleteUnicodeString);
+ // No valueDeleter, because the vector maintain the value objects
+ UVector *metaZoneIDs = NULL;
+ if (U_SUCCESS(status)) {
+ metaZoneIDs = new UVector(NULL, uhash_compareUChars, status);
+ if (metaZoneIDs == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ }
+ } else {
+ uhash_close(metaZoneIDTable);
+ }
+ if (U_SUCCESS(status)) {
+ metaZoneIDs->setDeleter(uhash_freeBlock);
+
+ UResourceBundle *rb = ures_openDirect(NULL, gMetaZones, &status);
+ UResourceBundle *bundle = ures_getByKey(rb, gMapTimezonesTag, NULL, &status);
+ UResourceBundle res;
+ ures_initStackObject(&res);
+ while (U_SUCCESS(status) && ures_hasNext(bundle)) {
+ ures_getNextResource(bundle, &res, &status);
+ if (U_FAILURE(status)) {
+ break;
+ }
+ const char *mzID = ures_getKey(&res);
+ int32_t len = uprv_strlen(mzID);
+ UChar *uMzID = (UChar*)uprv_malloc(sizeof(UChar) * (len + 1));
+ if (uMzID == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ break;
+ }
+ u_charsToUChars(mzID, uMzID, len);
+ uMzID[len] = 0;
+ UnicodeString *usMzID = new UnicodeString(uMzID);
+ if (uhash_get(metaZoneIDTable, usMzID) == NULL) {
+ metaZoneIDs->addElement((void *)uMzID, status);
+ uhash_put(metaZoneIDTable, (void *)usMzID, (void *)uMzID, &status);
+ } else {
+ uprv_free(uMzID);
+ delete usMzID;
+ }
+ }
+ if (U_SUCCESS(status)) {
+ gMetaZoneIDs = metaZoneIDs;
+ gMetaZoneIDTable = metaZoneIDTable;
+ gMetaZoneIDsInitialized = TRUE;
+ } else {
+ uhash_close(metaZoneIDTable);
+ delete metaZoneIDs;
+ }
+ ures_close(&res);
+ ures_close(bundle);
+ ures_close(rb);
+ }
+ }
+ }
+ umtx_unlock(&gZoneMetaLock);
+ }
+}
+
+const UVector*
+ZoneMeta::getAvailableMetazoneIDs() {
+ initAvailableMetaZoneIDs();
+ return gMetaZoneIDs;
+}
+
+const UChar*
+ZoneMeta::findMetaZoneID(const UnicodeString& mzid) {
+ initAvailableMetaZoneIDs();
+ return (const UChar*)uhash_get(gMetaZoneIDTable, &mzid);
+}
+
+const UChar*
+ZoneMeta::findTimeZoneID(const UnicodeString& tzid) {
+ return TimeZone::findID(tzid);
+}
+
U_NAMESPACE_END
#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/icu4c/source/i18n/zonemeta.h b/icu4c/source/i18n/zonemeta.h
index fa677c8a65f..085c2af023d 100644
--- a/icu4c/source/i18n/zonemeta.h
+++ b/icu4c/source/i18n/zonemeta.h
@@ -23,6 +23,7 @@ typedef struct OlsonToMetaMappingEntry {
} OlsonToMetaMappingEntry;
class UVector;
+class TimeZone;
class U_I18N_API ZoneMeta {
public:
@@ -35,6 +36,18 @@ public:
*/
static UnicodeString& U_EXPORT2 getCanonicalCLDRID(const UnicodeString &tzid, UnicodeString &systemID, UErrorCode& status);
+ /**
+ * Return the canonical id for this tzid defined by CLDR, which might be the id itself.
+ * This overload method returns a persistent const UChar*, which is guranteed to persist
+ * (a pointer to a resource).
+ */
+ static const UChar* U_EXPORT2 getCanonicalCLDRID(const UnicodeString &tzid, UErrorCode& status);
+
+ /*
+ * Conveninent method returning CLDR canonical ID for the given time zone
+ */
+ static const UChar* U_EXPORT2 getCanonicalCLDRID(const TimeZone& tz);
+
/**
* Return the canonical country code for this tzid. If we have none, or if the time zone
* is not associated with a country, return null.
@@ -60,9 +73,24 @@ public:
static const UVector* U_EXPORT2 getMetazoneMappings(const UnicodeString &tzid);
+ static const UVector* U_EXPORT2 getAvailableMetazoneIDs();
+
+ /**
+ * Returns the pointer to the persistent time zone ID string, or NULL if the given tzid is not in the
+ * tz database. This method is useful when you maintain persistent zone IDs without duplication.
+ */
+ static const UChar* U_EXPORT2 findTimeZoneID(const UnicodeString& tzid);
+
+ /**
+ * Returns the pointer to the persistent meta zone ID string, or NULL if the given mzid is not available.
+ * This method is useful when you maintain persistent meta zone IDs without duplication.
+ */
+ static const UChar* U_EXPORT2 findMetaZoneID(const UnicodeString& mzid);
+
private:
ZoneMeta(); // Prevent construction.
static UVector* createMetazoneMappings(const UnicodeString &tzid);
+ static void initAvailableMetaZoneIDs();
};
U_NAMESPACE_END
diff --git a/icu4c/source/i18n/zstrfmt.cpp b/icu4c/source/i18n/zstrfmt.cpp
deleted file mode 100644
index d4b06c7f2b1..00000000000
--- a/icu4c/source/i18n/zstrfmt.cpp
+++ /dev/null
@@ -1,2228 +0,0 @@
-/*
-*******************************************************************************
-* Copyright (C) 2007-2011, International Business Machines Corporation and *
-* others. All Rights Reserved. *
-*******************************************************************************
-*/
-
-#include "unicode/utypes.h"
-
-#if !UCONFIG_NO_FORMATTING
-
-#include "zstrfmt.h"
-
-#include "unicode/ustring.h"
-#include "unicode/putil.h"
-#include "unicode/msgfmt.h"
-#include "unicode/basictz.h"
-#include "unicode/simpletz.h"
-#include "unicode/rbtz.h"
-#include "unicode/vtzone.h"
-
-#include "uvector.h"
-#include "cstring.h"
-#include "cmemory.h"
-#include "uresimp.h"
-#include "zonemeta.h"
-#include "olsontz.h"
-#include "umutex.h"
-#include "ucln_in.h"
-#include "uassert.h"
-#include "ureslocs.h"
-
-/**
- * global ZoneStringFormatCache stuffs
- */
-static UMTX gZSFCacheLock = NULL;
-static U_NAMESPACE_QUALIFIER ZSFCache *gZoneStringFormatCache = NULL;
-
-U_CDECL_BEGIN
-/**
- * ZoneStringFormatCache cleanup callback func
- */
-static UBool U_CALLCONV zoneStringFormat_cleanup(void)
-{
- umtx_destroy(&gZSFCacheLock);
- if (gZoneStringFormatCache != NULL) {
- delete gZoneStringFormatCache;
- gZoneStringFormatCache = NULL;
- }
- gZoneStringFormatCache = NULL;
- return TRUE;
-}
-
-/**
- * Deleter for ZoneStringInfo
- */
-static void U_CALLCONV
-deleteZoneStringInfo(void *obj) {
- delete (U_NAMESPACE_QUALIFIER ZoneStringInfo*)obj;
-}
-
-/**
- * Deleter for ZoneStrings
- */
-static void U_CALLCONV
-deleteZoneStrings(void *obj) {
- delete (U_NAMESPACE_QUALIFIER ZoneStrings*)obj;
-}
-U_CDECL_END
-
-U_NAMESPACE_BEGIN
-
-#define ZID_KEY_MAX 128
-
-static const char gCountriesTag[] = "Countries";
-static const char gZoneStringsTag[] = "zoneStrings";
-static const char gShortGenericTag[] = "sg";
-static const char gShortStandardTag[] = "ss";
-static const char gShortDaylightTag[] = "sd";
-static const char gLongGenericTag[] = "lg";
-static const char gLongStandardTag[] = "ls";
-static const char gLongDaylightTag[] = "ld";
-static const char gExemplarCityTag[] = "ec";
-static const char gCommonlyUsedTag[] = "cu";
-static const char gFallbackFormatTag[] = "fallbackFormat";
-static const char gRegionFormatTag[] = "regionFormat";
-
-#define MZID_PREFIX_LEN 5
-static const char gMetazoneIdPrefix[] = "meta:";
-
-#define MAX_METAZONES_PER_ZONE 10
-
-static const UChar gDefFallbackPattern[] = {0x7B, 0x31, 0x7D, 0x20, 0x28, 0x7B, 0x30, 0x7D, 0x29, 0x00}; // "{1} ({0})"
-static const UChar gDefRegionPattern[] = {0x7B, 0x30, 0x7D, 0x00}; // "{0}"
-static const UChar gCommonlyUsedTrue[] = {0x31, 0x00}; // "1"
-
-static const double kDstCheckRange = (double)184*U_MILLIS_PER_DAY;
-
-static int32_t
-getTimeZoneTranslationTypeIndex(TimeZoneTranslationType type) {
- int32_t typeIdx = 0;
- switch (type) {
- case LOCATION:
- typeIdx = ZSIDX_LOCATION;
- break;
- case GENERIC_LONG:
- typeIdx = ZSIDX_LONG_GENERIC;
- break;
- case GENERIC_SHORT:
- typeIdx = ZSIDX_SHORT_GENERIC;
- break;
- case STANDARD_LONG:
- typeIdx = ZSIDX_LONG_STANDARD;
- break;
- case STANDARD_SHORT:
- typeIdx = ZSIDX_SHORT_STANDARD;
- break;
- case DAYLIGHT_LONG:
- typeIdx = ZSIDX_LONG_DAYLIGHT;
- break;
- case DAYLIGHT_SHORT:
- typeIdx = ZSIDX_SHORT_DAYLIGHT;
- break;
- }
- return typeIdx;
-}
-
-static int32_t
-getTimeZoneTranslationType(TimeZoneTranslationTypeIndex typeIdx) {
- int32_t type = 0;
- switch (typeIdx) {
- case ZSIDX_LOCATION:
- type = LOCATION;
- break;
- case ZSIDX_LONG_GENERIC:
- type = GENERIC_LONG;
- break;
- case ZSIDX_SHORT_GENERIC:
- type = GENERIC_SHORT;
- break;
- case ZSIDX_LONG_STANDARD:
- type = STANDARD_LONG;
- break;
- case ZSIDX_SHORT_STANDARD:
- type = STANDARD_SHORT;
- break;
- case ZSIDX_LONG_DAYLIGHT:
- type = DAYLIGHT_LONG;
- break;
- case ZSIDX_COUNT:
- case ZSIDX_SHORT_DAYLIGHT:
- type = DAYLIGHT_SHORT;
- break;
- default:
- break;
- }
- return type;
-}
-
-#define DEFAULT_CHARACTERNODE_CAPACITY 1
-
-// ----------------------------------------------------------------------------
-void CharacterNode::clear() {
- uprv_memset(this, 0, sizeof(*this));
-}
-
-void CharacterNode::deleteValues() {
- if (fValues == NULL) {
- // Do nothing.
- } else if (!fHasValuesVector) {
- deleteZoneStringInfo(fValues);
- } else {
- delete (UVector *)fValues;
- }
-}
-
-void
-CharacterNode::addValue(void *value, UErrorCode &status) {
- if (U_FAILURE(status)) {
- deleteZoneStringInfo(value);
- return;
- }
- if (fValues == NULL) {
- fValues = value;
- } else {
- // At least one value already.
- if (!fHasValuesVector) {
- // There is only one value so far, and not in a vector yet.
- // Create a vector and add the old value.
- UVector *values = new UVector(deleteZoneStringInfo, NULL, DEFAULT_CHARACTERNODE_CAPACITY, status);
- if (U_FAILURE(status)) {
- deleteZoneStringInfo(value);
- return;
- }
- values->addElement(fValues, status);
- fValues = values;
- fHasValuesVector = TRUE;
- }
- // Add the new value.
- ((UVector *)fValues)->addElement(value, status);
- }
-}
-
-//----------------------------------------------------------------------------
-// Virtual destructor to avoid warning
-TextTrieMapSearchResultHandler::~TextTrieMapSearchResultHandler(){
-}
-
-// ----------------------------------------------------------------------------
-TextTrieMap::TextTrieMap(UBool ignoreCase)
-: fIgnoreCase(ignoreCase), fNodes(NULL), fNodesCapacity(0), fNodesCount(0),
- fLazyContents(NULL), fIsEmpty(TRUE) {
-}
-
-TextTrieMap::~TextTrieMap() {
- int32_t index;
- for (index = 0; index < fNodesCount; ++index) {
- fNodes[index].deleteValues();
- }
- uprv_free(fNodes);
- if (fLazyContents != NULL) {
- for (int32_t i=0; isize(); i+=2) {
- ZoneStringInfo *zsinf = (ZoneStringInfo *)fLazyContents->elementAt(i+1);
- delete zsinf;
- }
- delete fLazyContents;
- }
-}
-
-int32_t TextTrieMap::isEmpty() const {
- // Use a separate field for fIsEmpty because it will remain unchanged once the
- // Trie is built, while fNodes and fLazyContents change with the lazy init
- // of the nodes structure. Trying to test the changing fields has
- // thread safety complications.
- return fIsEmpty;
-}
-
-
-// We defer actually building the TextTrieMap node structure until the first time a
-// search is performed. put() simply saves the parameters in case we do
-// eventually need to build it.
-//
-void
-TextTrieMap::put(const UnicodeString &key, void *value, ZSFStringPool &sp, UErrorCode &status) {
- fIsEmpty = FALSE;
- if (fLazyContents == NULL) {
- fLazyContents = new UVector(status);
- if (fLazyContents == NULL) {
- status = U_MEMORY_ALLOCATION_ERROR;
- }
- }
- if (U_FAILURE(status)) {
- return;
- }
- UChar *s = const_cast(sp.get(key, status));
- fLazyContents->addElement(s, status);
- fLazyContents->addElement(value, status);
-}
-
-
-void
-TextTrieMap::putImpl(const UnicodeString &key, void *value, UErrorCode &status) {
- if (fNodes == NULL) {
- fNodesCapacity = 512;
- fNodes = (CharacterNode *)uprv_malloc(fNodesCapacity * sizeof(CharacterNode));
- fNodes[0].clear(); // Init root node.
- fNodesCount = 1;
- }
-
- UnicodeString foldedKey;
- const UChar *keyBuffer;
- int32_t keyLength;
- if (fIgnoreCase) {
- // Ok to use fastCopyFrom() because we discard the copy when we return.
- foldedKey.fastCopyFrom(key).foldCase();
- keyBuffer = foldedKey.getBuffer();
- keyLength = foldedKey.length();
- } else {
- keyBuffer = key.getBuffer();
- keyLength = key.length();
- }
-
- CharacterNode *node = fNodes;
- int32_t index;
- for (index = 0; index < keyLength; ++index) {
- node = addChildNode(node, keyBuffer[index], status);
- }
- node->addValue(value, status);
-}
-
-UBool
-TextTrieMap::growNodes() {
- if (fNodesCapacity == 0xffff) {
- return FALSE; // We use 16-bit node indexes.
- }
- int32_t newCapacity = fNodesCapacity + 1000;
- if (newCapacity > 0xffff) {
- newCapacity = 0xffff;
- }
- CharacterNode *newNodes = (CharacterNode *)uprv_malloc(newCapacity * sizeof(CharacterNode));
- if (newNodes == NULL) {
- return FALSE;
- }
- uprv_memcpy(newNodes, fNodes, fNodesCount * sizeof(CharacterNode));
- uprv_free(fNodes);
- fNodes = newNodes;
- fNodesCapacity = newCapacity;
- return TRUE;
-}
-
-CharacterNode*
-TextTrieMap::addChildNode(CharacterNode *parent, UChar c, UErrorCode &status) {
- if (U_FAILURE(status)) {
- return NULL;
- }
- // Linear search of the sorted list of children.
- uint16_t prevIndex = 0;
- uint16_t nodeIndex = parent->fFirstChild;
- while (nodeIndex > 0) {
- CharacterNode *current = fNodes + nodeIndex;
- UChar childCharacter = current->fCharacter;
- if (childCharacter == c) {
- return current;
- } else if (childCharacter > c) {
- break;
- }
- prevIndex = nodeIndex;
- nodeIndex = current->fNextSibling;
- }
-
- // Ensure capacity. Grow fNodes[] if needed.
- if (fNodesCount == fNodesCapacity) {
- int32_t parentIndex = (int32_t)(parent - fNodes);
- if (!growNodes()) {
- status = U_MEMORY_ALLOCATION_ERROR;
- return NULL;
- }
- parent = fNodes + parentIndex;
- }
-
- // Insert a new child node with c in sorted order.
- CharacterNode *node = fNodes + fNodesCount;
- node->clear();
- node->fCharacter = c;
- node->fNextSibling = nodeIndex;
- if (prevIndex == 0) {
- parent->fFirstChild = (uint16_t)fNodesCount;
- } else {
- fNodes[prevIndex].fNextSibling = (uint16_t)fNodesCount;
- }
- ++fNodesCount;
- return node;
-}
-
-CharacterNode*
-TextTrieMap::getChildNode(CharacterNode *parent, UChar c) const {
- // Linear search of the sorted list of children.
- uint16_t nodeIndex = parent->fFirstChild;
- while (nodeIndex > 0) {
- CharacterNode *current = fNodes + nodeIndex;
- UChar childCharacter = current->fCharacter;
- if (childCharacter == c) {
- return current;
- } else if (childCharacter > c) {
- break;
- }
- nodeIndex = current->fNextSibling;
- }
- return NULL;
-}
-
-// Mutex for protecting the lazy creation of the Trie node structure on the first call to search().
-static UMTX TextTrieMutex;
-
-// buildTrie() - The Trie node structure is needed. Create it from the data that was
-// saved at the time the ZoneStringFormatter was created. The Trie is only
-// needed for parsing operations, which are less common than formatting,
-// and the Trie is big, which is why its creation is deferred until first use.
-void TextTrieMap::buildTrie(UErrorCode &status) {
- umtx_lock(&TextTrieMutex);
- if (fLazyContents != NULL) {
- for (int32_t i=0; isize(); i+=2) {
- const UChar *key = (UChar *)fLazyContents->elementAt(i);
- void *val = fLazyContents->elementAt(i+1);
- UnicodeString keyString(TRUE, key, -1); // Aliasing UnicodeString constructor.
- putImpl(keyString, val, status);
- }
- delete fLazyContents;
- fLazyContents = NULL;
- }
- umtx_unlock(&TextTrieMutex);
-}
-
-
-void
-TextTrieMap::search(const UnicodeString &text, int32_t start,
- TextTrieMapSearchResultHandler *handler, UErrorCode &status) const {
- UBool trieNeedsInitialization = FALSE;
- UMTX_CHECK(&TextTrieMutex, fLazyContents != NULL, trieNeedsInitialization);
- if (trieNeedsInitialization) {
- TextTrieMap *nonConstThis = const_cast(this);
- nonConstThis->buildTrie(status);
- }
- if (fNodes == NULL) {
- return;
- }
- search(fNodes, text, start, start, handler, status);
-}
-
-void
-TextTrieMap::search(CharacterNode *node, const UnicodeString &text, int32_t start,
- int32_t index, TextTrieMapSearchResultHandler *handler, UErrorCode &status) const {
- if (U_FAILURE(status)) {
- return;
- }
- if (node->hasValues()) {
- if (!handler->handleMatch(index - start, node, status)) {
- return;
- }
- if (U_FAILURE(status)) {
- return;
- }
- }
- UChar32 c = text.char32At(index);
- if (fIgnoreCase) {
- // size of character may grow after fold operation
- UnicodeString tmp(c);
- tmp.foldCase();
- int32_t tmpidx = 0;
- while (tmpidx < tmp.length()) {
- c = tmp.char32At(tmpidx);
- node = getChildNode(node, c);
- if (node == NULL) {
- break;
- }
- tmpidx = tmp.moveIndex32(tmpidx, 1);
- }
- } else {
- node = getChildNode(node, c);
- }
- if (node != NULL) {
- search(node, text, start, index+1, handler, status);
- }
-}
-
-// ----------------------------------------------------------------------------
-ZoneStringInfo::ZoneStringInfo(const UnicodeString &id, const UnicodeString &str,
- TimeZoneTranslationType type, ZSFStringPool &sp, UErrorCode &status)
-: fType(type) {
- fId = sp.get(id, status);
- fStr = sp.get(str, status);
-}
-
-ZoneStringInfo::~ZoneStringInfo() {
-}
-
-
-// ----------------------------------------------------------------------------
-ZoneStringSearchResultHandler::ZoneStringSearchResultHandler(UErrorCode &status)
-: fResults(status)
-{
- clear();
-}
-
-ZoneStringSearchResultHandler::~ZoneStringSearchResultHandler() {
- clear();
-}
-
-UBool
-ZoneStringSearchResultHandler::handleMatch(int32_t matchLength, const CharacterNode *node, UErrorCode &status) {
- if (U_FAILURE(status)) {
- return FALSE;
- }
- if (node->hasValues()) {
- int32_t valuesCount = node->countValues();
- for (int32_t i = 0; i < valuesCount; i++) {
- ZoneStringInfo *zsinfo = (ZoneStringInfo*)node->getValue(i);
- if (zsinfo == NULL) {
- break;
- }
- // Update the results
- UBool foundType = FALSE;
- for (int32_t j = 0; j < fResults.size(); j++) {
- ZoneStringInfo *tmp = (ZoneStringInfo*)fResults.elementAt(j);
- if (zsinfo->fType == tmp->fType) {
- int32_t lenidx = getTimeZoneTranslationTypeIndex(tmp->fType);
- if (matchLength > fMatchLen[lenidx]) {
- // Same type, longer match
- fResults.setElementAt(zsinfo, j);
- fMatchLen[lenidx] = matchLength;
- }
- foundType = TRUE;
- break;
- }
- }
- if (!foundType) {
- // not found in the current list
- fResults.addElement(zsinfo, status);
- fMatchLen[getTimeZoneTranslationTypeIndex(zsinfo->fType)] = matchLength;
- }
- }
- }
- return TRUE;
-}
-
-int32_t
-ZoneStringSearchResultHandler::countMatches(void) {
- return fResults.size();
-}
-
-const ZoneStringInfo*
-ZoneStringSearchResultHandler::getMatch(int32_t index, int32_t &matchLength) {
- ZoneStringInfo *zsinfo = NULL;
- if (index < fResults.size()) {
- zsinfo = (ZoneStringInfo*)fResults.elementAt(index);
- matchLength = fMatchLen[getTimeZoneTranslationTypeIndex(zsinfo->fType)];
- }
- return zsinfo;
-}
-
-void
-ZoneStringSearchResultHandler::clear(void) {
- fResults.removeAllElements();
- for (int32_t i = 0; i < (int32_t)(sizeof(fMatchLen)/sizeof(fMatchLen[0])); i++) {
- fMatchLen[i] = 0;
- }
-}
-
-// Mutex for protecting the lazy load of a zone ID (or a full load) to ZoneStringFormat structures.
-static UMTX ZoneStringFormatMutex;
-
-
-// ----------------------------------------------------------------------------
-ZoneStringFormat::ZoneStringFormat(const UnicodeString* const* strings,
- int32_t rowCount, int32_t columnCount, UErrorCode &status)
-: fLocale(""),
- fTzidToStrings(NULL),
- fMzidToStrings(NULL),
- fZoneStringsTrie(TRUE),
- fStringPool(status),
- fZoneStringsArray(NULL),
- fMetazoneItem(NULL),
- fZoneItem(NULL),
- fIsFullyLoaded(FALSE)
-{
- if (U_FAILURE(status)) {
- return;
- }
- fLocale.setToBogus();
- if (strings == NULL || columnCount <= 0 || rowCount <= 0) {
- status = U_ILLEGAL_ARGUMENT_ERROR;
- return;
- }
- fTzidToStrings = uhash_open(uhash_hashUChars, // key hash function
- uhash_compareUChars, // key comparison function
- NULL, // Value comparison function
- &status);
- fMzidToStrings = uhash_open(uhash_hashUChars,
- uhash_compareUChars,
- NULL,
- &status);
-
- uhash_setValueDeleter(fTzidToStrings, deleteZoneStrings);
- uhash_setValueDeleter(fMzidToStrings, deleteZoneStrings);
-
- for (int32_t row = 0; row < rowCount; row++) {
- if (strings[row][0].isEmpty()) {
- continue;
- }
- UnicodeString *names = new UnicodeString[ZSIDX_COUNT];
- for (int32_t col = 1; col < columnCount; col++) {
- if (!strings[row][col].isEmpty()) {
- int32_t typeIdx = -1;
- switch (col) {
- case 1:
- typeIdx = ZSIDX_LONG_STANDARD;
- break;
- case 2:
- typeIdx = ZSIDX_SHORT_STANDARD;
- break;
- case 3:
- typeIdx = ZSIDX_LONG_DAYLIGHT;
- break;
- case 4:
- typeIdx = ZSIDX_SHORT_DAYLIGHT;
- break;
- case 5:
- typeIdx = ZSIDX_LOCATION;
- break;
- case 6:
- typeIdx = ZSIDX_LONG_GENERIC;
- break;
- case 7:
- typeIdx = ZSIDX_SHORT_GENERIC;
- break;
- }
- if (typeIdx != -1) {
- names[typeIdx].setTo(strings[row][col]);
-
- // Put the name into the trie
- int32_t type = getTimeZoneTranslationType((TimeZoneTranslationTypeIndex)typeIdx);
- ZoneStringInfo *zsinf = new ZoneStringInfo(strings[row][0],
- strings[row][col],
- (TimeZoneTranslationType)type,
- fStringPool,
- status);
- fZoneStringsTrie.put(strings[row][col], zsinf, fStringPool, status);
- if (U_FAILURE(status)) {
- delete zsinf;
- goto error_cleanup;
- }
- }
- }
- }
- // Note: ZoneStrings constructor adopts and delete the names array.
- ZoneStrings *zstrings = new ZoneStrings(names, ZSIDX_COUNT, TRUE, NULL, 0, 0,
- fStringPool, status);
- UChar *utzid = const_cast(fStringPool.get(strings[row][0], status));
- uhash_put(fTzidToStrings, utzid, zstrings, &status);
- if (U_FAILURE(status)) {
- delete zstrings;
- goto error_cleanup;
- }
- }
- fStringPool.freeze();
- fIsFullyLoaded = TRUE;
- return;
-
-error_cleanup:
- return;
-}
-
-ZoneStringFormat::ZoneStringFormat(const Locale &locale, UErrorCode &status)
-: fLocale(locale),
- fTzidToStrings(NULL),
- fMzidToStrings(NULL),
- fZoneStringsTrie(TRUE),
- fStringPool(status),
- fZoneStringsArray(NULL),
- fMetazoneItem(NULL),
- fZoneItem(NULL),
- fIsFullyLoaded(FALSE)
-{
- if (U_FAILURE(status)) {
- return;
- }
- fTzidToStrings = uhash_open(uhash_hashUChars, // key hash function
- uhash_compareUChars, // key comparison function
- NULL, // Value comparison function
- &status);
- fMzidToStrings = uhash_open(uhash_hashUChars, // key hash function
- uhash_compareUChars, // key comparison function
- NULL, // Value comparison function
- &status);
- uhash_setValueDeleter(fTzidToStrings, deleteZoneStrings);
- uhash_setValueDeleter(fMzidToStrings, deleteZoneStrings);
-}
-
-// Load only a single zone
-void
-ZoneStringFormat::loadZone(const UnicodeString &utzid, UErrorCode &status)
-{
- if (fIsFullyLoaded) {
- return;
- }
-
- if (U_FAILURE(status)) {
- return;
- }
-
- umtx_lock(&ZoneStringFormatMutex);
-
- if (fZoneStringsArray == NULL) {
- fZoneStringsArray = ures_open(U_ICUDATA_ZONE, fLocale.getName(), &status);
- fZoneStringsArray = ures_getByKeyWithFallback(fZoneStringsArray, gZoneStringsTag, fZoneStringsArray, &status);
- if (U_FAILURE(status)) {
- // If no locale bundles are available, zoneStrings will be null.
- // We still want to go through the rest of zone strings initialization,
- // because generic location format is generated from tzid for the case.
- // The rest of code should work even zoneStrings is null.
- status = U_ZERO_ERROR;
- ures_close(fZoneStringsArray);
- fZoneStringsArray = NULL;
- }
- }
-
- // Skip non-canonical IDs
- UnicodeString canonicalID;
- ZoneMeta::getCanonicalCLDRID(utzid, canonicalID, status);
- if (U_FAILURE(status)) {
- // Ignore unknown ID - we should not get here, but just in case.
- // status = U_ZERO_ERROR;
- umtx_unlock(&ZoneStringFormatMutex);
- return;
- }
-
- if (U_SUCCESS(status)) {
- if (uhash_count(fTzidToStrings) > 0) {
- ZoneStrings *zstrings = (ZoneStrings*)uhash_get(fTzidToStrings, canonicalID.getTerminatedBuffer());
- if (zstrings != NULL) {
- umtx_unlock(&ZoneStringFormatMutex);
- return; // We already about this one
- }
- }
- }
-
- addSingleZone(canonicalID, status);
-
- umtx_unlock(&ZoneStringFormatMutex);
-}
-
-// Load only a single zone
-void
-ZoneStringFormat::addSingleZone(UnicodeString &utzid, UErrorCode &status)
-{
- if (U_FAILURE(status)) {
- return;
- }
-
- if (uhash_count(fTzidToStrings) > 0) {
- ZoneStrings *zstrings = (ZoneStrings*)uhash_get(fTzidToStrings, utzid.getTerminatedBuffer());
- if (zstrings != NULL) {
- return; // We already about this one
- }
- }
-
- MessageFormat *fallbackFmt = NULL;
- MessageFormat *regionFmt = NULL;
-
- fallbackFmt = getFallbackFormat(fLocale, status);
- if (U_FAILURE(status)) {
- goto error_cleanup;
- }
- regionFmt = getRegionFormat(fLocale, status);
- if (U_FAILURE(status)) {
- goto error_cleanup;
- }
-
-
- {
- char zidkey[ZID_KEY_MAX+1];
- char tzid[ZID_KEY_MAX+1];
- utzid.extract(0, utzid.length(), zidkey, ZID_KEY_MAX, US_INV);
- utzid.extract(0, utzid.length(), tzid, ZID_KEY_MAX, US_INV);
-
- const UChar *zstrarray[ZSIDX_COUNT];
- const UChar *mzstrarray[ZSIDX_COUNT];
- UnicodeString mzPartialLoc[MAX_METAZONES_PER_ZONE][4];
-
- // Replace '/' with ':'
- char *pCity = NULL;
- char *p = zidkey;
- while (*p) {
- if (*p == '/') {
- *p = ':';
- pCity = p + 1;
- }
- p++;
- }
-
- if (fZoneStringsArray != NULL) {
- fZoneItem = ures_getByKeyWithFallback(fZoneStringsArray, zidkey, fZoneItem, &status);
- if (U_FAILURE(status)) {
- // If failed to open the zone item, create only location string
- ures_close(fZoneItem);
- fZoneItem = NULL;
- status = U_ZERO_ERROR;
- }
- }
-
- UnicodeString region;
- getRegion(region);
-
- zstrarray[ZSIDX_LONG_STANDARD] = getZoneStringFromBundle(fZoneItem, gLongStandardTag);
- zstrarray[ZSIDX_SHORT_STANDARD] = getZoneStringFromBundle(fZoneItem, gShortStandardTag);
- zstrarray[ZSIDX_LONG_DAYLIGHT] = getZoneStringFromBundle(fZoneItem, gLongDaylightTag);
- zstrarray[ZSIDX_SHORT_DAYLIGHT] = getZoneStringFromBundle(fZoneItem, gShortDaylightTag);
- zstrarray[ZSIDX_LONG_GENERIC] = getZoneStringFromBundle(fZoneItem, gLongGenericTag);
- zstrarray[ZSIDX_SHORT_GENERIC] = getZoneStringFromBundle(fZoneItem, gShortGenericTag);
-
- // Compose location format string
- UnicodeString location;
- UnicodeString country;
- UnicodeString city;
- UnicodeString countryCode;
- ZoneMeta::getCanonicalCountry(utzid, countryCode);
- if (!countryCode.isEmpty()) {
- const UChar* tmpCity = getZoneStringFromBundle(fZoneItem, gExemplarCityTag);
- if (tmpCity != NULL) {
- city.setTo(TRUE, tmpCity, -1);
- } else {
- city.setTo(UnicodeString(pCity, -1, US_INV));
- // Replace '_' with ' '
- for (int32_t i = 0; i < city.length(); i++) {
- if (city.charAt(i) == (UChar)0x5F /*'_'*/) {
- city.setCharAt(i, (UChar)0x20 /*' '*/);
- }
- }
- }
- getLocalizedCountry(countryCode, fLocale, country);
- UnicodeString singleCountry;
- ZoneMeta::getSingleCountry(utzid, singleCountry);
- FieldPosition fpos;
- if (singleCountry.isEmpty()) {
- Formattable params [] = {
- Formattable(city),
- Formattable(country)
- };
- fallbackFmt->format(params, 2, location, fpos, status);
- } else {
- // If the zone is only one zone in the country, do not add city
- Formattable params [] = {
- Formattable(country)
- };
- regionFmt->format(params, 1, location, fpos, status);
- }
- if (U_FAILURE(status)) {
- goto error_cleanup;
- }
-
- zstrarray[ZSIDX_LOCATION] = location.getTerminatedBuffer();
- } else {
- if (uprv_strlen(tzid) > 4 && uprv_strncmp(tzid, "Etc/", 4) == 0) {
- // "Etc/xxx" is not associated with a specific location, so localized
- // GMT format is always used as generic location format.
- zstrarray[ZSIDX_LOCATION] = NULL;
- } else {
- // When a new time zone ID, which is actually associated with a specific
- // location, is added in tzdata, but the current CLDR data does not have
- // the information yet, ICU creates a generic location string based on
- // the ID. This implementation supports canonical time zone round trip
- // with format pattern "VVVV". See #6602 for the details.
- UnicodeString loc(utzid);
- int32_t slashIdx = loc.lastIndexOf((UChar)0x2f);
- if (slashIdx == -1) {
- // A time zone ID without slash in the tz database is not
- // associated with a specific location. For instances,
- // MET, CET, EET and WET fall into this category.
- // In this case, we still use GMT format as fallback.
- zstrarray[ZSIDX_LOCATION] = NULL;
- } else {
- FieldPosition fpos;
- Formattable params[] = {
- Formattable(loc)
- };
- regionFmt->format(params, 1, location, fpos, status);
- if (U_FAILURE(status)) {
- goto error_cleanup;
- }
- zstrarray[ZSIDX_LOCATION] = location.getTerminatedBuffer();
- }
- }
- }
-
- UBool commonlyUsed = isCommonlyUsed(fZoneItem);
-
- // Resolve metazones used by this zone
- int32_t mzPartialLocIdx = 0;
- const UVector *metazoneMappings = ZoneMeta::getMetazoneMappings(utzid);
- if (metazoneMappings != NULL) {
- for (int32_t i = 0; i < metazoneMappings->size(); i++) {
- const OlsonToMetaMappingEntry *mzmap =
- (const OlsonToMetaMappingEntry*)metazoneMappings->elementAt(i);
- UnicodeString mzid(mzmap->mzid);
- const ZoneStrings *mzStrings =
- (const ZoneStrings*)uhash_get(fMzidToStrings, mzid.getTerminatedBuffer());
- if (mzStrings == NULL) {
- // If the metazone strings are not yet processed, do it now.
- char mzidkey[ZID_KEY_MAX];
- uprv_strcpy(mzidkey, gMetazoneIdPrefix);
- u_UCharsToChars(mzmap->mzid, mzidkey + MZID_PREFIX_LEN, u_strlen(mzmap->mzid) + 1);
- fMetazoneItem = ures_getByKeyWithFallback(fZoneStringsArray, mzidkey, fMetazoneItem, &status);
- if (U_FAILURE(status)) {
- // No resources available for this metazone
- // Resource bundle will be cleaned up after end of the loop.
- status = U_ZERO_ERROR;
- continue;
- }
- UBool mzCommonlyUsed = isCommonlyUsed(fMetazoneItem);
- mzstrarray[ZSIDX_LONG_STANDARD] = getZoneStringFromBundle(fMetazoneItem, gLongStandardTag);
- mzstrarray[ZSIDX_SHORT_STANDARD] = getZoneStringFromBundle(fMetazoneItem, gShortStandardTag);
- mzstrarray[ZSIDX_LONG_DAYLIGHT] = getZoneStringFromBundle(fMetazoneItem, gLongDaylightTag);
- mzstrarray[ZSIDX_SHORT_DAYLIGHT] = getZoneStringFromBundle(fMetazoneItem, gShortDaylightTag);
- mzstrarray[ZSIDX_LONG_GENERIC] = getZoneStringFromBundle(fMetazoneItem, gLongGenericTag);
- mzstrarray[ZSIDX_SHORT_GENERIC] = getZoneStringFromBundle(fMetazoneItem, gShortGenericTag);
- mzstrarray[ZSIDX_LOCATION] = NULL;
-
- int32_t lastNonNullIdx = ZSIDX_COUNT - 1;
- while (lastNonNullIdx >= 0) {
- if (mzstrarray[lastNonNullIdx] != NULL) {
- break;
- }
- lastNonNullIdx--;
- }
- UnicodeString *strings_mz = NULL;
- ZoneStrings *tmp_mzStrings = NULL;
- if (lastNonNullIdx >= 0) {
- // Create UnicodeString array and put strings to the zone string trie
- strings_mz = new UnicodeString[lastNonNullIdx + 1];
-
- UnicodeString preferredIdForLocale;
- ZoneMeta::getZoneIdByMetazone(mzid, region, preferredIdForLocale);
-
- for (int32_t typeidx = 0; typeidx <= lastNonNullIdx; typeidx++) {
- if (mzstrarray[typeidx] != NULL) {
- strings_mz[typeidx].setTo(TRUE, mzstrarray[typeidx], -1);
-
- // Add a metazone string to the zone string trie
- int32_t type = getTimeZoneTranslationType((TimeZoneTranslationTypeIndex)typeidx);
- ZoneStringInfo *zsinfo = new ZoneStringInfo(
- preferredIdForLocale,
- strings_mz[typeidx],
- (TimeZoneTranslationType)type,
- fStringPool,
- status);
- fZoneStringsTrie.put(strings_mz[typeidx], zsinfo, fStringPool, status);
- if (U_FAILURE(status)) {
- delete []strings_mz;
- goto error_cleanup;
- }
- }
- }
- // Note: ZoneStrings constructor adopts and deletes the strings_mz array.
- tmp_mzStrings = new ZoneStrings(strings_mz, lastNonNullIdx + 1,
- mzCommonlyUsed, NULL, 0, 0, fStringPool, status);
- } else {
- // Create ZoneStrings with empty contents
- tmp_mzStrings = new ZoneStrings(NULL, 0, FALSE, NULL, 0, 0, fStringPool, status);
- }
-
- UChar *umzid = const_cast(fStringPool.get(mzid, status));
- uhash_put(fMzidToStrings, umzid, tmp_mzStrings, &status);
- if (U_FAILURE(status)) {
- goto error_cleanup;
- }
-
- mzStrings = tmp_mzStrings;
- }
-
- // Compose generic partial location format
- UnicodeString lg;
- UnicodeString sg;
-
- mzStrings->getString(ZSIDX_LONG_GENERIC, lg);
- mzStrings->getString(ZSIDX_SHORT_GENERIC, sg);
-
- if (!lg.isEmpty() || !sg.isEmpty()) {
- UBool addMzPartialLocationNames = TRUE;
- for (int32_t j = 0; j < mzPartialLocIdx; j++) {
- if (mzPartialLoc[j][0] == mzid) {
- // already processed
- addMzPartialLocationNames = FALSE;
- break;
- }
- }
- if (addMzPartialLocationNames) {
- UnicodeString *locationPart = NULL;
- // Check if the zone is the preferred zone for the territory associated with the zone
- UnicodeString preferredID;
- ZoneMeta::getZoneIdByMetazone(mzid, countryCode, preferredID);
- if (utzid == preferredID) {
- // Use country for the location
- locationPart = &country;
- } else {
- // Use city for the location
- locationPart = &city;
- }
- // Reset the partial location string array
- mzPartialLoc[mzPartialLocIdx][0].setTo(mzid);
- mzPartialLoc[mzPartialLocIdx][1].remove();
- mzPartialLoc[mzPartialLocIdx][2].remove();
- mzPartialLoc[mzPartialLocIdx][3].remove();
-
- if (locationPart->length() != 0) {
- FieldPosition fpos;
- if (!lg.isEmpty()) {
- Formattable params [] = {
- Formattable(*locationPart),
- Formattable(lg)
- };
- fallbackFmt->format(params, 2, mzPartialLoc[mzPartialLocIdx][1], fpos, status);
- }
- if (!sg.isEmpty()) {
- Formattable params [] = {
- Formattable(*locationPart),
- Formattable(sg)
- };
- fallbackFmt->format(params, 2, mzPartialLoc[mzPartialLocIdx][2], fpos, status);
- if (mzStrings->isShortFormatCommonlyUsed()) {
- mzPartialLoc[mzPartialLocIdx][3].setTo(TRUE, gCommonlyUsedTrue, -1);
- }
- }
- if (U_FAILURE(status)) {
- goto error_cleanup;
- }
- }
- mzPartialLocIdx++;
- }
- }
- }
- }
- // Collected names for a zone
-
- // Create UnicodeString array for localized zone strings
- int32_t lastIdx = ZSIDX_COUNT - 1;
- while (lastIdx >= 0) {
- if (zstrarray[lastIdx] != NULL) {
- break;
- }
- lastIdx--;
- }
- UnicodeString *strings = NULL;
- int32_t stringsCount = lastIdx + 1;
-
- if (stringsCount > 0) {
- strings = new UnicodeString[stringsCount];
- for (int32_t i = 0; i < stringsCount; i++) {
- if (zstrarray[i] != NULL) {
- strings[i].setTo(zstrarray[i], -1);
-
- // Add names to the trie
- int32_t type = getTimeZoneTranslationType((TimeZoneTranslationTypeIndex)i);
- ZoneStringInfo *zsinfo = new ZoneStringInfo(utzid,
- strings[i],
- (TimeZoneTranslationType)type,
- fStringPool,
- status);
- fZoneStringsTrie.put(strings[i], zsinfo, fStringPool, status);
- if (U_FAILURE(status)) {
- delete zsinfo;
- delete[] strings;
- goto error_cleanup;
- }
- }
- }
- }
-
- // Create UnicodeString array for generic partial location strings
- UnicodeString **genericPartialLocationNames = NULL;
- int32_t genericPartialRowCount = mzPartialLocIdx;
- int32_t genericPartialColCount = 4;
-
- if (genericPartialRowCount != 0) {
- genericPartialLocationNames =
- (UnicodeString**)uprv_malloc(genericPartialRowCount * sizeof(UnicodeString*));
- if (genericPartialLocationNames == NULL) {
- status = U_MEMORY_ALLOCATION_ERROR;
- delete[] strings;
- goto error_cleanup;
- }
- for (int32_t i = 0; i < genericPartialRowCount; i++) {
- genericPartialLocationNames[i] = new UnicodeString[genericPartialColCount];
- for (int32_t j = 0; j < genericPartialColCount; j++) {
- genericPartialLocationNames[i][j].setTo(mzPartialLoc[i][j]);
- // Add names to the trie
- if ((j == 1 || j == 2) &&!genericPartialLocationNames[i][j].isEmpty()) {
- ZoneStringInfo *zsinfo;
- TimeZoneTranslationType type = (j == 1) ? GENERIC_LONG : GENERIC_SHORT;
- zsinfo = new ZoneStringInfo(utzid, genericPartialLocationNames[i][j], type,
- fStringPool, status);
- fZoneStringsTrie.put(genericPartialLocationNames[i][j], zsinfo, fStringPool, status);
- if (U_FAILURE(status)) {
- delete[] genericPartialLocationNames[i];
- uprv_free(genericPartialLocationNames);
- delete[] strings;
- goto error_cleanup;
- }
- }
- }
- }
- }
-
- // Finally, create ZoneStrings instance and put it into the tzidToStinrgs map
- ZoneStrings *zstrings = new ZoneStrings(strings, stringsCount, commonlyUsed,
- genericPartialLocationNames, genericPartialRowCount,
- genericPartialColCount, fStringPool, status);
-
- UChar *uutzid = const_cast(fStringPool.get(utzid, status));
- uhash_put(fTzidToStrings, uutzid, zstrings, &status);
- if (U_FAILURE(status)) {
- delete zstrings;
- goto error_cleanup;
- }
- }
-
-error_cleanup:
- if (fallbackFmt != NULL) {
- delete fallbackFmt;
- }
- if (regionFmt != NULL) {
- delete regionFmt;
- }
- // fStringPool.freeze();
-}
-
-void
-ZoneStringFormat::loadFull(UErrorCode &status)
-{
- if (U_FAILURE(status)) {
- return;
- }
- if (fIsFullyLoaded) {
- return;
- }
-
- umtx_lock(&ZoneStringFormatMutex);
-
- if (fZoneStringsArray == NULL) {
- fZoneStringsArray = ures_open(U_ICUDATA_ZONE, fLocale.getName(), &status);
- fZoneStringsArray = ures_getByKeyWithFallback(fZoneStringsArray, gZoneStringsTag, fZoneStringsArray, &status);
- if (U_FAILURE(status)) {
- // If no locale bundles are available, zoneStrings will be null.
- // We still want to go through the rest of zone strings initialization,
- // because generic location format is generated from tzid for the case.
- // The rest of code should work even zoneStrings is null.
- status = U_ZERO_ERROR;
- ures_close(fZoneStringsArray);
- fZoneStringsArray = NULL;
- }
- }
-
- StringEnumeration *tzids = NULL;
-
- tzids = TimeZone::createEnumeration();
- const char *tzid;
- while ((tzid = tzids->next(NULL, status))) {
- if (U_FAILURE(status)) {
- goto error_cleanup;
- }
- // Skip non-canonical IDs
- UnicodeString utzid(tzid, -1, US_INV);
- UnicodeString canonicalID;
- ZoneMeta::getCanonicalCLDRID(utzid, canonicalID, status);
- if (U_FAILURE(status)) {
- // Ignore unknown ID - we should not get here, but just in case.
- status = U_ZERO_ERROR;
- continue;
- }
-
- if (U_SUCCESS(status)) {
- if (uhash_count(fTzidToStrings) > 0) {
- ZoneStrings *zstrings = (ZoneStrings*)uhash_get(fTzidToStrings, canonicalID.getTerminatedBuffer());
- if (zstrings != NULL) {
- continue; // We already about this one
- }
- }
- }
-
- addSingleZone(canonicalID, status);
-
- if (U_FAILURE(status)) {
- goto error_cleanup;
- }
- }
-
- fIsFullyLoaded = TRUE;
-
-error_cleanup:
- if (tzids != NULL) {
- delete tzids;
- }
- fStringPool.freeze();
-
- umtx_unlock(&ZoneStringFormatMutex);
-}
-
-
-ZoneStringFormat::~ZoneStringFormat() {
- uhash_close(fTzidToStrings);
- uhash_close(fMzidToStrings);
- ures_close(fZoneItem);
- ures_close(fMetazoneItem);
- ures_close(fZoneStringsArray);
-}
-
-SafeZoneStringFormatPtr*
-ZoneStringFormat::getZoneStringFormat(const Locale& locale, UErrorCode &status) {
- umtx_lock(&gZSFCacheLock);
- if (gZoneStringFormatCache == NULL) {
- gZoneStringFormatCache = new ZSFCache(10 /* capacity */);
- ucln_i18n_registerCleanup(UCLN_I18N_ZSFORMAT, zoneStringFormat_cleanup);
- }
- umtx_unlock(&gZSFCacheLock);
-
- return gZoneStringFormatCache->get(locale, status);
-}
-
-
-UnicodeString**
-ZoneStringFormat::createZoneStringsArray(UDate date, int32_t &rowCount, int32_t &colCount, UErrorCode &status) const {
- if (U_FAILURE(status)) {
- return NULL;
- }
- ZoneStringFormat *nonConstThis = const_cast(this);
- nonConstThis->loadFull(status);
-
- UnicodeString **result = NULL;
- rowCount = 0;
- colCount = 0;
-
- // Collect canonical time zone IDs
- UVector canonicalIDs(uhash_deleteUnicodeString, uhash_compareUnicodeString, status);
- if (U_FAILURE(status)) {
- return NULL;
- }
- StringEnumeration *tzids = TimeZone::createEnumeration();
- const UChar *tzid;
- while ((tzid = tzids->unext(NULL, status))) {
- if (U_FAILURE(status)) {
- delete tzids;
- return NULL;
- }
- UnicodeString utzid(tzid);
- UnicodeString canonicalID;
- ZoneMeta::getCanonicalCLDRID(UnicodeString(tzid), canonicalID, status);
- if (U_FAILURE(status)) {
- // Ignore unknown ID - we should not get here, but just in case.
- status = U_ZERO_ERROR;
- continue;
- }
- if (utzid == canonicalID) {
- canonicalIDs.addElement(new UnicodeString(utzid), status);
- if (U_FAILURE(status)) {
- delete tzids;
- return NULL;
- }
- }
- }
- delete tzids;
-
- // Allocate array
- result = (UnicodeString**)uprv_malloc(canonicalIDs.size() * sizeof(UnicodeString*));
- if (result == NULL) {
- status = U_MEMORY_ALLOCATION_ERROR;
- return NULL;
- }
- for (int32_t i = 0; i < canonicalIDs.size(); i++) {
- result[i] = new UnicodeString[8];
- UnicodeString *id = (UnicodeString*)canonicalIDs.elementAt(i);
- result[i][0].setTo(*id);
- getLongStandard(*id, date, result[i][1]);
- getShortStandard(*id, date, FALSE, result[i][2]);
- getLongDaylight(*id, date, result[i][3]);
- getShortDaylight(*id, date, FALSE, result[i][4]);
- getGenericLocation(*id, result[i][5]);
- getLongGenericNonLocation(*id, date, result[i][6]);
- getShortGenericNonLocation(*id, date, FALSE, result[i][7]);
- }
-
- rowCount = canonicalIDs.size();
- colCount = 8;
- return result;
-}
-
-UnicodeString&
-ZoneStringFormat::getSpecificLongString(const Calendar &cal, UnicodeString &result,
- UErrorCode &status) const {
- result.remove();
- if (U_FAILURE(status)) {
- return result;
- }
- UnicodeString tzid;
- cal.getTimeZone().getID(tzid);
- UDate date = cal.getTime(status);
- if (cal.get(UCAL_DST_OFFSET, status) == 0) {
- return getString(tzid, ZSIDX_LONG_STANDARD, date, FALSE /*not used*/, result);
- } else {
- return getString(tzid, ZSIDX_LONG_DAYLIGHT, date, FALSE /*not used*/, result);
- }
-}
-
-UnicodeString&
-ZoneStringFormat::getSpecificShortString(const Calendar &cal, UBool commonlyUsedOnly,
- UnicodeString &result, UErrorCode &status) const {
- result.remove();
- if (U_FAILURE(status)) {
- return result;
- }
- UnicodeString tzid;
- cal.getTimeZone().getID(tzid);
- UDate date = cal.getTime(status);
- if (cal.get(UCAL_DST_OFFSET, status) == 0) {
- return getString(tzid, ZSIDX_SHORT_STANDARD, date, commonlyUsedOnly, result);
- } else {
- return getString(tzid, ZSIDX_SHORT_DAYLIGHT, date, commonlyUsedOnly, result);
- }
-}
-
-UnicodeString&
-ZoneStringFormat::getGenericLongString(const Calendar &cal, UnicodeString &result,
- UErrorCode &status) const {
- return getGenericString(cal, FALSE /*long*/, FALSE /* not used */, result, status);
-}
-
-UnicodeString&
-ZoneStringFormat::getGenericShortString(const Calendar &cal, UBool commonlyUsedOnly,
- UnicodeString &result, UErrorCode &status) const {
- return getGenericString(cal, TRUE /*short*/, commonlyUsedOnly, result, status);
-}
-
-UnicodeString&
-ZoneStringFormat::getGenericLocationString(const Calendar &cal, UnicodeString &result,
- UErrorCode &status) const {
- UnicodeString tzid;
- cal.getTimeZone().getID(tzid);
- UDate date = cal.getTime(status);
- return getString(tzid, ZSIDX_LOCATION, date, FALSE /*not used*/, result);
-}
-
-const ZoneStringInfo*
-ZoneStringFormat::findSpecificLong(const UnicodeString &text, int32_t start,
- int32_t &matchLength, UErrorCode &status) const {
- return find(text, start, STANDARD_LONG | DAYLIGHT_LONG, matchLength, status);
-}
-
-const ZoneStringInfo*
-ZoneStringFormat::findSpecificShort(const UnicodeString &text, int32_t start,
- int32_t &matchLength, UErrorCode &status) const {
- return find(text, start, STANDARD_SHORT | DAYLIGHT_SHORT, matchLength, status);
-}
-
-const ZoneStringInfo*
-ZoneStringFormat::findGenericLong(const UnicodeString &text, int32_t start,
- int32_t &matchLength, UErrorCode &status) const {
- return find(text, start, GENERIC_LONG | STANDARD_LONG | LOCATION, matchLength, status);
-}
-
-const ZoneStringInfo*
-ZoneStringFormat::findGenericShort(const UnicodeString &text, int32_t start,
- int32_t &matchLength, UErrorCode &status) const {
- return find(text, start, GENERIC_SHORT | STANDARD_SHORT | LOCATION, matchLength, status);
-}
-
-const ZoneStringInfo*
-ZoneStringFormat::findGenericLocation(const UnicodeString &text, int32_t start,
- int32_t &matchLength, UErrorCode &status) const {
- return find(text, start, LOCATION, matchLength, status);
-}
-
-UnicodeString&
-ZoneStringFormat::getString(const UnicodeString &tzid, TimeZoneTranslationTypeIndex typeIdx, UDate date,
- UBool commonlyUsedOnly, UnicodeString& result) const {
- UErrorCode status = U_ZERO_ERROR;
- result.remove();
- if (!fIsFullyLoaded) {
- // Lazy loading
- ZoneStringFormat *nonConstThis = const_cast(this);
- nonConstThis->loadZone(tzid, status);
- }
-
- // ICU's own array does not have entries for aliases
- UnicodeString canonicalID;
- ZoneMeta::getCanonicalCLDRID(tzid, canonicalID, status);
- if (U_FAILURE(status)) {
- // Unknown ID, but users might have their own data.
- canonicalID.setTo(tzid);
- }
-
- if (uhash_count(fTzidToStrings) > 0) {
- ZoneStrings *zstrings = (ZoneStrings*)uhash_get(fTzidToStrings, canonicalID.getTerminatedBuffer());
- if (zstrings != NULL) {
- switch (typeIdx) {
- case ZSIDX_LONG_STANDARD:
- case ZSIDX_LONG_DAYLIGHT:
- case ZSIDX_LONG_GENERIC:
- case ZSIDX_LOCATION:
- zstrings->getString(typeIdx, result);
- break;
- case ZSIDX_SHORT_STANDARD:
- case ZSIDX_SHORT_DAYLIGHT:
- case ZSIDX_COUNT: //added to avoid warning
- case ZSIDX_SHORT_GENERIC:
- if (!commonlyUsedOnly || zstrings->isShortFormatCommonlyUsed()) {
- zstrings->getString(typeIdx, result);
- }
- break;
- default:
- break;
- }
- }
- }
- if (result.isEmpty() && uhash_count(fMzidToStrings) > 0 && typeIdx != ZSIDX_LOCATION) {
- // Try metazone
- UnicodeString mzid;
- ZoneMeta::getMetazoneID(canonicalID, date, mzid);
- if (!mzid.isEmpty()) {
- ZoneStrings *mzstrings = (ZoneStrings*)uhash_get(fMzidToStrings, mzid.getTerminatedBuffer());
- if (mzstrings != NULL) {
- switch (typeIdx) {
- case ZSIDX_LONG_STANDARD:
- case ZSIDX_LONG_DAYLIGHT:
- case ZSIDX_LONG_GENERIC:
- case ZSIDX_LOCATION:
- mzstrings->getString(typeIdx, result);
- break;
- case ZSIDX_SHORT_STANDARD:
- case ZSIDX_SHORT_DAYLIGHT:
- case ZSIDX_COUNT: //added to avoid warning
- case ZSIDX_SHORT_GENERIC:
- if (!commonlyUsedOnly || mzstrings->isShortFormatCommonlyUsed()) {
- mzstrings->getString(typeIdx, result);
- }
- break;
- default:
- break;
- }
- }
- }
- }
- return result;
-}
-
-UnicodeString&
-ZoneStringFormat::getGenericString(const Calendar &cal, UBool isShort, UBool commonlyUsedOnly,
- UnicodeString &result, UErrorCode &status) const {
- result.remove();
- UDate time = cal.getTime(status);
- if (U_FAILURE(status)) {
- return result;
- }
- const TimeZone &tz = cal.getTimeZone();
- UnicodeString tzid;
- tz.getID(tzid);
-
- if (!fIsFullyLoaded) {
- // Lazy loading
- ZoneStringFormat *nonConstThis = const_cast(this);
- nonConstThis->loadZone(tzid, status);
- }
-
- // ICU's own array does not have entries for aliases
- UnicodeString canonicalID;
- ZoneMeta::getCanonicalCLDRID(tzid, canonicalID, status);
- if (U_FAILURE(status)) {
- // Unknown ID, but users might have their own data.
- status = U_ZERO_ERROR;
- canonicalID.setTo(tzid);
- }
-
- ZoneStrings *zstrings = NULL;
- if (uhash_count(fTzidToStrings) > 0) {
- zstrings = (ZoneStrings*)uhash_get(fTzidToStrings, canonicalID.getTerminatedBuffer());
- if (zstrings != NULL) {
- if (isShort) {
- if (!commonlyUsedOnly || zstrings->isShortFormatCommonlyUsed()) {
- zstrings->getString(ZSIDX_SHORT_GENERIC, result);
- }
- } else {
- zstrings->getString(ZSIDX_LONG_GENERIC, result);
- }
- }
- }
- if (result.isEmpty() && uhash_count(fMzidToStrings) > 0) {
- // try metazone
- int32_t raw, sav;
- UnicodeString mzid;
- ZoneMeta::getMetazoneID(canonicalID, time, mzid);
- if (!mzid.isEmpty()) {
- UBool useStandard = FALSE;
- sav = cal.get(UCAL_DST_OFFSET, status);
- if (U_FAILURE(status)) {
- return result;
- }
- if (sav == 0) {
- useStandard = TRUE;
- // Check if the zone actually uses daylight saving time around the time
- TimeZone *tmptz = tz.clone();
- BasicTimeZone *btz = NULL;
- if (dynamic_cast(tmptz) != NULL
- || dynamic_cast(tmptz) != NULL
- || dynamic_cast(tmptz) != NULL
- || dynamic_cast(tmptz) != NULL) {
- btz = (BasicTimeZone*)tmptz;
- }
-
- if (btz != NULL) {
- TimeZoneTransition before;
- UBool beforTrs = btz->getPreviousTransition(time, TRUE, before);
- if (beforTrs
- && (time - before.getTime() < kDstCheckRange)
- && before.getFrom()->getDSTSavings() != 0) {
- useStandard = FALSE;
- } else {
- TimeZoneTransition after;
- UBool afterTrs = btz->getNextTransition(time, FALSE, after);
- if (afterTrs
- && (after.getTime() - time < kDstCheckRange)
- && after.getTo()->getDSTSavings() != 0) {
- useStandard = FALSE;
- }
- }
- } else {
- // If not BasicTimeZone... only if the instance is not an ICU's implementation.
- // We may get a wrong answer in edge case, but it should practically work OK.
- tmptz->getOffset(time - kDstCheckRange, FALSE, raw, sav, status);
- if (sav != 0) {
- useStandard = FALSE;
- } else {
- tmptz->getOffset(time + kDstCheckRange, FALSE, raw, sav, status);
- if (sav != 0){
- useStandard = FALSE;
- }
- }
- if (U_FAILURE(status)) {
- delete tmptz;
- result.remove();
- return result;
- }
- }
- delete tmptz;
- }
- if (useStandard) {
- getString(canonicalID, (isShort ? ZSIDX_SHORT_STANDARD : ZSIDX_LONG_STANDARD),
- time, commonlyUsedOnly, result);
-
- // Note:
- // In CLDR 1.5.1, a same localization is used for both generic and standard
- // for some metazones in some locales. This is actually data bugs and should
- // be resolved in later versions of CLDR. For now, we check if the standard
- // name is different from its generic name below.
- if (!result.isEmpty()) {
- UnicodeString genericNonLocation;
- getString(canonicalID, (isShort ? ZSIDX_SHORT_GENERIC : ZSIDX_LONG_GENERIC),
- time, commonlyUsedOnly, genericNonLocation);
- if (!genericNonLocation.isEmpty() && result == genericNonLocation) {
- result.remove();
- }
- }
- }
- if (result.isEmpty()) {
- ZoneStrings *mzstrings = (ZoneStrings*)uhash_get(fMzidToStrings, mzid.getTerminatedBuffer());
- if (mzstrings != NULL) {
- if (isShort) {
- if (!commonlyUsedOnly || mzstrings->isShortFormatCommonlyUsed()) {
- mzstrings->getString(ZSIDX_SHORT_GENERIC, result);
- }
- } else {
- mzstrings->getString(ZSIDX_LONG_GENERIC, result);
- }
- }
- if (!result.isEmpty()) {
- // Check if the offsets at the given time matches the preferred zone's offsets
- UnicodeString preferredId;
- UnicodeString region;
- ZoneMeta::getZoneIdByMetazone(mzid, getRegion(region), preferredId);
- if (canonicalID != preferredId) {
- // Check if the offsets at the given time are identical with the preferred zone
- raw = cal.get(UCAL_ZONE_OFFSET, status);
- if (U_FAILURE(status)) {
- result.remove();
- return result;
- }
- TimeZone *preferredZone = TimeZone::createTimeZone(preferredId);
- int32_t prfRaw, prfSav;
- // Check offset in preferred time zone with wall time.
- // With getOffset(time, false, preferredOffsets),
- // you may get incorrect results because of time overlap at DST->STD
- // transition.
- preferredZone->getOffset(time + raw + sav, TRUE, prfRaw, prfSav, status);
- delete preferredZone;
-
- if (U_FAILURE(status)) {
- result.remove();
- return result;
- }
- if ((raw != prfRaw || sav != prfSav) && zstrings != NULL) {
- // Use generic partial location string as fallback
- zstrings->getGenericPartialLocationString(mzid, isShort, commonlyUsedOnly, result);
- }
- }
- }
- }
- }
- }
- if (result.isEmpty()) {
- // Use location format as the final fallback
- getString(canonicalID, ZSIDX_LOCATION, time, FALSE /*not used*/, result);
- }
-
- return result;
-}
-
-UnicodeString&
-ZoneStringFormat::getGenericPartialLocationString(const UnicodeString &tzid, UBool isShort,
- UDate date, UBool commonlyUsedOnly, UnicodeString &result) const {
- UErrorCode status = U_ZERO_ERROR;
- result.remove();
- if (!fIsFullyLoaded) {
- // Lazy loading
- ZoneStringFormat *nonConstThis = const_cast(this);
- nonConstThis->loadZone(tzid, status);
- }
-
- if (uhash_count(fTzidToStrings) <= 0) {
- return result;
- }
-
- UnicodeString canonicalID;
- ZoneMeta::getCanonicalCLDRID(tzid, canonicalID, status);
- if (U_FAILURE(status)) {
- // Unknown ID, so no corresponding meta data.
- return result;
- }
-
- UnicodeString mzid;
- ZoneMeta::getMetazoneID(canonicalID, date, mzid);
-
- if (!mzid.isEmpty()) {
- ZoneStrings *zstrings = (ZoneStrings*)uhash_get(fTzidToStrings, canonicalID.getTerminatedBuffer());
- if (zstrings != NULL) {
- zstrings->getGenericPartialLocationString(mzid, isShort, commonlyUsedOnly, result);
- }
- }
- return result;
-}
-
-// This method does lazy zone string loading
-const ZoneStringInfo*
-ZoneStringFormat::find(const UnicodeString &text, int32_t start, int32_t types,
- int32_t &matchLength, UErrorCode &status) const {
-
- if (U_FAILURE(status)) {
- return NULL;
- }
-
- const ZoneStringInfo * result = subFind(text, start, types, matchLength, status);
- if (fIsFullyLoaded) {
- return result;
- }
- // When zone string data is partially loaded,
- // this method return the result only when
- // the input text is fully consumed.
- if (result != NULL) {
- UnicodeString tmpString;
- matchLength = (result->getString(tmpString)).length();
- if (text.length() - start == matchLength) {
- return result;
- }
- }
-
- // Now load all zone strings
- ZoneStringFormat *nonConstThis = const_cast(this);
- nonConstThis->loadFull(status);
-
- return subFind(text, start, types, matchLength, status);
-}
-
-
-/*
- * Find a prefix matching time zone for the given zone string types.
- * @param text The text contains a time zone string
- * @param start The start index within the text
- * @param types The bit mask representing a set of requested types
- * @return If any zone string matched for the requested types, returns a
- * ZoneStringInfo for the longest match. If no matches are found for
- * the requested types, returns a ZoneStringInfo for the longest match
- * for any other types. If nothing matches at all, returns null.
- */
-const ZoneStringInfo*
-ZoneStringFormat::subFind(const UnicodeString &text, int32_t start, int32_t types,
- int32_t &matchLength, UErrorCode &status) const {
- matchLength = 0;
- if (U_FAILURE(status)) {
- return NULL;
- }
- if (fZoneStringsTrie.isEmpty()) {
- return NULL;
- }
-
- const ZoneStringInfo *result = NULL;
- const ZoneStringInfo *fallback = NULL;
- int32_t fallbackMatchLen = 0;
-
- ZoneStringSearchResultHandler handler(status);
- fZoneStringsTrie.search(text, start, (TextTrieMapSearchResultHandler*)&handler, status);
- if (U_SUCCESS(status)) {
- int32_t numMatches = handler.countMatches();
- for (int32_t i = 0; i < numMatches; i++) {
- int32_t tmpMatchLen = 0; // init. output only param to silence gcc
- const ZoneStringInfo *tmp = handler.getMatch(i, tmpMatchLen);
- if ((types & tmp->fType) != 0) {
- if (result == NULL || matchLength < tmpMatchLen) {
- result = tmp;
- matchLength = tmpMatchLen;
- } else if (matchLength == tmpMatchLen) {
- // Tie breaker - there are some examples that a
- // long standard name is identical with a location
- // name - for example, "Uruguay Time". In this case,
- // we interpret it as generic, not specific.
- if (tmp->isGeneric() && !result->isGeneric()) {
- result = tmp;
- }
- }
- } else if (result == NULL) {
- if (fallback == NULL || fallbackMatchLen < tmpMatchLen) {
- fallback = tmp;
- fallbackMatchLen = tmpMatchLen;
- } else if (fallbackMatchLen == tmpMatchLen) {
- if (tmp->isGeneric() && !fallback->isGeneric()) {
- fallback = tmp;
- }
- }
- }
- }
- if (result == NULL && fallback != NULL) {
- result = fallback;
- matchLength = fallbackMatchLen;
- }
- }
- return result;
-}
-
-
-UnicodeString&
-ZoneStringFormat::getRegion(UnicodeString ®ion) const {
- const char* country = fLocale.getCountry();
- // TODO: Utilize addLikelySubtag in Locale to resolve default region
- // when the implementation is ready.
- region.setTo(UnicodeString(country, -1, US_INV));
- return region;
-}
-
-MessageFormat*
-ZoneStringFormat::getFallbackFormat(const Locale &locale, UErrorCode &status) {
- if (U_FAILURE(status)) {
- return NULL;
- }
- UnicodeString pattern(TRUE, gDefFallbackPattern, -1);
- UResourceBundle *zoneStringsArray = ures_open(U_ICUDATA_ZONE, locale.getName(), &status);
- zoneStringsArray = ures_getByKeyWithFallback(zoneStringsArray, gZoneStringsTag, zoneStringsArray, &status);
- int32_t len;
- const UChar *flbkfmt = ures_getStringByKeyWithFallback(zoneStringsArray, gFallbackFormatTag, &len, &status);
- if (U_SUCCESS(status)) {
- pattern.setTo(flbkfmt);
- } else {
- status = U_ZERO_ERROR;
- }
- ures_close(zoneStringsArray);
-
- MessageFormat *fallbackFmt = new MessageFormat(pattern, status);
- return fallbackFmt;
-}
-
-MessageFormat*
-ZoneStringFormat::getRegionFormat(const Locale& locale, UErrorCode &status) {
- if (U_FAILURE(status)) {
- return NULL;
- }
- UnicodeString pattern(TRUE, gDefRegionPattern, -1);
- UResourceBundle *zoneStringsArray = ures_open(U_ICUDATA_ZONE, locale.getName(), &status);
- zoneStringsArray = ures_getByKeyWithFallback(zoneStringsArray, gZoneStringsTag, zoneStringsArray, &status);
- int32_t len;
- const UChar *regionfmt = ures_getStringByKeyWithFallback(zoneStringsArray, gRegionFormatTag, &len, &status);
- if (U_SUCCESS(status)) {
- pattern.setTo(regionfmt);
- } else {
- status = U_ZERO_ERROR;
- }
- ures_close(zoneStringsArray);
-
- MessageFormat *regionFmt = new MessageFormat(pattern, status);
- return regionFmt;
-}
-
-const UChar*
-ZoneStringFormat::getZoneStringFromBundle(const UResourceBundle *zoneitem, const char *key) {
- const UChar *str = NULL;
- if (zoneitem != NULL) {
- UErrorCode status = U_ZERO_ERROR;
- int32_t len;
- str = ures_getStringByKeyWithFallback(zoneitem, key, &len, &status);
- str = fStringPool.adopt(str, status);
- if (U_FAILURE(status)) {
- str = NULL;
- }
- }
- return str;
-}
-
-UBool
-ZoneStringFormat::isCommonlyUsed(const UResourceBundle *zoneitem) {
- if (zoneitem == NULL) {
- return TRUE;
- }
-
- UBool commonlyUsed = FALSE;
- UErrorCode status = U_ZERO_ERROR;
- UResourceBundle *cuRes = ures_getByKey(zoneitem, gCommonlyUsedTag, NULL, &status);
- int32_t cuValue = ures_getInt(cuRes, &status);
- if (U_SUCCESS(status)) {
- if (cuValue == 1) {
- commonlyUsed = TRUE;
- }
- }
- ures_close(cuRes);
- return commonlyUsed;
-}
-
-UnicodeString&
-ZoneStringFormat::getLocalizedCountry(const UnicodeString &countryCode, const Locale &locale, UnicodeString &displayCountry) {
- // We do not want to use display country names only from the target language bundle
- // Note: we should do this in better way.
- displayCountry.remove();
- int32_t ccLen = countryCode.length();
- if (ccLen > 0 && ccLen < ULOC_COUNTRY_CAPACITY) {
- UErrorCode status = U_ZERO_ERROR;
- UResourceBundle *localeBundle = ures_open(NULL, locale.getName(), &status);
- if (U_SUCCESS(status)) {
- const char *bundleLocStr = ures_getLocale(localeBundle, &status);
- if (U_SUCCESS(status) && uprv_strlen(bundleLocStr) > 0) {
- Locale bundleLoc(bundleLocStr);
- if (uprv_strcmp(bundleLocStr, "root") != 0 &&
- uprv_strcmp(bundleLoc.getLanguage(), locale.getLanguage()) == 0) {
- // Create a fake locale strings
- char tmpLocStr[ULOC_COUNTRY_CAPACITY + 3];
- uprv_strcpy(tmpLocStr, "xx_");
- u_UCharsToChars(countryCode.getBuffer(), &tmpLocStr[3], ccLen);
- tmpLocStr[3 + ccLen] = 0;
-
- Locale tmpLoc(tmpLocStr);
- tmpLoc.getDisplayCountry(locale, displayCountry);
- }
- }
- }
- ures_close(localeBundle);
- }
- if (displayCountry.isEmpty()) {
- // Use the country code as the fallback
- displayCountry.setTo(countryCode);
- }
- return displayCountry;
-}
-
-// ----------------------------------------------------------------------------
-/*
- * ZoneStrings constructor adopts (and promptly copies and deletes)
- * the input UnicodeString arrays.
- */
-ZoneStrings::ZoneStrings(UnicodeString *strings,
- int32_t stringsCount,
- UBool commonlyUsed,
- UnicodeString **genericPartialLocationStrings,
- int32_t genericRowCount,
- int32_t genericColCount,
- ZSFStringPool &sp,
- UErrorCode &status)
-: fStrings(NULL),
- fStringsCount(stringsCount),
- fIsCommonlyUsed(commonlyUsed),
- fGenericPartialLocationStrings(NULL),
- fGenericPartialLocationRowCount(genericRowCount),
- fGenericPartialLocationColCount(genericColCount)
-{
- if (U_FAILURE(status)) {
- return;
- }
- int32_t i, j;
- if (strings != NULL) {
- fStrings = (const UChar **)uprv_malloc(sizeof(const UChar **) * stringsCount);
- if (fStrings == NULL) {
- status = U_MEMORY_ALLOCATION_ERROR;
- return;
- }
- for (i=0; i= 0 && typeIdx < fStringsCount) {
- result.setTo(fStrings[typeIdx], -1);
- } else {
- result.remove();
- }
- return result;
-}
-
-UnicodeString&
-ZoneStrings::getGenericPartialLocationString(const UnicodeString &mzid, UBool isShort,
- UBool commonlyUsedOnly, UnicodeString &result) const {
- UBool isSet = FALSE;
- if (fGenericPartialLocationColCount >= 2) {
- for (int32_t i = 0; i < fGenericPartialLocationRowCount; i++) {
- if (mzid.compare(fGenericPartialLocationStrings[i][0], -1) == 0) {
- if (isShort) {
- if (fGenericPartialLocationColCount >= 3) {
- if (!commonlyUsedOnly ||
- fGenericPartialLocationColCount == 3 ||
- fGenericPartialLocationStrings[i][3][0] != 0) {
- result.setTo(fGenericPartialLocationStrings[i][2], -1);
- isSet = TRUE;
- }
- }
- } else {
- result.setTo(fGenericPartialLocationStrings[i][1], -1);
- isSet = TRUE;
- }
- break;
- }
- }
- }
- if (!isSet) {
- result.remove();
- }
- return result;
-}
-
-// --------------------------------------------------------------
-SafeZoneStringFormatPtr::SafeZoneStringFormatPtr(ZSFCacheEntry *cacheEntry)
-: fCacheEntry(cacheEntry) {
-}
-
-SafeZoneStringFormatPtr::~SafeZoneStringFormatPtr() {
- fCacheEntry->delRef();
-}
-
-const ZoneStringFormat*
-SafeZoneStringFormatPtr::get() const {
- return fCacheEntry->getZoneStringFormat();
-}
-
-ZSFCacheEntry::ZSFCacheEntry(const Locale &locale, ZoneStringFormat *zsf, ZSFCacheEntry *next)
-: fLocale(locale), fZoneStringFormat(zsf),
- fNext(next), fRefCount(1)
-{
-}
-
-ZSFCacheEntry::~ZSFCacheEntry () {
- delete fZoneStringFormat;
-}
-
-const ZoneStringFormat*
-ZSFCacheEntry::getZoneStringFormat(void) {
- return (const ZoneStringFormat*)fZoneStringFormat;
-}
-
-void
-ZSFCacheEntry::delRef(void) {
- umtx_lock(&gZSFCacheLock);
- --fRefCount;
- umtx_unlock(&gZSFCacheLock);
-}
-
-ZSFCache::ZSFCache(int32_t capacity)
-: fCapacity(capacity), fFirst(NULL) {
-}
-
-ZSFCache::~ZSFCache() {
- ZSFCacheEntry *entry = fFirst;
- while (entry) {
- ZSFCacheEntry *next = entry->fNext;
- delete entry;
- entry = next;
- }
-}
-
-SafeZoneStringFormatPtr*
-ZSFCache::get(const Locale &locale, UErrorCode &status) {
- SafeZoneStringFormatPtr *result = NULL;
-
- // Search the cache entry list
- ZSFCacheEntry *entry = NULL;
- ZSFCacheEntry *next, *prev;
-
- umtx_lock(&gZSFCacheLock);
- entry = fFirst;
- prev = NULL;
- while (entry) {
- next = entry->fNext;
- if (entry->fLocale == locale) {
- // Add reference count
- entry->fRefCount++;
-
- // move the entry to the top
- if (entry != fFirst) {
- prev->fNext = next;
- entry->fNext = fFirst;
- fFirst = entry;
- }
- break;
- }
- prev = entry;
- entry = next;
- }
- umtx_unlock(&gZSFCacheLock);
-
- // Create a new ZoneStringFormat
- if (entry == NULL) {
- ZoneStringFormat *zsf = new ZoneStringFormat(locale, status);
- if (U_FAILURE(status)) {
- delete zsf;
- return NULL;
- }
- if (zsf == NULL) {
- status = U_MEMORY_ALLOCATION_ERROR;
- return NULL;
- }
-
- // Now add the new entry
- umtx_lock(&gZSFCacheLock);
- // Make sure no other threads already created the one for the same locale
- entry = fFirst;
- prev = NULL;
- while (entry) {
- next = entry->fNext;
- if (entry->fLocale == locale) {
- // Add reference count
- entry->fRefCount++;
-
- // move the entry to the top
- if (entry != fFirst) {
- prev->fNext = next;
- entry->fNext = fFirst;
- fFirst = entry;
- }
- break;
- }
- prev = entry;
- entry = next;
- }
- if (entry == NULL) {
- // Add the new one to the top
- next = fFirst;
- entry = new ZSFCacheEntry(locale, zsf, next);
- fFirst = entry;
- } else {
- delete zsf;
- }
- umtx_unlock(&gZSFCacheLock);
- }
-
- result = new SafeZoneStringFormatPtr(entry);
-
- // Now, delete unused cache entries beyond the capacity
- umtx_lock(&gZSFCacheLock);
- entry = fFirst;
- prev = NULL;
- int32_t idx = 1;
- while (entry) {
- next = entry->fNext;
- if (idx >= fCapacity && entry->fRefCount == 0) {
- if (entry == fFirst) {
- fFirst = next;
- } else {
- prev->fNext = next;
- }
- delete entry;
- } else {
- prev = entry;
- }
- entry = next;
- idx++;
- }
- umtx_unlock(&gZSFCacheLock);
-
- return result;
-}
-
-
-/*
- * Zone String Formatter String Pool Implementation
- *
- * String pool for (UChar *) strings. Avoids having repeated copies of the same string.
- */
-
-static const int32_t POOL_CHUNK_SIZE = 2000;
-struct ZSFStringPoolChunk: public UMemory {
- ZSFStringPoolChunk *fNext; // Ptr to next pool chunk
- int32_t fLimit; // Index to start of unused area at end of fStrings
- UChar fStrings[POOL_CHUNK_SIZE]; // Strings array
- ZSFStringPoolChunk();
-};
-
-ZSFStringPoolChunk::ZSFStringPoolChunk() {
- fNext = NULL;
- fLimit = 0;
-}
-
-ZSFStringPool::ZSFStringPool(UErrorCode &status) {
- fChunks = NULL;
- fHash = NULL;
- if (U_FAILURE(status)) {
- return;
- }
- fChunks = new ZSFStringPoolChunk;
- if (fChunks == NULL) {
- status = U_MEMORY_ALLOCATION_ERROR;
- return;
- }
-
- fHash = uhash_open(uhash_hashUChars /* keyHash */,
- uhash_compareUChars /* keyComp */,
- uhash_compareUChars /* valueComp */,
- &status);
- if (U_FAILURE(status)) {
- return;
- }
-}
-
-
-ZSFStringPool::~ZSFStringPool() {
- if (fHash != NULL) {
- uhash_close(fHash);
- fHash = NULL;
- }
-
- while (fChunks != NULL) {
- ZSFStringPoolChunk *nextChunk = fChunks->fNext;
- delete fChunks;
- fChunks = nextChunk;
- }
-}
-
-static const UChar EmptyString = 0;
-
-const UChar *ZSFStringPool::get(const UChar *s, UErrorCode &status) {
- const UChar *pooledString;
- if (U_FAILURE(status)) {
- return &EmptyString;
- }
-
- pooledString = static_cast(uhash_get(fHash, s));
- if (pooledString != NULL) {
- return pooledString;
- }
-
- int32_t length = u_strlen(s);
- int32_t remainingLength = POOL_CHUNK_SIZE - fChunks->fLimit;
- if (remainingLength <= length) {
- U_ASSERT(length < POOL_CHUNK_SIZE);
- if (length >= POOL_CHUNK_SIZE) {
- status = U_INTERNAL_PROGRAM_ERROR;
- return &EmptyString;
- }
- ZSFStringPoolChunk *oldChunk = fChunks;
- fChunks = new ZSFStringPoolChunk;
- if (fChunks == NULL) {
- status = U_MEMORY_ALLOCATION_ERROR;
- return &EmptyString;
- }
- fChunks->fNext = oldChunk;
- }
-
- UChar *destString = &fChunks->fStrings[fChunks->fLimit];
- u_strcpy(destString, s);
- fChunks->fLimit += (length + 1);
- uhash_put(fHash, destString, destString, &status);
- return destString;
-}
-
-
-//
-// ZSFStringPool::adopt() Put a string into the hash, but do not copy the string data
-// into the pool's storage. Used for strings from resource bundles,
-// which will perisist for the life of the zone string formatter, and
-// therefore can be used directly without copying.
-const UChar *ZSFStringPool::adopt(const UChar * s, UErrorCode &status) {
- const UChar *pooledString;
- if (U_FAILURE(status)) {
- return &EmptyString;
- }
- if (s != NULL) {
- pooledString = static_cast(uhash_get(fHash, s));
- if (pooledString == NULL) {
- UChar *ncs = const_cast(s);
- uhash_put(fHash, ncs, ncs, &status);
- }
- }
- return s;
-}
-
-
-const UChar *ZSFStringPool::get(const UnicodeString &s, UErrorCode &status) {
- UnicodeString &nonConstStr = const_cast(s);
- return this->get(nonConstStr.getTerminatedBuffer(), status);
-}
-
-/*
- * freeze(). Close the hash table that maps to the pooled strings.
- * After freezing, the pool can not be searched or added to,
- * but all existing references to pooled strings remain valid.
- *
- * The main purpose is to recover the storage used for the hash.
- */
-void ZSFStringPool::freeze() {
- uhash_close(fHash);
- fHash = NULL;
-}
-
-U_NAMESPACE_END
-
-#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/icu4c/source/i18n/zstrfmt.h b/icu4c/source/i18n/zstrfmt.h
deleted file mode 100644
index 53f744458ed..00000000000
--- a/icu4c/source/i18n/zstrfmt.h
+++ /dev/null
@@ -1,526 +0,0 @@
-/*
-*******************************************************************************
-* Copyright (C) 2007-2011, International Business Machines Corporation and *
-* others. All Rights Reserved. *
-*******************************************************************************
-*/
-#ifndef ZSTRFMT_H
-#define ZSTRFMT_H
-
-#include "unicode/utypes.h"
-
-#if !UCONFIG_NO_FORMATTING
-
-#include "unicode/unistr.h"
-#include "unicode/calendar.h"
-#include "uhash.h"
-#include "uvector.h"
-
-U_NAMESPACE_BEGIN
-
-/*
- * Character node used by TextTrieMap
- */
-struct CharacterNode {
- // No constructor or destructor.
- // We malloc and free an uninitalized array of CharacterNode objects
- // and clear and delete them ourselves.
-
- void clear();
- void deleteValues();
-
- void addValue(void *value, UErrorCode &status);
- inline UBool hasValues() const;
- inline int32_t countValues() const;
- inline const void *getValue(int32_t index) const;
-
- void *fValues; // Union of one single value vs. UVector of values.
- UChar fCharacter; // UTF-16 code unit.
- uint16_t fFirstChild; // 0 if no children.
- uint16_t fNextSibling; // 0 terminates the list.
- UBool fHasValuesVector;
- UBool fPadding;
-
- // No value: fValues == NULL and fHasValuesVector == FALSE
- // One value: fValues == value and fHasValuesVector == FALSE
- // >=2 values: fValues == UVector of values and fHasValuesVector == TRUE
-};
-
-inline UBool CharacterNode::hasValues() const {
- return (UBool)(fValues != NULL);
-}
-
-inline int32_t CharacterNode::countValues() const {
- return
- fValues == NULL ? 0 :
- !fHasValuesVector ? 1 :
- ((const UVector *)fValues)->size();
-}
-
-inline const void *CharacterNode::getValue(int32_t index) const {
- if (!fHasValuesVector) {
- return fValues; // Assume index == 0.
- } else {
- return ((const UVector *)fValues)->elementAt(index);
- }
-}
-
-/*
- * Search result handler callback interface used by TextTrieMap search.
- */
-class TextTrieMapSearchResultHandler : public UMemory {
-public:
- virtual UBool handleMatch(int32_t matchLength,
- const CharacterNode *node, UErrorCode& status) = 0;
- virtual ~TextTrieMapSearchResultHandler(); //added to avoid warning
-};
-
-
-/*
- * ZSFStringPool Pool of (UChar *) strings. Provides for sharing of repeated
- * strings within ZoneStringFormats.
- */
-struct ZSFStringPoolChunk;
-class ZSFStringPool: public UMemory {
- public:
- ZSFStringPool(UErrorCode &status);
- ~ZSFStringPool();
-
- /* Get the pooled string that is equal to the supplied string s.
- * Copy the string into the pool if it is not already present.
- *
- * Life time of the returned string is that of the pool.
- */
- const UChar *get(const UChar *s, UErrorCode &status);
-
- /* Get the pooled string that is equal to the supplied string s.
- * Copy the string into the pool if it is not already present.
- */
- const UChar *get(const UnicodeString &s, UErrorCode &status);
-
- /* Adopt a string into the pool, without copying it.
- * Used for strings from resource bundles, which will persist without copying.
- */
- const UChar *adopt(const UChar *s, UErrorCode &status);
-
- /* Freeze the string pool. Discards the hash table that is used
- * for looking up a string. All pointers to pooled strings remain valid.
- */
- void freeze();
-
- private:
- ZSFStringPoolChunk *fChunks;
- UHashtable *fHash;
-};
-
-
-/**
- * TextTrieMap is a trie implementation for supporting
- * fast prefix match for the string key.
- */
-class TextTrieMap : public UMemory {
-public:
- TextTrieMap(UBool ignoreCase);
- virtual ~TextTrieMap();
-
- void put(const UnicodeString &key, void *value, ZSFStringPool &sp, UErrorCode &status);
- void search(const UnicodeString &text, int32_t start,
- TextTrieMapSearchResultHandler *handler, UErrorCode& status) const;
- int32_t isEmpty() const;
-
-private:
- UBool fIgnoreCase;
- CharacterNode *fNodes;
- int32_t fNodesCapacity;
- int32_t fNodesCount;
-
- UVector *fLazyContents;
- UBool fIsEmpty;
-
- UBool growNodes();
- CharacterNode* addChildNode(CharacterNode *parent, UChar c, UErrorCode &status);
- CharacterNode* getChildNode(CharacterNode *parent, UChar c) const;
-
- void putImpl(const UnicodeString &key, void *value, UErrorCode &status);
- void buildTrie(UErrorCode &status);
- void search(CharacterNode *node, const UnicodeString &text, int32_t start,
- int32_t index, TextTrieMapSearchResultHandler *handler, UErrorCode &status) const;
-};
-
-
-// Name types, these bit flag are used for zone string lookup
-enum TimeZoneTranslationType {
- LOCATION = 0x0001,
- GENERIC_LONG = 0x0002,
- GENERIC_SHORT = 0x0004,
- STANDARD_LONG = 0x0008,
- STANDARD_SHORT = 0x0010,
- DAYLIGHT_LONG = 0x0020,
- DAYLIGHT_SHORT = 0x0040
-};
-
-// Name type index, these constants are used for index in the zone strings array.
-enum TimeZoneTranslationTypeIndex {
- ZSIDX_LOCATION = 0,
- ZSIDX_LONG_STANDARD,
- ZSIDX_SHORT_STANDARD,
- ZSIDX_LONG_DAYLIGHT,
- ZSIDX_SHORT_DAYLIGHT,
- ZSIDX_LONG_GENERIC,
- ZSIDX_SHORT_GENERIC,
-
- ZSIDX_COUNT
-};
-
-class MessageFormat;
-
-
-/*
- * ZoneStringInfo is a class holding a localized zone string
- * information.
- */
-class ZoneStringInfo : public UMemory {
-public:
- virtual ~ZoneStringInfo();
-
- inline UnicodeString& getID(UnicodeString &result) const;
- inline UnicodeString& getString(UnicodeString &result) const;
- inline UBool isStandard(void) const;
- inline UBool isDaylight(void) const;
- inline UBool isGeneric(void) const;
-
-private:
- friend class ZoneStringFormat;
- friend class ZoneStringSearchResultHandler;
-
- ZoneStringInfo(const UnicodeString &id, const UnicodeString &str,
- TimeZoneTranslationType type, ZSFStringPool &sp, UErrorCode &status);
-
- const UChar *fId;
- const UChar *fStr;
- TimeZoneTranslationType fType;
-};
-
-inline UnicodeString& ZoneStringInfo::getID(UnicodeString &result) const {
- return result.setTo(fId, -1);
-}
-
-inline UnicodeString& ZoneStringInfo::getString(UnicodeString &result) const {
- return result.setTo(fStr, -1);
-}
-
-inline UBool ZoneStringInfo::isStandard(void) const {
- return (fType == STANDARD_LONG || fType == STANDARD_SHORT);
-}
-
-inline UBool ZoneStringInfo::isDaylight(void) const {
- return (fType == DAYLIGHT_LONG || fType == DAYLIGHT_SHORT);
-}
-
-inline UBool ZoneStringInfo::isGeneric(void) const {
- return (fType == LOCATION || fType == GENERIC_LONG || fType == GENERIC_SHORT);
-}
-
-class SafeZoneStringFormatPtr;
-
-class ZoneStringFormat : public UMemory {
-public:
- ZoneStringFormat(const UnicodeString* const* strings, int32_t rowCount, int32_t columnCount, UErrorCode &status);
- ZoneStringFormat(const Locale& locale, UErrorCode &status);
- virtual ~ZoneStringFormat();
-
- /* Gets zone string format from cache if available, create it if not cached. */
- static SafeZoneStringFormatPtr* getZoneStringFormat(const Locale& locale, UErrorCode &status);
-
- /*
- * Create a snapshot of old zone strings array for the given date
- */
- UnicodeString** createZoneStringsArray(UDate date, int32_t &rowCount, int32_t &colCount, UErrorCode &status) const;
-
- /* TODO: There is no implementation for this function. Delete declaration? */
- const UnicodeString** getZoneStrings(int32_t &rowCount, int32_t &columnCount) const;
-
- UnicodeString& getSpecificLongString(const Calendar &cal,
- UnicodeString &result, UErrorCode &status) const;
-
- UnicodeString& getSpecificShortString(const Calendar &cal,
- UBool commonlyUsedOnly, UnicodeString &result, UErrorCode &status) const;
-
- UnicodeString& getGenericLongString(const Calendar &cal,
- UnicodeString &result, UErrorCode &status) const;
-
- UnicodeString& getGenericShortString(const Calendar &cal,
- UBool commonlyUsedOnly, UnicodeString &result, UErrorCode &status) const;
-
- UnicodeString& getGenericLocationString(const Calendar &cal,
- UnicodeString &result, UErrorCode &status) const;
-
- const ZoneStringInfo* findSpecificLong(const UnicodeString &text, int32_t start,
- int32_t &matchLength, UErrorCode &status) const;
- const ZoneStringInfo* findSpecificShort(const UnicodeString &text, int32_t start,
- int32_t &matchLength, UErrorCode &status) const;
- const ZoneStringInfo* findGenericLong(const UnicodeString &text, int32_t start,
- int32_t &matchLength, UErrorCode &status) const;
- const ZoneStringInfo* findGenericShort(const UnicodeString &text, int32_t start,
- int32_t &matchLength, UErrorCode &status) const;
- const ZoneStringInfo* findGenericLocation(const UnicodeString &text, int32_t start,
- int32_t &matchLength, UErrorCode &status) const;
-
- // Following APIs are not used by SimpleDateFormat, but public for testing purpose
- inline UnicodeString& getLongStandard(const UnicodeString &tzid, UDate date,
- UnicodeString &result) const;
- inline UnicodeString& getLongDaylight(const UnicodeString &tzid, UDate date,
- UnicodeString &result) const;
- inline UnicodeString& getLongGenericNonLocation(const UnicodeString &tzid, UDate date,
- UnicodeString &result) const;
- inline UnicodeString& getLongGenericPartialLocation(const UnicodeString &tzid, UDate date,
- UnicodeString &result) const;
- inline UnicodeString& getShortStandard(const UnicodeString &tzid, UDate date, UBool commonlyUsedOnly,
- UnicodeString &result) const;
- inline UnicodeString& getShortDaylight(const UnicodeString &tzid, UDate date, UBool commonlyUsedOnly,
- UnicodeString &result) const;
- inline UnicodeString& getShortGenericNonLocation(const UnicodeString &tzid, UDate date, UBool commonlyUsedOnly,
- UnicodeString &result) const;
- inline UnicodeString& getShortGenericPartialLocation(const UnicodeString &tzid, UDate date, UBool commonlyUsedOnly,
- UnicodeString &result) const;
- inline UnicodeString& getGenericLocation(const UnicodeString &tzid, UnicodeString &result) const;
-
-private:
- Locale fLocale;
- UHashtable *fTzidToStrings;
- UHashtable *fMzidToStrings;
-
- TextTrieMap fZoneStringsTrie;
- ZSFStringPool fStringPool;
-
- UResourceBundle *fZoneStringsArray;
- UResourceBundle *fMetazoneItem;
- UResourceBundle *fZoneItem;
-
- UBool fIsFullyLoaded;
-
- void loadZone(const UnicodeString &utzid, UErrorCode &status);
- void addSingleZone(UnicodeString &utzid, UErrorCode &status);
- void loadFull(UErrorCode &status);
-
-
- /*
- * Private method to get a zone string except generic partial location types.
- */
- UnicodeString& getString(const UnicodeString &tzid, TimeZoneTranslationTypeIndex typeIdx, UDate date,
- UBool commonlyUsedOnly, UnicodeString& result) const;
-
- /*
- * Private method to get a generic string, with fallback logic involved,
- * that is,
- *
- * 1. If a generic non-location string is avaiable for the zone, return it.
- * 2. If a generic non-location string is associated with a metazone and
- * the zone never use daylight time around the given date, use the standard
- * string (if available).
- *
- * Note: In CLDR1.5.1, the same localization is used for generic and standard.
- * In this case, we do not use the standard string and do the rest.
- *
- * 3. If a generic non-location string is associated with a metazone and
- * the offset at the given time is different from the preferred zone for the
- * current locale, then return the generic partial location string (if avaiable)
- * 4. If a generic non-location string is not available, use generic location
- * string.
- */
- UnicodeString& getGenericString(const Calendar &cal, UBool isShort, UBool commonlyUsedOnly,
- UnicodeString &result, UErrorCode &status) const;
-
- /*
- * Private method to get a generic partial location string
- */
- UnicodeString& getGenericPartialLocationString(const UnicodeString &tzid, UBool isShort,
- UDate date, UBool commonlyUsedOnly, UnicodeString &result) const;
-
- /*
- * Find a prefix matching time zone for the given zone string types.
- * @param text The text contains a time zone string
- * @param start The start index within the text
- * @param types The bit mask representing a set of requested types
- * @param matchLength Receives the match length
- * @param status
- * @return If any zone string matched for the requested types, returns a
- * ZoneStringInfo for the longest match. If no matches are found for
- * the requested types, returns a ZoneStringInfo for the longest match
- * for any other types. If nothing matches at all, returns null.
- */
- const ZoneStringInfo* find(const UnicodeString &text, int32_t start, int32_t types,
- int32_t &matchLength, UErrorCode &status) const;
- const ZoneStringInfo* subFind(const UnicodeString &text, int32_t start, int32_t types,
- int32_t &matchLength, UErrorCode &status) const;
-
- UnicodeString& getRegion(UnicodeString ®ion) const;
-
- static MessageFormat* getFallbackFormat(const Locale &locale, UErrorCode &status);
- static MessageFormat* getRegionFormat(const Locale &locale, UErrorCode &status);
- const UChar* getZoneStringFromBundle(const UResourceBundle *zoneitem, const char *key);
- static UBool isCommonlyUsed(const UResourceBundle *zoneitem);
- static UnicodeString& getLocalizedCountry(const UnicodeString &countryCode, const Locale &locale,
- UnicodeString &displayCountry);
-};
-
-inline UnicodeString&
-ZoneStringFormat::getLongStandard(const UnicodeString &tzid, UDate date,
- UnicodeString &result) const {
- return getString(tzid, ZSIDX_LONG_STANDARD, date, FALSE /* not used */, result);
-}
-
-inline UnicodeString&
-ZoneStringFormat::getLongDaylight(const UnicodeString &tzid, UDate date,
- UnicodeString &result) const {
- return getString(tzid, ZSIDX_LONG_DAYLIGHT, date, FALSE /* not used */, result);
-}
-
-inline UnicodeString&
-ZoneStringFormat::getLongGenericNonLocation(const UnicodeString &tzid, UDate date,
- UnicodeString &result) const {
- return getString(tzid, ZSIDX_LONG_GENERIC, date, FALSE /* not used */, result);
-}
-
-inline UnicodeString&
-ZoneStringFormat::getLongGenericPartialLocation(const UnicodeString &tzid, UDate date,
- UnicodeString &result) const {
- return getGenericPartialLocationString(tzid, FALSE, date, FALSE /* not used */, result);
-}
-
-inline UnicodeString&
-ZoneStringFormat::getShortStandard(const UnicodeString &tzid, UDate date, UBool commonlyUsedOnly,
- UnicodeString &result) const {
- return getString(tzid, ZSIDX_SHORT_STANDARD, date, commonlyUsedOnly, result);
-}
-
-inline UnicodeString&
-ZoneStringFormat::getShortDaylight(const UnicodeString &tzid, UDate date, UBool commonlyUsedOnly,
- UnicodeString &result) const {
- return getString(tzid, ZSIDX_SHORT_DAYLIGHT, date, commonlyUsedOnly, result);
-}
-
-inline UnicodeString&
-ZoneStringFormat::getShortGenericNonLocation(const UnicodeString &tzid, UDate date, UBool commonlyUsedOnly,
- UnicodeString &result) const {
- return getString(tzid, ZSIDX_SHORT_GENERIC, date, commonlyUsedOnly, result);
-}
-
-inline UnicodeString&
-ZoneStringFormat::getShortGenericPartialLocation(const UnicodeString &tzid, UDate date, UBool commonlyUsedOnly,
- UnicodeString &result) const {
- return getGenericPartialLocationString(tzid, TRUE, date, commonlyUsedOnly, result);
-}
-
-inline UnicodeString&
-ZoneStringFormat::getGenericLocation(const UnicodeString &tzid, UnicodeString &result) const {
- return getString(tzid, ZSIDX_LOCATION, 0 /*not used*/, FALSE /*not used*/, result);
-}
-
-
-/*
- * ZoneStrings is a container of localized zone strings used by ZoneStringFormat
- */
-class ZoneStrings : public UMemory {
-public:
- ZoneStrings(UnicodeString *strings,
- int32_t stringsCount,
- UBool commonlyUsed,
- UnicodeString **genericPartialLocationStrings,
- int32_t genericRowCount,
- int32_t genericColCount,
- ZSFStringPool &sp,
- UErrorCode &status);
- virtual ~ZoneStrings();
-
- UnicodeString& getString(int32_t typeIdx, UnicodeString &result) const;
- inline UBool isShortFormatCommonlyUsed(void) const;
- UnicodeString& getGenericPartialLocationString(const UnicodeString &mzid, UBool isShort,
- UBool commonlyUsedOnly, UnicodeString &result) const;
-
-private:
- const UChar **fStrings;
- int32_t fStringsCount;
- UBool fIsCommonlyUsed;
- const UChar * **fGenericPartialLocationStrings;
- int32_t fGenericPartialLocationRowCount;
- int32_t fGenericPartialLocationColCount;
-};
-
-inline UBool
-ZoneStrings::isShortFormatCommonlyUsed(void) const {
- return fIsCommonlyUsed;
-}
-
-/*
- * ZoneStringSearchResultHandler is an implementation of
- * TextTrieMapSearchHandler. This class is used by ZoneStringFormat
- * for collecting search results for localized zone strings.
- */
-class ZoneStringSearchResultHandler : public TextTrieMapSearchResultHandler {
-public:
- ZoneStringSearchResultHandler(UErrorCode &status);
- virtual ~ZoneStringSearchResultHandler();
-
- virtual UBool handleMatch(int32_t matchLength, const CharacterNode *node, UErrorCode &status);
- int32_t countMatches(void);
- const ZoneStringInfo* getMatch(int32_t index, int32_t &matchLength);
- void clear(void);
-
-private:
- UVector fResults;
- int32_t fMatchLen[ZSIDX_COUNT];
-};
-
-
-/*
- * ZoneStringFormat cache implementation
- */
-class ZSFCacheEntry : public UMemory {
-public:
- ~ZSFCacheEntry();
-
- void delRef(void);
- const ZoneStringFormat* getZoneStringFormat(void);
-
-private:
- friend class ZSFCache;
-
- ZSFCacheEntry(const Locale &locale, ZoneStringFormat *zsf, ZSFCacheEntry *next);
-
- Locale fLocale;
- ZoneStringFormat *fZoneStringFormat;
- ZSFCacheEntry *fNext;
- int32_t fRefCount;
-};
-
-class SafeZoneStringFormatPtr : public UMemory {
-public:
- ~SafeZoneStringFormatPtr();
- const ZoneStringFormat* get() const;
-
-private:
- friend class ZSFCache;
-
- SafeZoneStringFormatPtr(ZSFCacheEntry *cacheEntry);
-
- ZSFCacheEntry *fCacheEntry;
-};
-
-class ZSFCache : public UMemory {
-public:
- ZSFCache(int32_t capacity);
- ~ZSFCache();
-
- SafeZoneStringFormatPtr* get(const Locale &locale, UErrorCode &status);
-
-private:
- int32_t fCapacity;
- ZSFCacheEntry *fFirst;
-};
-
-U_NAMESPACE_END
-
-#endif /* #if !UCONFIG_NO_FORMATTING */
-
-#endif // ZSTRFMT_H
diff --git a/icu4c/source/test/intltest/callimts.cpp b/icu4c/source/test/intltest/callimts.cpp
index ed583ef07db..42869cdac19 100644
--- a/icu4c/source/test/intltest/callimts.cpp
+++ b/icu4c/source/test/intltest/callimts.cpp
@@ -1,6 +1,6 @@
/***********************************************************************
* COPYRIGHT:
- * Copyright (c) 1997-2010, International Business Machines Corporation
+ * Copyright (c) 1997-2011, International Business Machines Corporation
* and others. All Rights Reserved.
***********************************************************************/
@@ -105,7 +105,7 @@ CalendarLimitTest::TestCalendarExtremeLimit()
return;
}
fmt->adoptCalendar(cal);
- ((SimpleDateFormat*) fmt)->applyPattern("HH:mm:ss.SSS zzz, EEEE, MMMM d, yyyy G");
+ ((SimpleDateFormat*) fmt)->applyPattern("HH:mm:ss.SSS Z, EEEE, MMMM d, yyyy G");
// This test used to test the algorithmic limits of the dates that
diff --git a/icu4c/source/test/intltest/dtfmttst.cpp b/icu4c/source/test/intltest/dtfmttst.cpp
index e3398ff59eb..1aa8ef706ae 100644
--- a/icu4c/source/test/intltest/dtfmttst.cpp
+++ b/icu4c/source/test/intltest/dtfmttst.cpp
@@ -166,7 +166,7 @@ void DateFormatTest::TestWallyWedel()
sdf->format(today,fmtOffset, pos);
// UnicodeString fmtOffset = tzS.toString();
UnicodeString *fmtDstOffset = 0;
- if (fmtOffset.startsWith("GMT"))
+ if (fmtOffset.startsWith("GMT") && fmtOffset.length() != 3)
{
//fmtDstOffset = fmtOffset->substring(3);
fmtDstOffset = new UnicodeString();
@@ -397,7 +397,7 @@ void DateFormatTest::TestFieldPosition() {
"Anno Domini", "1997", "August", "0013", "0014", "0014", "0034", "0012", "5130",
"Wednesday", "0225", "0002", "0033", "0002", "PM", "0002", "0002", "Pacific Daylight Time", "1997", "Wednesday", "1997", "2450674", "52452513", "GMT-07:00",
- "Pacific Time", "Wednesday", "August", "3rd quarter", "3rd quarter", "United States (Los Angeles)"
+ "Pacific Time", "Wednesday", "August", "3rd quarter", "3rd quarter", "United States Time (Los Angeles)"
};
const int32_t EXPECTED_LENGTH = sizeof(EXPECTED)/sizeof(EXPECTED[0]);
@@ -1066,11 +1066,11 @@ DateFormatTest::TestDateFormatZone146()
UDate greenwichdate = greenwichcalendar->getTime(status);
// format every way
UnicodeString DATA [] = {
- UnicodeString("simple format: "), UnicodeString("04/04/97 23:00 GMT+00:00"),
+ UnicodeString("simple format: "), UnicodeString("04/04/97 23:00 GMT"),
UnicodeString("MM/dd/yy HH:mm z"),
- UnicodeString("full format: "), UnicodeString("Friday, April 4, 1997 11:00:00 o'clock PM GMT+00:00"),
+ UnicodeString("full format: "), UnicodeString("Friday, April 4, 1997 11:00:00 o'clock PM GMT"),
UnicodeString("EEEE, MMMM d, yyyy h:mm:ss 'o''clock' a z"),
- UnicodeString("long format: "), UnicodeString("April 4, 1997 11:00:00 PM GMT+00:00"),
+ UnicodeString("long format: "), UnicodeString("April 4, 1997 11:00:00 PM GMT"),
UnicodeString("MMMM d, yyyy h:mm:ss a z"),
UnicodeString("default format: "), UnicodeString("04-Apr-97 11:00:00 PM"),
UnicodeString("dd-MMM-yy h:mm:ss a"),
@@ -1821,8 +1821,9 @@ void DateFormatTest::expectFormat(const char** data, int32_t data_length,
}
void DateFormatTest::TestGenericTime() {
- // any zone pattern should parse any zone
const Locale en("en");
+ // Note: We no longer parse strings in different styles.
+/*
const char* ZDATA[] = {
"yyyy MM dd HH:mm zzz",
// round trip
@@ -1862,12 +1863,44 @@ void DateFormatTest::TestGenericTime() {
"y/M/d H:mm v", "pf", "2004/10/31 1:30 PDT", "2004 10 31 01:30 PDT", "2004/10/31 1:30 PT",
"y/M/d H:mm", "pf", "2004/10/31 1:30", "2004 10 31 01:30 PST", "2004/10/31 1:30",
};
+*/
+ const char* ZDATA[] = {
+ "yyyy MM dd HH:mm zzz",
+ // round trip
+ "y/M/d H:mm zzzz", "F", "2004 01 01 01:00 PST", "2004/1/1 1:00 Pacific Standard Time",
+ "y/M/d H:mm zzz", "F", "2004 01 01 01:00 PST", "2004/1/1 1:00 PST",
+ "y/M/d H:mm vvvv", "F", "2004 01 01 01:00 PST", "2004/1/1 1:00 Pacific Time",
+ "y/M/d H:mm v", "F", "2004 01 01 01:00 PST", "2004/1/1 1:00 PT",
+ // non-generic timezone string influences dst offset even if wrong for date/time
+ "y/M/d H:mm zzz", "pf", "2004/1/1 1:00 PDT", "2004 01 01 01:00 PDT", "2004/1/1 0:00 PST",
+ "y/M/d H:mm zzz", "pf", "2004/7/1 1:00 PST", "2004 07 01 02:00 PDT", "2004/7/1 2:00 PDT",
+ // generic timezone generates dst offset appropriate for local time
+ "y/M/d H:mm zzz", "pf", "2004/1/1 1:00 PST", "2004 01 01 01:00 PST", "2004/1/1 1:00 PST",
+ "y/M/d H:mm vvvv", "pf", "2004/1/1 1:00 Pacific Time", "2004 01 01 01:00 PST", "2004/1/1 1:00 Pacific Time",
+ "y/M/d H:mm zzz", "pf", "2004/7/1 1:00 PDT", "2004 07 01 01:00 PDT", "2004/7/1 1:00 PDT",
+ "y/M/d H:mm vvvv", "pf", "2004/7/1 1:00 Pacific Time", "2004 07 01 01:00 PDT", "2004/7/1 1:00 Pacific Time",
+ // daylight savings time transition edge cases.
+ // time to parse does not really exist, PT interpreted as earlier time
+ "y/M/d H:mm zzz", "pf", "2005/4/3 2:30 PST", "2005 04 03 03:30 PDT", "2005/4/3 3:30 PDT",
+ "y/M/d H:mm zzz", "pf", "2005/4/3 2:30 PDT", "2005 04 03 01:30 PST", "2005/4/3 1:30 PST",
+ "y/M/d H:mm v", "pf", "2005/4/3 2:30 PT", "2005 04 03 03:30 PDT", "2005/4/3 3:30 PT",
+ "y/M/d H:mm", "pf", "2005/4/3 2:30", "2005 04 03 03:30 PDT", "2005/4/3 3:30",
+ // time to parse is ambiguous, PT interpreted as later time
+ "y/M/d H:mm v", "pf", "2005/10/30 1:30 PT", "2005 10 30 01:30 PST", "2005/10/30 1:30 PT",
+ "y/M/d H:mm", "pf", "2005/10/30 1:30 PT", "2005 10 30 01:30 PST", "2005/10/30 1:30",
+
+ "y/M/d H:mm zzz", "pf", "2004/10/31 1:30 PST", "2004 10 31 01:30 PST", "2004/10/31 1:30 PST",
+ "y/M/d H:mm zzz", "pf", "2004/10/31 1:30 PDT", "2004 10 31 01:30 PDT", "2004/10/31 1:30 PDT",
+ "y/M/d H:mm v", "pf", "2004/10/31 1:30 PT", "2004 10 31 01:30 PST", "2004/10/31 1:30 PT",
+ "y/M/d H:mm", "pf", "2004/10/31 1:30", "2004 10 31 01:30 PST", "2004/10/31 1:30",
+ };
+
const int32_t ZDATA_length = sizeof(ZDATA)/ sizeof(ZDATA[0]);
expect(ZDATA, ZDATA_length, en);
UErrorCode status = U_ZERO_ERROR;
- logln("cross format/parse tests");
+ logln("cross format/parse tests"); // Note: We no longer support cross format/parse
UnicodeString basepat("yy/MM/dd H:mm ");
SimpleDateFormat formats[] = {
SimpleDateFormat(basepat + "vvv", en, status),
@@ -1919,29 +1952,52 @@ void DateFormatTest::TestGenericTime() {
void DateFormatTest::TestGenericTimeZoneOrder() {
// generic times should parse the same no matter what the placement of the time zone string
- // should work for standard and daylight times
+ // Note: We no longer support cross style format/parse
+
+ //const char* XDATA[] = {
+ // "yyyy MM dd HH:mm zzz",
+ // // standard time, explicit daylight/standard
+ // "y/M/d H:mm zzz", "pf", "2004/1/1 1:00 PT", "2004 01 01 01:00 PST", "2004/1/1 1:00 PST",
+ // "y/M/d zzz H:mm", "pf", "2004/1/1 PT 1:00", "2004 01 01 01:00 PST", "2004/1/1 PST 1:00",
+ // "zzz y/M/d H:mm", "pf", "PT 2004/1/1 1:00", "2004 01 01 01:00 PST", "PST 2004/1/1 1:00",
+
+ // // standard time, generic
+ // "y/M/d H:mm vvvv", "pf", "2004/1/1 1:00 PT", "2004 01 01 01:00 PST", "2004/1/1 1:00 Pacific Time",
+ // "y/M/d vvvv H:mm", "pf", "2004/1/1 PT 1:00", "2004 01 01 01:00 PST", "2004/1/1 Pacific Time 1:00",
+ // "vvvv y/M/d H:mm", "pf", "PT 2004/1/1 1:00", "2004 01 01 01:00 PST", "Pacific Time 2004/1/1 1:00",
+
+ // // dahylight time, explicit daylight/standard
+ // "y/M/d H:mm zzz", "pf", "2004/7/1 1:00 PT", "2004 07 01 01:00 PDT", "2004/7/1 1:00 PDT",
+ // "y/M/d zzz H:mm", "pf", "2004/7/1 PT 1:00", "2004 07 01 01:00 PDT", "2004/7/1 PDT 1:00",
+ // "zzz y/M/d H:mm", "pf", "PT 2004/7/1 1:00", "2004 07 01 01:00 PDT", "PDT 2004/7/1 1:00",
+
+ // // daylight time, generic
+ // "y/M/d H:mm vvvv", "pf", "2004/7/1 1:00 PT", "2004 07 01 01:00 PDT", "2004/7/1 1:00 Pacific Time",
+ // "y/M/d vvvv H:mm", "pf", "2004/7/1 PT 1:00", "2004 07 01 01:00 PDT", "2004/7/1 Pacific Time 1:00",
+ // "vvvv y/M/d H:mm", "pf", "PT 2004/7/1 1:00", "2004 07 01 01:00 PDT", "Pacific Time 2004/7/1 1:00",
+ //};
const char* XDATA[] = {
"yyyy MM dd HH:mm zzz",
// standard time, explicit daylight/standard
- "y/M/d H:mm zzz", "pf", "2004/1/1 1:00 PT", "2004 01 01 01:00 PST", "2004/1/1 1:00 PST",
- "y/M/d zzz H:mm", "pf", "2004/1/1 PT 1:00", "2004 01 01 01:00 PST", "2004/1/1 PST 1:00",
- "zzz y/M/d H:mm", "pf", "PT 2004/1/1 1:00", "2004 01 01 01:00 PST", "PST 2004/1/1 1:00",
+ "y/M/d H:mm zzz", "pf", "2004/1/1 1:00 PST", "2004 01 01 01:00 PST", "2004/1/1 1:00 PST",
+ "y/M/d zzz H:mm", "pf", "2004/1/1 PST 1:00", "2004 01 01 01:00 PST", "2004/1/1 PST 1:00",
+ "zzz y/M/d H:mm", "pf", "PST 2004/1/1 1:00", "2004 01 01 01:00 PST", "PST 2004/1/1 1:00",
// standard time, generic
- "y/M/d H:mm vvvv", "pf", "2004/1/1 1:00 PT", "2004 01 01 01:00 PST", "2004/1/1 1:00 Pacific Time",
- "y/M/d vvvv H:mm", "pf", "2004/1/1 PT 1:00", "2004 01 01 01:00 PST", "2004/1/1 Pacific Time 1:00",
- "vvvv y/M/d H:mm", "pf", "PT 2004/1/1 1:00", "2004 01 01 01:00 PST", "Pacific Time 2004/1/1 1:00",
+ "y/M/d H:mm vvvv", "pf", "2004/1/1 1:00 Pacific Time", "2004 01 01 01:00 PST", "2004/1/1 1:00 Pacific Time",
+ "y/M/d vvvv H:mm", "pf", "2004/1/1 Pacific Time 1:00", "2004 01 01 01:00 PST", "2004/1/1 Pacific Time 1:00",
+ "vvvv y/M/d H:mm", "pf", "Pacific Time 2004/1/1 1:00", "2004 01 01 01:00 PST", "Pacific Time 2004/1/1 1:00",
// dahylight time, explicit daylight/standard
- "y/M/d H:mm zzz", "pf", "2004/7/1 1:00 PT", "2004 07 01 01:00 PDT", "2004/7/1 1:00 PDT",
- "y/M/d zzz H:mm", "pf", "2004/7/1 PT 1:00", "2004 07 01 01:00 PDT", "2004/7/1 PDT 1:00",
- "zzz y/M/d H:mm", "pf", "PT 2004/7/1 1:00", "2004 07 01 01:00 PDT", "PDT 2004/7/1 1:00",
+ "y/M/d H:mm zzz", "pf", "2004/7/1 1:00 PDT", "2004 07 01 01:00 PDT", "2004/7/1 1:00 PDT",
+ "y/M/d zzz H:mm", "pf", "2004/7/1 PDT 1:00", "2004 07 01 01:00 PDT", "2004/7/1 PDT 1:00",
+ "zzz y/M/d H:mm", "pf", "PDT 2004/7/1 1:00", "2004 07 01 01:00 PDT", "PDT 2004/7/1 1:00",
// daylight time, generic
- "y/M/d H:mm vvvv", "pf", "2004/7/1 1:00 PT", "2004 07 01 01:00 PDT", "2004/7/1 1:00 Pacific Time",
- "y/M/d vvvv H:mm", "pf", "2004/7/1 PT 1:00", "2004 07 01 01:00 PDT", "2004/7/1 Pacific Time 1:00",
- "vvvv y/M/d H:mm", "pf", "PT 2004/7/1 1:00", "2004 07 01 01:00 PDT", "Pacific Time 2004/7/1 1:00",
+ "y/M/d H:mm v", "pf", "2004/7/1 1:00 PT", "2004 07 01 01:00 PDT", "2004/7/1 1:00 PT",
+ "y/M/d v H:mm", "pf", "2004/7/1 PT 1:00", "2004 07 01 01:00 PDT", "2004/7/1 PT 1:00",
+ "v y/M/d H:mm", "pf", "PT 2004/7/1 1:00", "2004 07 01 01:00 PDT", "PT 2004/7/1 1:00",
};
const int32_t XDATA_length = sizeof(XDATA)/sizeof(XDATA[0]);
Locale en("en");
@@ -2187,7 +2243,7 @@ void DateFormatTest::TestTimeZoneDisplayName()
{ "en", "America/Los_Angeles", "2004-07-15T00:00:00Z", "zzzz", "Pacific Daylight Time", "America/Los_Angeles" },
{ "en", "America/Los_Angeles", "2004-07-15T00:00:00Z", "v", "PT", "America/Los_Angeles" },
{ "en", "America/Los_Angeles", "2004-07-15T00:00:00Z", "vvvv", "Pacific Time", "America/Los_Angeles" },
- { "en", "America/Los_Angeles", "2004-07-15T00:00:00Z", "VVVV", "United States (Los Angeles)", "America/Los_Angeles" },
+ { "en", "America/Los_Angeles", "2004-07-15T00:00:00Z", "VVVV", "United States Time (Los Angeles)", "America/Los_Angeles" },
{ "en_GB", "America/Los_Angeles", "2004-01-15T12:00:00Z", "z", "PST", "America/Los_Angeles" },
{ "en", "America/Phoenix", "2004-01-15T00:00:00Z", "Z", "-0700", "-7:00" },
{ "en", "America/Phoenix", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-07:00", "-7:00" },
@@ -2201,7 +2257,7 @@ void DateFormatTest::TestTimeZoneDisplayName()
{ "en", "America/Phoenix", "2004-07-15T00:00:00Z", "zzzz", "Mountain Standard Time", "America/Phoenix" },
{ "en", "America/Phoenix", "2004-07-15T00:00:00Z", "v", "MST", "America/Phoenix" },
{ "en", "America/Phoenix", "2004-07-15T00:00:00Z", "vvvv", "Mountain Standard Time", "America/Phoenix" },
- { "en", "America/Phoenix", "2004-07-15T00:00:00Z", "VVVV", "United States (Phoenix)", "America/Phoenix" },
+ { "en", "America/Phoenix", "2004-07-15T00:00:00Z", "VVVV", "United States Time (Phoenix)", "America/Phoenix" },
{ "en", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
{ "en", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
@@ -2213,9 +2269,9 @@ void DateFormatTest::TestTimeZoneDisplayName()
{ "en", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "z", "GMT-03:00", "-3:00" },
{ "en", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "V", "ART", "-3:00" },
{ "en", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "zzzz", "Argentina Time", "-3:00" },
- { "en", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "v", "Argentina (Buenos Aires)", "America/Buenos_Aires" },
+ { "en", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "v", "Argentina Time (Buenos Aires)", "America/Buenos_Aires" },
{ "en", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "vvvv", "Argentina Time", "America/Buenos_Aires" },
- { "en", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "VVVV", "Argentina (Buenos Aires)", "America/Buenos_Aires" },
+ { "en", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "VVVV", "Argentina Time (Buenos Aires)", "America/Buenos_Aires" },
{ "en", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
{ "en", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
@@ -2227,9 +2283,9 @@ void DateFormatTest::TestTimeZoneDisplayName()
{ "en", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "z", "GMT-03:00", "-3:00" },
{ "en", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "V", "ART", "-3:00" },
{ "en", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "zzzz", "Argentina Time", "-3:00" },
- { "en", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "v", "Argentina (Buenos Aires)", "America/Buenos_Aires" },
+ { "en", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "v", "Argentina Time (Buenos Aires)", "America/Buenos_Aires" },
{ "en", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "vvvv", "Argentina Time", "America/Buenos_Aires" },
- { "en", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "VVVV", "Argentina (Buenos Aires)", "America/Buenos_Aires" },
+ { "en", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "VVVV", "Argentina Time (Buenos Aires)", "America/Buenos_Aires" },
{ "en", "America/Havana", "2004-01-15T00:00:00Z", "Z", "-0500", "-5:00" },
{ "en", "America/Havana", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-05:00", "-5:00" },
@@ -2255,9 +2311,9 @@ void DateFormatTest::TestTimeZoneDisplayName()
{ "en", "Australia/ACT", "2004-07-15T00:00:00Z", "z", "GMT+10:00", "+10:00" },
{ "en", "Australia/ACT", "2004-07-15T00:00:00Z", "V", "AEST", "+10:00" },
{ "en", "Australia/ACT", "2004-07-15T00:00:00Z", "zzzz", "Australian Eastern Standard Time", "+10:00" },
- { "en", "Australia/ACT", "2004-07-15T00:00:00Z", "v", "Australia (Sydney)", "Australia/Sydney" },
+ { "en", "Australia/ACT", "2004-07-15T00:00:00Z", "v", "Australia Time (Sydney)", "Australia/Sydney" },
{ "en", "Australia/ACT", "2004-07-15T00:00:00Z", "vvvv", "Eastern Australia Time", "Australia/Sydney" },
- { "en", "Australia/ACT", "2004-07-15T00:00:00Z", "VVVV", "Australia (Sydney)", "Australia/Sydney" },
+ { "en", "Australia/ACT", "2004-07-15T00:00:00Z", "VVVV", "Australia Time (Sydney)", "Australia/Sydney" },
{ "en", "Australia/Sydney", "2004-01-15T00:00:00Z", "Z", "+1100", "+11:00" },
{ "en", "Australia/Sydney", "2004-01-15T00:00:00Z", "ZZZZ", "GMT+11:00", "+11:00" },
@@ -2269,12 +2325,12 @@ void DateFormatTest::TestTimeZoneDisplayName()
{ "en", "Australia/Sydney", "2004-07-15T00:00:00Z", "z", "GMT+10:00", "+10:00" },
{ "en", "Australia/Sydney", "2004-07-15T00:00:00Z", "V", "AEST", "+10:00" },
{ "en", "Australia/Sydney", "2004-07-15T00:00:00Z", "zzzz", "Australian Eastern Standard Time", "+10:00" },
- { "en", "Australia/Sydney", "2004-07-15T00:00:00Z", "v", "Australia (Sydney)", "Australia/Sydney" },
+ { "en", "Australia/Sydney", "2004-07-15T00:00:00Z", "v", "Australia Time (Sydney)", "Australia/Sydney" },
{ "en", "Australia/Sydney", "2004-07-15T00:00:00Z", "vvvv", "Eastern Australia Time", "Australia/Sydney" },
- { "en", "Australia/Sydney", "2004-07-15T00:00:00Z", "VVVV", "Australia (Sydney)", "Australia/Sydney" },
+ { "en", "Australia/Sydney", "2004-07-15T00:00:00Z", "VVVV", "Australia Time (Sydney)", "Australia/Sydney" },
{ "en", "Europe/London", "2004-01-15T00:00:00Z", "Z", "+0000", "+0:00" },
- { "en", "Europe/London", "2004-01-15T00:00:00Z", "ZZZZ", "GMT+00:00", "+0:00" },
+ { "en", "Europe/London", "2004-01-15T00:00:00Z", "ZZZZ", "GMT", "+0:00" },
{ "en", "Europe/London", "2004-01-15T00:00:00Z", "z", "GMT", "+0:00" },
{ "en", "Europe/London", "2004-01-15T00:00:00Z", "V", "GMT", "+0:00" },
{ "en", "Europe/London", "2004-01-15T00:00:00Z", "zzzz", "Greenwich Mean Time", "+0:00" },
@@ -2385,9 +2441,9 @@ void DateFormatTest::TestTimeZoneDisplayName()
{ "de", "Australia/Sydney", "2004-07-15T00:00:00Z", "vvvv", "Australien (Sydney)", "Australia/Sydney" },
{ "de", "Europe/London", "2004-01-15T00:00:00Z", "Z", "+0000", "+0:00" },
- { "de", "Europe/London", "2004-01-15T00:00:00Z", "ZZZZ", "GMT+00:00", "+0:00" },
- { "de", "Europe/London", "2004-01-15T00:00:00Z", "z", "GMT+00:00", "+0:00" },
- { "de", "Europe/London", "2004-01-15T00:00:00Z", "zzzz", "GMT+00:00", "+0:00" },
+ { "de", "Europe/London", "2004-01-15T00:00:00Z", "ZZZZ", "GMT", "+0:00" },
+ { "de", "Europe/London", "2004-01-15T00:00:00Z", "z", "GMT", "+0:00" },
+ { "de", "Europe/London", "2004-01-15T00:00:00Z", "zzzz", "GMT", "+0:00" },
{ "de", "Europe/London", "2004-07-15T00:00:00Z", "Z", "+0100", "+1:00" },
{ "de", "Europe/London", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+01:00", "+1:00" },
{ "de", "Europe/London", "2004-07-15T00:00:00Z", "z", "GMT+01:00", "+1:00" },
@@ -2489,8 +2545,8 @@ void DateFormatTest::TestTimeZoneDisplayName()
{ "zh", "Australia/Sydney", "2004-07-15T00:00:00Z", "vvvv", "\\u6fb3\\u5927\\u5229\\u4e9a\\u4e1c\\u90e8\\u65f6\\u95f4", "Australia/Sydney" },
{ "zh", "Europe/London", "2004-01-15T00:00:00Z", "Z", "+0000", "+0:00" },
- { "zh", "Europe/London", "2004-01-15T00:00:00Z", "ZZZZ", "\\u683c\\u6797\\u5c3c\\u6cbb\\u6807\\u51c6\\u65f6\\u95f4+0000", "+0:00" },
- { "zh", "Europe/London", "2004-01-15T00:00:00Z", "z", "\\u683c\\u6797\\u5c3c\\u6cbb\\u6807\\u51c6\\u65f6\\u95f4+0000", "+0:00" },
+ { "zh", "Europe/London", "2004-01-15T00:00:00Z", "ZZZZ", "\\u683c\\u6797\\u5c3c\\u6cbb\\u6807\\u51c6\\u65f6\\u95f4", "+0:00" },
+ { "zh", "Europe/London", "2004-01-15T00:00:00Z", "z", "\\u683c\\u6797\\u5c3c\\u6cbb\\u6807\\u51c6\\u65f6\\u95f4", "+0:00" },
{ "zh", "Europe/London", "2004-01-15T00:00:00Z", "V", "GMT", "+0:00" },
{ "zh", "Europe/London", "2004-01-15T00:00:00Z", "zzzz", "\\u683C\\u6797\\u5C3C\\u6CBB\\u6807\\u51C6\\u65F6\\u95F4", "+0:00" },
{ "zh", "Europe/London", "2004-07-15T00:00:00Z", "Z", "+0100", "+1:00" },
@@ -2594,9 +2650,9 @@ void DateFormatTest::TestTimeZoneDisplayName()
{ "hi", "Australia/Sydney", "2004-07-15T00:00:00Z", "vvvv", "\\u0911\\u0938\\u094d\\u091f\\u094d\\u0930\\u0947\\u0932\\u093f\\u092f\\u093e (\\u0938\\u093f\\u0921\\u0928\\u0940)", "Australia/Sydney" },
{ "hi", "Europe/London", "2004-01-15T00:00:00Z", "Z", "+0000", "+0:00" },
- { "hi", "Europe/London", "2004-01-15T00:00:00Z", "ZZZZ", "GMT+\\u0966\\u0966:\\u0966\\u0966", "+0:00" },
- { "hi", "Europe/London", "2004-01-15T00:00:00Z", "z", "GMT+\\u0966\\u0966:\\u0966\\u0966", "+0:00" },
- { "hi", "Europe/London", "2004-01-15T00:00:00Z", "zzzz", "GMT+\\u0966\\u0966:\\u0966\\u0966", "+0:00" },
+ { "hi", "Europe/London", "2004-01-15T00:00:00Z", "ZZZZ", "GMT", "+0:00" },
+ { "hi", "Europe/London", "2004-01-15T00:00:00Z", "z", "GMT", "+0:00" },
+ { "hi", "Europe/London", "2004-01-15T00:00:00Z", "zzzz", "GMT", "+0:00" },
{ "hi", "Europe/London", "2004-07-15T00:00:00Z", "Z", "+0100", "+1:00" },
{ "hi", "Europe/London", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+\\u0966\\u0967:\\u0966\\u0966", "+1:00" },
{ "hi", "Europe/London", "2004-07-15T00:00:00Z", "z", "GMT+\\u0966\\u0967:\\u0966\\u0966", "+1:00" },
@@ -2700,8 +2756,8 @@ void DateFormatTest::TestTimeZoneDisplayName()
{ "bg", "Australia/Sydney", "2004-07-15T00:00:00Z", "vvvv", "\\u0410\\u0432\\u0441\\u0442\\u0440\\u0430\\u043b\\u0438\\u044f (\\u0421\\u0438\\u0434\\u043D\\u0438)", "Australia/Sydney" },
{ "bg", "Europe/London", "2004-01-15T00:00:00Z", "Z", "+0000", "+0:00" },
- { "bg", "Europe/London", "2004-01-15T00:00:00Z", "ZZZZ", "\\u0413\\u0440\\u0438\\u0438\\u043D\\u0443\\u0438\\u0447+0000", "+0:00" },
- { "bg", "Europe/London", "2004-01-15T00:00:00Z", "z", "\\u0413\\u0440\\u0438\\u0438\\u043D\\u0443\\u0438\\u0447+0000", "+0:00" },
+ { "bg", "Europe/London", "2004-01-15T00:00:00Z", "ZZZZ", "\\u0413\\u0440\\u0438\\u0438\\u043D\\u0443\\u0438\\u0447", "+0:00" },
+ { "bg", "Europe/London", "2004-01-15T00:00:00Z", "z", "\\u0413\\u0440\\u0438\\u0438\\u043D\\u0443\\u0438\\u0447", "+0:00" },
{ "bg", "Europe/London", "2004-01-15T00:00:00Z", "zzzz", "\\u0427\\u0430\\u0441\\u043E\\u0432\\u0430 \\u0437\\u043E\\u043D\\u0430 \\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447", "+0:00" },
{ "bg", "Europe/London", "2004-07-15T00:00:00Z", "Z", "+0100", "+1:00" },
{ "bg", "Europe/London", "2004-07-15T00:00:00Z", "ZZZZ", "\\u0413\\u0440\\u0438\\u0438\\u043D\\u0443\\u0438\\u0447+0100", "+1:00" },
@@ -2807,8 +2863,8 @@ void DateFormatTest::TestTimeZoneDisplayName()
{ "ja", "Australia/Sydney", "2004-07-15T00:00:00Z", "vvvv", "\\u30aa\\u30fc\\u30b9\\u30c8\\u30e9\\u30ea\\u30a2 (\\u30b7\\u30c9\\u30cb\\u30fc)", "Australia/Sydney" },
{ "ja", "Europe/London", "2004-01-15T00:00:00Z", "Z", "+0000", "+0:00" },
- { "ja", "Europe/London", "2004-01-15T00:00:00Z", "ZZZZ", "GMT+00:00", "+0:00" },
- { "ja", "Europe/London", "2004-01-15T00:00:00Z", "z", "GMT+00:00", "+0:00" },
+ { "ja", "Europe/London", "2004-01-15T00:00:00Z", "ZZZZ", "GMT", "+0:00" },
+ { "ja", "Europe/London", "2004-01-15T00:00:00Z", "z", "GMT", "+0:00" },
{ "ja", "Europe/London", "2004-01-15T00:00:00Z", "V", "GMT", "+0:00" },
{ "ja", "Europe/London", "2004-01-15T00:00:00Z", "zzzz", "\\u30B0\\u30EA\\u30CB\\u30C3\\u30B8\\u6A19\\u6E96\\u6642", "+0:00" },
{ "ja", "Europe/London", "2004-07-15T00:00:00Z", "Z", "+0100", "+1:00" },
@@ -2912,9 +2968,9 @@ void DateFormatTest::TestTimeZoneDisplayName()
{ "si", "Australia/Sydney", "2004-07-15T00:00:00Z", "vvvv", "AU (Sydney)", "Australia/Sydney" },
{ "si", "Europe/London", "2004-01-15T00:00:00Z", "Z", "+0000", "+0:00" },
- { "si", "Europe/London", "2004-01-15T00:00:00Z", "ZZZZ", "GMT+00:00", "+0:00" },
- { "si", "Europe/London", "2004-01-15T00:00:00Z", "z", "GMT+00:00", "+0:00" },
- { "si", "Europe/London", "2004-01-15T00:00:00Z", "zzzz", "GMT+00:00", "+0:00" },
+ { "si", "Europe/London", "2004-01-15T00:00:00Z", "ZZZZ", "GMT", "+0:00" },
+ { "si", "Europe/London", "2004-01-15T00:00:00Z", "z", "GMT", "+0:00" },
+ { "si", "Europe/London", "2004-01-15T00:00:00Z", "zzzz", "GMT", "+0:00" },
{ "si", "Europe/London", "2004-07-15T00:00:00Z", "Z", "+0100", "+1:00" },
{ "si", "Europe/London", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+01:00", "+1:00" },
{ "si", "Europe/London", "2004-07-15T00:00:00Z", "z", "GMT+01:00", "+1:00" },
diff --git a/icu4c/source/test/intltest/dtptngts.cpp b/icu4c/source/test/intltest/dtptngts.cpp
index 28a89fab5eb..d53d2b6bcf3 100644
--- a/icu4c/source/test/intltest/dtptngts.cpp
+++ b/icu4c/source/test/intltest/dtptngts.cpp
@@ -272,7 +272,7 @@ void IntlTestDateTimePatternGeneratorAPI::testAPI(/*char *par*/)
UnicodeString("Thu, Oct 14, 1999 6:58:59 AM"),
UnicodeString("6:58 AM"),
UnicodeString("6:58 AM"),
- UnicodeString("6:58 AM GMT+00:00"),
+ UnicodeString("6:58 AM GMT"),
UnicodeString(""),
};
diff --git a/icu4c/source/test/intltest/tzfmttst.cpp b/icu4c/source/test/intltest/tzfmttst.cpp
index 145af36e4a9..84a64deb74f 100644
--- a/icu4c/source/test/intltest/tzfmttst.cpp
+++ b/icu4c/source/test/intltest/tzfmttst.cpp
@@ -1,6 +1,6 @@
/*
*******************************************************************************
-* Copyright (C) 2007-2010, International Business Machines Corporation and *
+* Copyright (C) 2007-2011, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*/
@@ -102,16 +102,16 @@ TimeZoneFormatTest::TestTimeZoneRoundTrip(void) {
}
StringEnumeration *tzids = TimeZone::createEnumeration();
- if (U_FAILURE(status)) {
- errln("tzids->count failed");
- return;
- }
-
int32_t inRaw, inDst;
int32_t outRaw, outDst;
// Run the roundtrip test
for (int32_t locidx = 0; locidx < nLocales; locidx++) {
+ UnicodeString localGMTString;
+ SimpleDateFormat gmtFmt(UnicodeString("ZZZZ"), LOCALES[locidx], status);
+ gmtFmt.setTimeZone(*TimeZone::getGMT());
+ gmtFmt.format(0.0, localGMTString);
+
for (int32_t patidx = 0; patidx < NUM_PATTERNS; patidx++) {
SimpleDateFormat *sdf = new SimpleDateFormat((UnicodeString)PATTERNS[patidx], LOCALES[locidx], status);
@@ -208,7 +208,7 @@ TimeZoneFormatTest::TestTimeZoneRoundTrip(void) {
numDigits++;
}
}
- if (numDigits >= 3) {
+ if (tzstr == localGMTString || numDigits >= 3) {
// Localized GMT or RFC: total offset (raw + dst) must be preserved.
int32_t inOffset = inRaw + inDst;
int32_t outOffset = outRaw + outDst;
@@ -274,9 +274,9 @@ public:
UBool expectedRoundTrip[4];
int32_t testLen = 0;
- StringEnumeration *tzids = TimeZone::createEnumeration();
+ StringEnumeration *tzids = TimeZone::createTimeZoneIDEnumeration(UCAL_ZONE_TYPE_CANONICAL, NULL, NULL, status);
if (U_FAILURE(status)) {
- log.errln("tzids->count failed");
+ log.errln("TimeZone::createTimeZoneIDEnumeration failed");
return;
}
@@ -330,17 +330,6 @@ public:
timer = Calendar::getNow();
while ((tzid = tzids->snext(status))) {
- UnicodeString canonical;
- TimeZone::getCanonicalID(*tzid, canonical, status);
- if (U_FAILURE(status)) {
- // Unknown ID - we should not get here
- status = U_ZERO_ERROR;
- continue;
- }
- if (*tzid != canonical) {
- // Skip aliases
- continue;
- }
BasicTimeZone *tz = (BasicTimeZone*) TimeZone::createTimeZone(*tzid);
sdf->setTimeZone(*tz);
diff --git a/icu4c/source/test/intltest/tztest.cpp b/icu4c/source/test/intltest/tztest.cpp
index f293b176dc1..250e1b0ac2b 100644
--- a/icu4c/source/test/intltest/tztest.cpp
+++ b/icu4c/source/test/intltest/tztest.cpp
@@ -1443,8 +1443,8 @@ TimeZoneTest::TestDisplayName()
{FALSE, TimeZone::SHORT_COMMONLY_USED, "PST"},
{TRUE, TimeZone::SHORT_COMMONLY_USED, "PDT"},
- {FALSE, TimeZone::GENERIC_LOCATION, "United States (Los Angeles)"},
- {TRUE, TimeZone::GENERIC_LOCATION, "United States (Los Angeles)"},
+ {FALSE, TimeZone::GENERIC_LOCATION, "United States Time (Los Angeles)"},
+ {TRUE, TimeZone::GENERIC_LOCATION, "United States Time (Los Angeles)"},
{FALSE, TimeZone::LONG, ""}
};