ICU-8342 Refactoring ZoneStringFormat into TimeZoneNames and TimeZoneFormat (all internal APIs for now). Also supporting localized GMT zero format and fallback region format for generic names.

X-SVN-Rev: 29984
This commit is contained in:
Yoshito Umaoka 2011-05-03 14:59:01 +00:00
parent 607f78619b
commit 4d7569c743
30 changed files with 4558 additions and 3088 deletions

View file

@ -80,11 +80,12 @@ regexcmp.o rematch.o repattrn.o regexst.o regextxt.o udatpg.o uregex.o uregexc.o
ulocdata.o measfmt.o currfmt.o curramt.o currunit.o measure.o utmscale.o \
csdetect.o csmatch.o csr2022.o csrecog.o csrmbcs.o csrsbcs.o csrucode.o csrutf8.o inputext.o \
wintzimpl.o windtfmt.o winnmfmt.o basictz.o dtrule.o rbtz.o tzrule.o tztrans.o vtzone.o \
zonemeta.o zstrfmt.o plurrule.o plurfmt.o selfmt.o dtitvfmt.o dtitvinf.o \
zonemeta.o plurrule.o plurfmt.o selfmt.o dtitvfmt.o dtitvinf.o \
tmunit.o tmutamt.o tmutfmt.o colldata.o bmsearch.o bms.o currpinf.o \
uspoof.o uspoof_impl.o uspoof_build.o uspoof_conf.o uspoof_wsconf.o \
ztrans.o zrule.o vzone.o fphdlimp.o fpositer.o locdspnm.o \
decNumber.o decContext.o alphaindex.o
decNumber.o decContext.o alphaindex.o tznames.o tznames_impl.o tzgnames.o \
tzfmt.o
## Header files to install
HEADERS = $(srcdir)/unicode/*.h

View file

@ -1,6 +1,6 @@
/*
*******************************************************************************
* Copyright (C) 1997-2010, International Business Machines Corporation and *
* Copyright (C) 1997-2011, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*

View file

@ -1,6 +1,6 @@
/*
*******************************************************************************
* Copyright (C) 1997-2009, International Business Machines Corporation and *
* Copyright (C) 1997-2011, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*
@ -35,8 +35,8 @@
#include "gregoimp.h"
#include "hash.h"
#include "uresimp.h"
#include "zstrfmt.h"
#include "ureslocs.h"
#include "tznames.h"
// *****************************************************************************
// class DateFormatSymbols
@ -120,18 +120,19 @@ static const UChar gLastResortEras[2][3] =
{0x0041, 0x0044, 0x0000} /* "AD" */
};
// Not used now
//// These are the zone strings of last resort.
//static const UChar gLastResortZoneStrings[5][4] =
//{
// {0x0047, 0x004D, 0x0054, 0x0000}, /* "GMT" */
// {0x0047, 0x004D, 0x0054, 0x0000}, /* "GMT" */
// {0x0047, 0x004D, 0x0054, 0x0000}, /* "GMT" */
// {0x0047, 0x004D, 0x0054, 0x0000}, /* "GMT" */
// {0x0047, 0x004D, 0x0054, 0x0000}, /* "GMT" */
//};
// These are the zone strings of last resort.
static const UChar gLastResortZoneStrings[7][4] =
{
{0x0047, 0x004D, 0x0054, 0x0000}, /* "GMT" */
{0x0047, 0x004D, 0x0054, 0x0000}, /* "GMT" */
{0x0047, 0x004D, 0x0054, 0x0000}, /* "GMT" */
{0x0047, 0x004D, 0x0054, 0x0000}, /* "GMT" */
{0x0047, 0x004D, 0x0054, 0x0000}, /* "GMT" */
{0x0047, 0x004D, 0x0054, 0x0000}, /* "GMT" */
{0x0047, 0x004D, 0x0054, 0x0000} /* "GMT" */
};
static const UChar gLastResortGmtZero[] =
{0x0047, 0x004D, 0x0054, 0x0000}; /* GMT */
static const UChar gLastResortGmtFormat[] =
{0x0047, 0x004D, 0x0054, 0x007B, 0x0030, 0x007D, 0x0000}; /* GMT{0} */
@ -189,6 +190,7 @@ static const char gAmPmMarkersTag[]="AmPmMarkers";
static const char gQuartersTag[]="quarters";
static const char gZoneStringsTag[]="zoneStrings";
static const char gGmtZeroFormatTag[] = "gmtZeroFormat";
static const char gGmtFormatTag[]="gmtFormat";
static const char gHourFormatTag[]="hourFormat";
@ -329,6 +331,7 @@ DateFormatSymbols::copyData(const DateFormatSymbols& other) {
assignArray(fShortQuarters, fShortQuartersCount, other.fShortQuarters, other.fShortQuartersCount);
assignArray(fStandaloneQuarters, fStandaloneQuartersCount, other.fStandaloneQuarters, other.fStandaloneQuartersCount);
assignArray(fStandaloneShortQuarters, fStandaloneShortQuartersCount, other.fStandaloneShortQuarters, other.fStandaloneShortQuartersCount);
fGmtZero = other.fGmtZero;
fGmtFormat = other.fGmtFormat;
assignArray(fGmtHourFormats, fGmtHourFormatsCount, other.fGmtHourFormats, other.fGmtHourFormatsCount);
@ -344,10 +347,7 @@ DateFormatSymbols::copyData(const DateFormatSymbols& other) {
}
fZSFLocale = other.fZSFLocale;
// Other zone strings data is created on demand
fZoneStringFormat = NULL;
fLocaleZoneStrings = NULL;
fZSFCachePtr = NULL;
fZSFLocal = NULL;
// fastCopyFrom() - see assignArray comments
fLocalPatternChars.fastCopyFrom(other.fLocalPatternChars);
@ -410,21 +410,11 @@ void DateFormatSymbols::disposeZoneStrings()
}
uprv_free(fLocaleZoneStrings);
}
if (fZSFLocal) {
delete fZSFLocal;
}
if (fZSFCachePtr) {
delete fZSFCachePtr;
}
fZoneStrings = NULL;
fLocaleZoneStrings = NULL;
fZoneStringsRowCount = 0;
fZoneStringsColCount = 0;
fZoneStringFormat = NULL;
fZSFLocal = NULL;
fZSFCachePtr = NULL;
}
UBool
@ -469,6 +459,7 @@ DateFormatSymbols::operator==(const DateFormatSymbols& other) const
fStandaloneQuartersCount == other.fStandaloneQuartersCount &&
fStandaloneShortQuartersCount == other.fStandaloneShortQuartersCount &&
fGmtHourFormatsCount == other.fGmtHourFormatsCount &&
fGmtZero == other.fGmtZero &&
fGmtFormat == other.fGmtFormat)
{
// Now compare the arrays themselves
@ -1033,41 +1024,6 @@ DateFormatSymbols::setAmPmStrings(const UnicodeString* amPmsArray, int32_t count
fAmPmsCount = count;
}
//------------------------------------------------------
const ZoneStringFormat*
DateFormatSymbols::getZoneStringFormat(void) const {
umtx_lock(&LOCK);
if (fZoneStringFormat == NULL) {
((DateFormatSymbols*)this)->initZoneStringFormat();
}
umtx_unlock(&LOCK);
return fZoneStringFormat;
}
void
DateFormatSymbols::initZoneStringFormat(void) {
if (fZoneStringFormat == NULL) {
UErrorCode status = U_ZERO_ERROR;
if (fZoneStrings) {
// Create an istance of ZoneStringFormat by the custom zone strings array
fZSFLocal = new ZoneStringFormat(fZoneStrings, fZoneStringsRowCount,
fZoneStringsColCount, status);
if (U_FAILURE(status)) {
delete fZSFLocal;
} else {
fZoneStringFormat = (const ZoneStringFormat*)fZSFLocal;
}
} else {
fZSFCachePtr = ZoneStringFormat::getZoneStringFormat(fZSFLocale, status);
if (U_FAILURE(status)) {
delete fZSFCachePtr;
} else {
fZoneStringFormat = fZSFCachePtr->get();
}
}
}
}
const UnicodeString**
DateFormatSymbols::getZoneStrings(int32_t& rowCount, int32_t& columnCount) const
{
@ -1089,18 +1045,89 @@ DateFormatSymbols::getZoneStrings(int32_t& rowCount, int32_t& columnCount) const
return result;
}
// For now, we include all zones
#define ZONE_SET UCAL_ZONE_TYPE_ANY
// This code must be called within a synchronized block
void
DateFormatSymbols::initZoneStringsArray(void) {
if (fZoneStrings == NULL && fLocaleZoneStrings == NULL) {
if (fZoneStringFormat == NULL) {
initZoneStringFormat();
if (fZoneStrings != NULL || fLocaleZoneStrings != NULL) {
return;
}
UErrorCode status = U_ZERO_ERROR;
StringEnumeration *tzids = NULL;
UnicodeString ** zarray = NULL;
TimeZoneNames *tzNames = NULL;
int32_t rows = 0;
do { // dummy do-while
tzids = TimeZone::createTimeZoneIDEnumeration(ZONE_SET, NULL, NULL, status);
rows = tzids->count(status);
if (U_FAILURE(status)) {
break;
}
if (fZoneStringFormat) {
UErrorCode status = U_ZERO_ERROR;
fLocaleZoneStrings = fZoneStringFormat->createZoneStringsArray(uprv_getUTCtime() /* use current time */,
fZoneStringsRowCount, fZoneStringsColCount, status);
// Allocate array
int32_t size = rows * sizeof(UnicodeString*);
zarray = (UnicodeString**)uprv_malloc(size);
if (zarray == NULL) {
status = U_MEMORY_ALLOCATION_ERROR;
break;
}
uprv_memset(zarray, 0, size);
tzNames = TimeZoneNames::createInstance(fZSFLocale, status);
const UnicodeString *tzid;
int32_t i = 0;
UDate now = Calendar::getNow();
UnicodeString tzDispName;
while ((tzid = tzids->snext(status))) {
if (U_FAILURE(status)) {
break;
}
zarray[i] = new UnicodeString[5];
if (zarray[i] == NULL) {
status = U_MEMORY_ALLOCATION_ERROR;
break;
}
zarray[i][0].setTo(*tzid);
zarray[i][1].setTo(tzNames->getDisplayName(*tzid, UTZNM_LONG_STANDARD, now, tzDispName));
zarray[i][2].setTo(tzNames->getDisplayName(*tzid, UTZNM_SHORT_STANDARD, now, tzDispName));
zarray[i][3].setTo(tzNames->getDisplayName(*tzid, UTZNM_LONG_DAYLIGHT, now, tzDispName));
zarray[i][4].setTo(tzNames->getDisplayName(*tzid, UTZNM_SHORT_DAYLIGHT, now, tzDispName));
i++;
}
} while (FALSE);
if (U_FAILURE(status)) {
if (zarray) {
for (int32_t i = 0; i < rows; i++) {
if (zarray[i]) {
delete[] zarray[i];
}
}
uprv_free(zarray);
}
}
if (tzNames) {
delete tzNames;
}
if (tzids) {
delete tzids;
}
fLocaleZoneStrings = zarray;
fZoneStringsRowCount = rows;
fZoneStringsColCount = 5;
}
void
@ -1236,10 +1263,6 @@ DateFormatSymbols::initializeData(const Locale& locale, const char *type, UError
fZoneStrings = NULL;
fLocaleZoneStrings = NULL;
fZoneStringFormat = NULL;
fZSFLocal = NULL;
fZSFCachePtr = NULL;
// We need to preserve the requested locale for
// lazy ZoneStringFormat instantiation. ZoneStringFormat
// is region sensitive, thus, bundle locale bundle's locale
@ -1318,6 +1341,7 @@ DateFormatSymbols::initializeData(const Locale& locale, const char *type, UError
initField(&fStandaloneQuarters, fStandaloneQuartersCount, (const UChar *)gLastResortQuarters, kQuarterNum, kQuarterLen, status);
initField(&fStandaloneShortQuarters, fStandaloneShortQuartersCount, (const UChar *)gLastResortQuarters, kQuarterNum, kQuarterLen, status);
initField(&fGmtHourFormats, fGmtHourFormatsCount, (const UChar *)gLastResortGmtHourFormats, kGmtHourNum, kGmtHourLen, status);
fGmtZero.setTo(TRUE, gLastResortGmtZero, -1);
fGmtFormat.setTo(TRUE, gLastResortGmtFormat, -1);
fLocalPatternChars.setTo(TRUE, gPatternChars, PATTERN_CHARS_LEN);
}
@ -1383,6 +1407,12 @@ DateFormatSymbols::initializeData(const Locale& locale, const char *type, UError
initField(&fStandaloneShortQuarters, fStandaloneShortQuartersCount, calData.getByKey2(gQuartersTag, gNamesAbbrTag, status), status);
}
// GMT zero
resStr = ures_getStringByKeyWithFallback(zoneStringsArray, gGmtZeroFormatTag, &len, &status);
if (len > 0) {
fGmtZero.setTo(TRUE, resStr, len);
}
// GMT format patterns
resStr = ures_getStringByKeyWithFallback(zoneStringsArray, gGmtFormatTag, &len, &status);
if (len > 0) {

View file

@ -255,6 +255,10 @@
<ClCompile Include="sortkey.cpp" />
<ClCompile Include="stsearch.cpp" />
<ClCompile Include="tblcoll.cpp" />
<ClCompile Include="tzfmt.cpp" />
<ClCompile Include="tzgnames.cpp" />
<ClCompile Include="tznames.cpp" />
<ClCompile Include="tznames_impl.cpp" />
<ClCompile Include="ucol.cpp" />
<ClCompile Include="ucol_bld.cpp" />
<ClCompile Include="ucol_cnt.cpp" />
@ -356,7 +360,6 @@
</ClCompile>
<ClCompile Include="zonemeta.cpp" />
<ClCompile Include="zrule.cpp" />
<ClCompile Include="zstrfmt.cpp" />
<ClCompile Include="ztrans.cpp" />
<ClCompile Include="ucln_in.c">
<DisableLanguageExtensions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">false</DisableLanguageExtensions>
@ -570,6 +573,10 @@
</Command>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
</CustomBuild>
<ClInclude Include="tzfmt.h" />
<ClInclude Include="tzgnames.h" />
<ClInclude Include="tznames.h" />
<ClInclude Include="tznames_impl.h" />
<ClInclude Include="ucol_bld.h" />
<ClInclude Include="ucol_cnt.h" />
<ClInclude Include="ucol_elm.h" />
@ -668,7 +675,7 @@
</CustomBuild>
<ClInclude Include="currfmt.h" />
<CustomBuild Include="unicode\currpinf.h">
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy "%(FullPath)" ..\..\include\unicode
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy "%(FullPath)" ..\..\include\unicode
</Command>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">copy "%(FullPath)" ..\..\include\unicode
@ -1328,7 +1335,6 @@
<ClInclude Include="wintzimpl.h" />
<ClInclude Include="zonemeta.h" />
<ClInclude Include="zrule.h" />
<ClInclude Include="zstrfmt.h" />
<ClInclude Include="ztrans.h" />
<ClInclude Include="ucln_in.h" />
<CustomBuild Include="unicode\regex.h">

View file

@ -312,9 +312,6 @@
<ClCompile Include="zrule.cpp">
<Filter>formatting</Filter>
</ClCompile>
<ClCompile Include="zstrfmt.cpp">
<Filter>formatting</Filter>
</ClCompile>
<ClCompile Include="ztrans.cpp">
<Filter>formatting</Filter>
</ClCompile>
@ -471,6 +468,18 @@
<ClCompile Include="alphaindex.cpp">
<Filter>collation</Filter>
</ClCompile>
<ClCompile Include="tzfmt.cpp">
<Filter>formatting</Filter>
</ClCompile>
<ClCompile Include="tzgnames.cpp">
<Filter>formatting</Filter>
</ClCompile>
<ClCompile Include="tznames.cpp">
<Filter>formatting</Filter>
</ClCompile>
<ClCompile Include="tznames_impl.cpp">
<Filter>formatting</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="bocsu.h">
@ -608,9 +617,6 @@
<ClInclude Include="zrule.h">
<Filter>formatting</Filter>
</ClInclude>
<ClInclude Include="zstrfmt.h">
<Filter>formatting</Filter>
</ClInclude>
<ClInclude Include="ztrans.h">
<Filter>formatting</Filter>
</ClInclude>
@ -743,6 +749,18 @@
<ClInclude Include="uspoof_wsconf.h">
<Filter>spoof</Filter>
</ClInclude>
<ClInclude Include="tzfmt.h">
<Filter>formatting</Filter>
</ClInclude>
<ClInclude Include="tzgnames.h">
<Filter>formatting</Filter>
</ClInclude>
<ClInclude Include="tznames.h">
<Filter>formatting</Filter>
</ClInclude>
<ClInclude Include="tznames_impl.h">
<Filter>formatting</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="i18n.rc">

View file

@ -1,6 +1,6 @@
/*
**********************************************************************
* Copyright (c) 2003-2010, International Business Machines
* Copyright (c) 2003-2011, International Business Machines
* Corporation and others. All Rights Reserved.
**********************************************************************
* Author: Alan Liu
@ -24,6 +24,7 @@
#include "uvector.h"
#include <float.h> // DBL_MAX
#include "uresimp.h" // struct UResourceBundle
#include "zonemeta.h"
#ifdef U_DEBUG_TZ
# include <stdio.h>
@ -93,6 +94,8 @@ UOBJECT_DEFINE_RTTI_IMPLEMENTATION(OlsonTimeZone)
* constructor fails so the resultant object is well-behaved.
*/
void OlsonTimeZone::constructEmpty() {
canonicalID = NULL;
transitionCountPre32 = transitionCount32 = transitionCountPost32 = 0;
transitionTimesPre32 = transitionTimes32 = transitionTimesPost32 = NULL;
@ -113,8 +116,9 @@ void OlsonTimeZone::constructEmpty() {
*/
OlsonTimeZone::OlsonTimeZone(const UResourceBundle* top,
const UResourceBundle* res,
const UnicodeString& tzid,
UErrorCode& ec) :
finalZone(NULL), transitionRulesInitialized(FALSE)
BasicTimeZone(tzid), finalZone(NULL), transitionRulesInitialized(FALSE)
{
clearTransitionRules();
U_DEBUG_TZ_MSG(("OlsonTimeZone(%s)\n", ures_getKey((UResourceBundle*)res)));
@ -245,6 +249,9 @@ OlsonTimeZone::OlsonTimeZone(const UResourceBundle* top,
ec = U_ZERO_ERROR;
}
ures_close(&r);
// initialize canonical ID
canonicalID = ZoneMeta::getCanonicalCLDRID(tzid, ec);
}
if (U_FAILURE(ec)) {
@ -264,6 +271,8 @@ OlsonTimeZone::OlsonTimeZone(const OlsonTimeZone& other) :
* Assignment operator
*/
OlsonTimeZone& OlsonTimeZone::operator=(const OlsonTimeZone& other) {
canonicalID = other.canonicalID;
transitionTimesPre32 = other.transitionTimesPre32;
transitionTimes32 = other.transitionTimes32;
transitionTimesPost32 = other.transitionTimesPost32;

View file

@ -1,6 +1,6 @@
/*
**********************************************************************
* Copyright (c) 2003-2010, International Business Machines
* Copyright (c) 2003-2011, International Business Machines
* Corporation and others. All Rights Reserved.
**********************************************************************
* Author: Alan Liu
@ -117,10 +117,13 @@ class U_I18N_API OlsonTimeZone: public BasicTimeZone {
* @param top the top-level zoneinfo resource bundle. This is used
* to lookup the rule that `res' may refer to, if there is one.
* @param res the resource bundle of the zone to be constructed
* @param tzid the time zone ID
* @param ec input-output error code
*/
OlsonTimeZone(const UResourceBundle* top,
const UResourceBundle* res, UErrorCode& ec);
const UResourceBundle* res,
const UnicodeString& tzid,
UErrorCode& ec);
/**
* Copy constructor
@ -271,6 +274,12 @@ class U_I18N_API OlsonTimeZone: public BasicTimeZone {
virtual void getTimeZoneRules(const InitialTimeZoneRule*& initial,
const TimeZoneRule* trsrules[], int32_t& trscount, UErrorCode& status) /*const*/;
/**
* Internal API returning the canonical ID of this zone.
* This ID won't be affected by setID().
*/
const UChar *getCanonicalID() const;
private:
/**
* Default constructor. Creates a time zone with an empty ID and
@ -366,6 +375,11 @@ private:
*/
int32_t finalStartYear;
/*
* Canonical (CLDR) ID of this zone
*/
const UChar *canonicalID;
/* BasicTimeZone support */
void clearTransitionRules(void);
void deleteTransitionRules(void);
@ -419,6 +433,12 @@ OlsonTimeZone::initialDstOffset() const {
return typeOffsets[1];
}
inline const UChar*
OlsonTimeZone::getCanonicalID() const {
return canonicalID;
}
U_NAMESPACE_END
#endif // !UCONFIG_NO_FORMATTING

View file

@ -52,9 +52,9 @@
#include "hebrwcal.h"
#include "cstring.h"
#include "uassert.h"
#include "zstrfmt.h"
#include "cmemory.h"
#include "umutex.h"
#include "tzfmt.h"
#include <float.h>
#if defined( U_DEBUG_CALSVC ) || defined (U_DEBUG_CAL)
@ -177,6 +177,9 @@ SimpleDateFormat::~SimpleDateFormat()
if (fNumberFormatters) {
uprv_free(fNumberFormatters);
}
if (fTimeZoneFormat) {
delete fTimeZoneFormat;
}
while (fOverrideList) {
NSOverride *cur = fOverrideList;
@ -191,6 +194,7 @@ SimpleDateFormat::~SimpleDateFormat()
SimpleDateFormat::SimpleDateFormat(UErrorCode& status)
: fLocale(Locale::getDefault()),
fSymbols(NULL),
fTimeZoneFormat(NULL),
fGMTFormatters(NULL),
fNumberFormatters(NULL),
fOverrideList(NULL)
@ -206,6 +210,7 @@ SimpleDateFormat::SimpleDateFormat(const UnicodeString& pattern,
: fPattern(pattern),
fLocale(Locale::getDefault()),
fSymbols(NULL),
fTimeZoneFormat(NULL),
fGMTFormatters(NULL),
fNumberFormatters(NULL),
fOverrideList(NULL)
@ -225,6 +230,7 @@ SimpleDateFormat::SimpleDateFormat(const UnicodeString& pattern,
: fPattern(pattern),
fLocale(Locale::getDefault()),
fSymbols(NULL),
fTimeZoneFormat(NULL),
fGMTFormatters(NULL),
fNumberFormatters(NULL),
fOverrideList(NULL)
@ -246,6 +252,7 @@ SimpleDateFormat::SimpleDateFormat(const UnicodeString& pattern,
UErrorCode& status)
: fPattern(pattern),
fLocale(locale),
fTimeZoneFormat(NULL),
fGMTFormatters(NULL),
fNumberFormatters(NULL),
fOverrideList(NULL)
@ -267,6 +274,7 @@ SimpleDateFormat::SimpleDateFormat(const UnicodeString& pattern,
UErrorCode& status)
: fPattern(pattern),
fLocale(locale),
fTimeZoneFormat(NULL),
fGMTFormatters(NULL),
fNumberFormatters(NULL),
fOverrideList(NULL)
@ -290,6 +298,7 @@ SimpleDateFormat::SimpleDateFormat(const UnicodeString& pattern,
UErrorCode& status)
: fPattern(pattern),
fLocale(Locale::getDefault()),
fTimeZoneFormat(NULL),
fSymbols(symbolsToAdopt),
fGMTFormatters(NULL),
fNumberFormatters(NULL),
@ -312,6 +321,7 @@ SimpleDateFormat::SimpleDateFormat(const UnicodeString& pattern,
: fPattern(pattern),
fLocale(Locale::getDefault()),
fSymbols(new DateFormatSymbols(symbols)),
fTimeZoneFormat(NULL),
fGMTFormatters(NULL),
fNumberFormatters(NULL),
fOverrideList(NULL)
@ -334,6 +344,7 @@ SimpleDateFormat::SimpleDateFormat(EStyle timeStyle,
UErrorCode& status)
: fLocale(locale),
fSymbols(NULL),
fTimeZoneFormat(NULL),
fGMTFormatters(NULL),
fNumberFormatters(NULL),
fOverrideList(NULL)
@ -355,6 +366,7 @@ SimpleDateFormat::SimpleDateFormat(const Locale& locale,
UErrorCode& status)
: fPattern(gDefaultPattern),
fLocale(locale),
fTimeZoneFormat(NULL),
fSymbols(NULL),
fGMTFormatters(NULL),
fNumberFormatters(NULL),
@ -389,6 +401,7 @@ SimpleDateFormat::SimpleDateFormat(const Locale& locale,
SimpleDateFormat::SimpleDateFormat(const SimpleDateFormat& other)
: DateFormat(other),
fSymbols(NULL),
fTimeZoneFormat(NULL),
fGMTFormatters(NULL),
fNumberFormatters(NULL),
fOverrideList(NULL)
@ -417,6 +430,11 @@ SimpleDateFormat& SimpleDateFormat::operator=(const SimpleDateFormat& other)
fPattern = other.fPattern;
// TimeZoneFormat in ICU4C only deneds on a locale for now
if (fLocale != other.fLocale) {
delete fTimeZoneFormat;
}
return *this;
}
@ -930,21 +948,26 @@ SimpleDateFormat::appendGMT(NumberFormat *currentNumberFormat,UnicodeString &app
if (U_FAILURE(status)) {
return;
}
if (isDefaultGMTFormat()) {
formatGMTDefault(currentNumberFormat,appendTo, offset);
if (offset == 0) {
// use GMT zero format
appendTo += fSymbols->fGmtZero;
} else {
((SimpleDateFormat*)this)->initGMTFormatters(status);
if (U_SUCCESS(status)) {
int32_t type;
if (offset < 0) {
offset = -offset;
type = (offset % U_MILLIS_PER_MINUTE) == 0 ? kGMTNegativeHM : kGMTNegativeHMS;
} else {
type = (offset % U_MILLIS_PER_MINUTE) == 0 ? kGMTPositiveHM : kGMTPositiveHMS;
if (isDefaultGMTFormat()) {
formatGMTDefault(currentNumberFormat,appendTo, offset);
} else {
((SimpleDateFormat*)this)->initGMTFormatters(status);
if (U_SUCCESS(status)) {
int32_t type;
if (offset < 0) {
offset = -offset;
type = (offset % U_MILLIS_PER_MINUTE) == 0 ? kGMTNegativeHM : kGMTNegativeHMS;
} else {
type = (offset % U_MILLIS_PER_MINUTE) == 0 ? kGMTPositiveHM : kGMTPositiveHMS;
}
Formattable param(offset, Formattable::kIsDate);
FieldPosition fpos(0);
fGMTFormatters[type]->format(&param, 1, appendTo, fpos, status);
}
Formattable param(offset, Formattable::kIsDate);
FieldPosition fpos(0);
fGMTFormatters[type]->format(&param, 1, appendTo, fpos, status);
}
}
}
@ -1648,34 +1671,32 @@ SimpleDateFormat::subFormat(UnicodeString &appendTo,
case UDAT_TIMEZONE_SPECIAL_FIELD:
{
UnicodeString zoneString;
const ZoneStringFormat *zsf = fSymbols->getZoneStringFormat();
if (zsf) {
const TimeZone& tz = cal.getTimeZone();
UDate date = cal.getTime(status);
if (U_SUCCESS(status)) {
if (patternCharIndex == UDAT_TIMEZONE_FIELD) {
if (count < 4) {
// "z", "zz", "zzz"
zsf->getSpecificShortString(cal, TRUE /*commonly used only*/,
zoneString, status);
tzFormat()->format(UTZFMT_STYLE_SPECIFIC_SHORT_COMMONLY_USED, tz, date, zoneString);
} else {
// "zzzz"
zsf->getSpecificLongString(cal, zoneString, status);
tzFormat()->format(UTZFMT_STYLE_SPECIFIC_LONG, tz, date, zoneString);
}
} else if (patternCharIndex == UDAT_TIMEZONE_GENERIC_FIELD) {
if (count == 1) {
// "v"
zsf->getGenericShortString(cal, TRUE /*commonly used only*/,
zoneString, status);
tzFormat()->format(UTZFMT_STYLE_GENERIC_SHORT, tz, date, zoneString);
} else if (count == 4) {
// "vvvv"
zsf->getGenericLongString(cal, zoneString, status);
tzFormat()->format(UTZFMT_STYLE_GENERIC_LONG, tz, date, zoneString);
}
} else { // patternCharIndex == UDAT_TIMEZONE_SPECIAL_FIELD
if (count == 1) {
// "V"
zsf->getSpecificShortString(cal, FALSE /*ignore commonly used*/,
zoneString, status);
tzFormat()->format(UTZFMT_STYLE_SPECIFIC_SHORT, tz, date, zoneString);
} else if (count == 4) {
// "VVVV"
zsf->getGenericLocationString(cal, zoneString, status);
tzFormat()->format(UTZFMT_STYLE_LOCATION, tz, date, zoneString);
}
}
}
@ -2812,70 +2833,76 @@ int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UC
}
// Step 3
// At this point, check for named time zones by looking through
// the locale data from the DateFormatZoneData strings.
// Want to be able to parse both short and long forms.
// optimize for calendar's current time zone
const ZoneStringFormat *zsf = fSymbols->getZoneStringFormat();
if (zsf) {
UErrorCode status = U_ZERO_ERROR;
const ZoneStringInfo *zsinfo = NULL;
int32_t matchLen;
switch (patternCharIndex) {
case UDAT_TIMEZONE_FIELD: // 'z'
if (count < 4) {
zsinfo = zsf->findSpecificShort(text, start, matchLen, status);
} else {
zsinfo = zsf->findSpecificLong(text, start, matchLen, status);
}
break;
case UDAT_TIMEZONE_GENERIC_FIELD: // 'v'
if (count == 1) {
zsinfo = zsf->findGenericShort(text, start, matchLen, status);
} else if (count == 4) {
zsinfo = zsf->findGenericLong(text, start, matchLen, status);
}
break;
case UDAT_TIMEZONE_SPECIAL_FIELD: // 'V'
if (count == 1) {
zsinfo = zsf->findSpecificShort(text, start, matchLen, status);
} else if (count == 4) {
zsinfo = zsf->findGenericLocation(text, start, matchLen, status);
}
break;
default:
break;
}
if (U_SUCCESS(status) && zsinfo != NULL) {
if (zsinfo->isStandard()) {
((SimpleDateFormat*)this)->tztype = TZTYPE_STD;
} else if (zsinfo->isDaylight()) {
((SimpleDateFormat*)this)->tztype = TZTYPE_DST;
}
UnicodeString tzid;
zsinfo->getID(tzid);
UnicodeString current;
cal.getTimeZone().getID(current);
if (tzid != current) {
TimeZone *tz = TimeZone::createTimeZone(tzid);
cal.adoptTimeZone(tz);
}
return start + matchLen;
}
}
// Step 4
// Final attempt - is this standalone GMT/UT/UTC?
// Is this standalone Localized GMT zero or GMT/UT/UTC?
int32_t gmtLen = 0;
if (text.compare(start, kGmtLen, gGmt) == 0) {
if (text.compare(start, fSymbols->fGmtZero.length(), fSymbols->fGmtZero) == 0) {
gmtLen = fSymbols->fGmtZero.length();
} else if (text.compare(start, kGmtLen, gGmt) == 0) {
gmtLen = kGmtLen;
} else if (text.compare(start, kUtcLen, gUtc) == 0) {
gmtLen = kUtcLen;
} else if (text.compare(start, kUtLen, gUt) == 0) {
gmtLen = kUtLen;
}
// If we parse the string to the end, we can exit here.
// If any characters follow, we still need to proceed to the
// next step. Otherwise, all time zone names starting with GMT/UT/UTC
// (for example, "UTT") will fail.
if (gmtLen > 0 && ((text.length() - start) == gmtLen)) {
TimeZone *tz = TimeZone::createTimeZone(UnicodeString("Etc/GMT"));
cal.adoptTimeZone(tz);
return start + gmtLen;
}
// Step 4
// At this point, check for named time zones by looking through
// the locale data.
if (patternCharIndex != UDAT_TIMEZONE_RFC_FIELD) {
UTimeZoneTimeType parsedTimeType = UTZFMT_TIME_TYPE_UNKNOWN;
ParsePosition tmpPos(start);
UnicodeString parsedID;
switch (patternCharIndex) {
case UDAT_TIMEZONE_FIELD:
if (count < 4) {
tzFormat()->parse(UTZFMT_STYLE_SPECIFIC_SHORT_COMMONLY_USED, text, tmpPos, parsedID, &parsedTimeType);
} else {
tzFormat()->parse(UTZFMT_STYLE_SPECIFIC_LONG, text, tmpPos, parsedID, &parsedTimeType);
}
break;
case UDAT_TIMEZONE_GENERIC_FIELD:
if (count < 4) {
tzFormat()->parse(UTZFMT_STYLE_GENERIC_SHORT, text, tmpPos, parsedID, &parsedTimeType);
} else {
tzFormat()->parse(UTZFMT_STYLE_GENERIC_LONG, text, tmpPos, parsedID, &parsedTimeType);
}
break;
case UDAT_TIMEZONE_SPECIAL_FIELD:
if (count < 4) {
tzFormat()->parse(UTZFMT_STYLE_SPECIFIC_SHORT, text, tmpPos, parsedID, &parsedTimeType);
} else {
tzFormat()->parse(UTZFMT_STYLE_LOCATION, text, tmpPos, parsedID, &parsedTimeType);
}
break;
}
if (tmpPos.getErrorIndex() < 0) {
if (parsedTimeType == UTZFMT_TIME_TYPE_STANDARD) {
((SimpleDateFormat*)this)->tztype = TZTYPE_STD;
} else if (parsedTimeType == UTZFMT_TIME_TYPE_DAYLIGHT) {
((SimpleDateFormat*)this)->tztype = TZTYPE_DST;
}
UnicodeString current;
cal.getTimeZone().getID(current);
if (parsedID != current) {
TimeZone *tz = TimeZone::createTimeZone(parsedID);
cal.adoptTimeZone(tz);
}
return tmpPos.getIndex();
}
}
// Step 5
// If we saw standalone GMT zero pattern, then use GMT.
if (gmtLen > 0) {
TimeZone *tz = TimeZone::createTimeZone(UnicodeString("Etc/GMT"));
cal.adoptTimeZone(tz);
@ -3280,6 +3307,26 @@ SimpleDateFormat::skipUWhiteSpace(const UnicodeString& text, int32_t pos) const
return pos;
}
//----------------------------------------------------------------------
// Lazy TimeZoneFormat instantiation, semantically const.
TimeZoneFormat *
SimpleDateFormat::tzFormat() const {
if (fTimeZoneFormat == NULL) {
umtx_lock(&LOCK);
{
if (fTimeZoneFormat == NULL) {
UErrorCode status = U_ZERO_ERROR;
TimeZoneFormat *tzfmt = TimeZoneFormat::createInstance(fLocale, status);
U_ASSERT(U_SUCCESS(status));
const_cast<SimpleDateFormat *>(this)->fTimeZoneFormat = tzfmt;
}
}
umtx_unlock(&LOCK);
}
return fTimeZoneFormat;
}
U_NAMESPACE_END
#endif /* #if !UCONFIG_NO_FORMATTING */

View file

@ -417,10 +417,8 @@ TimeZone::createSystemTimeZone(const UnicodeString& id, UErrorCode& ec) {
UResourceBundle *top = openOlsonResource(id, res, ec);
U_DEBUG_TZ_MSG(("post-err=%s\n", u_errorName(ec)));
if (U_SUCCESS(ec)) {
z = new OlsonTimeZone(top, &res, ec);
if (z) {
z->setID(id);
} else {
z = new OlsonTimeZone(top, &res, id, ec);
if (z == NULL) {
U_DEBUG_TZ_MSG(("cstz: olson time zone failed to initialize - err %s\n", u_errorName(ec)));
}
}
@ -1062,7 +1060,26 @@ TimeZone::getEquivalentID(const UnicodeString& id, int32_t index) {
// ---------------------------------------
// These two methods are used by ZoneMeta class only.
// These methods are used by ZoneMeta class only.
const UChar*
TimeZone::findID(const UnicodeString& id) {
const UChar *result = NULL;
UErrorCode ec = U_ZERO_ERROR;
UResourceBundle *rb = ures_openDirect(NULL, kZONEINFO, &ec);
// resolve zone index by name
UResourceBundle *names = ures_getByKey(rb, kNAMES, NULL, &ec);
int32_t idx = findInStringArray(names, id, ec);
result = ures_getStringByIndex(names, idx, NULL, &ec);
if (U_FAILURE(ec)) {
result = NULL;
}
ures_close(names);
ures_close(rb);
return result;
}
const UChar*
TimeZone::dereferOlsonLink(const UnicodeString& id) {

502
icu4c/source/i18n/tzfmt.cpp Normal file
View file

@ -0,0 +1,502 @@
/*
*******************************************************************************
* Copyright (C) 2011, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*/
#include "unicode/utypes.h"
#if !UCONFIG_NO_FORMATTING
#include "tzfmt.h"
#include "tzgnames.h"
#include "cmemory.h"
#include "cstring.h"
#include "putilimp.h"
#include "uassert.h"
#include "ucln_in.h"
#include "uhash.h"
#include "umutex.h"
#include "zonemeta.h"
U_NAMESPACE_BEGIN
// ---------------------------------------------------
// TimeZoneFormatImpl - the TimeZoneFormat implementation
// ---------------------------------------------------
class TimeZoneFormatImpl : public TimeZoneFormat {
public:
TimeZoneFormatImpl(const Locale& locale, UErrorCode& status);
virtual ~TimeZoneFormatImpl();
const TimeZoneNames* getTimeZoneNames() const;
UnicodeString& format(UTimeZoneFormatStyle style, const TimeZone& tz, UDate date,
UnicodeString& name, UTimeZoneTimeType* timeType = NULL) const;
UnicodeString& parse(UTimeZoneFormatStyle style, const UnicodeString& text, ParsePosition& pos,
UnicodeString& tzID, UTimeZoneTimeType* timeType = NULL) const;
private:
Locale fLocale;
char fTargetRegion[ULOC_COUNTRY_CAPACITY];
TimeZoneNames* fTimeZoneNames;
TimeZoneGenericNames* fTimeZoneGenericNames;
UnicodeString& formatGeneric(const TimeZone& tz, UTimeZoneGenericNameType genType, UDate date, UnicodeString& name) const;
UnicodeString& formatSpecific(const TimeZone& tz, UTimeZoneNameType stdType, UTimeZoneNameType dstType,
UDate date, UnicodeString& name, UTimeZoneTimeType *timeType) const;
};
TimeZoneFormatImpl::TimeZoneFormatImpl(const Locale& locale, UErrorCode& status)
: fLocale(locale), fTimeZoneNames(NULL), fTimeZoneGenericNames(NULL) {
const char* region = fLocale.getCountry();
int32_t regionLen = uprv_strlen(region);
if (regionLen == 0) {
char loc[ULOC_FULLNAME_CAPACITY];
uloc_addLikelySubtags(fLocale.getName(), loc, sizeof(loc), &status);
regionLen = uloc_getCountry(loc, fTargetRegion, sizeof(fTargetRegion), &status);
if (U_SUCCESS(status)) {
fTargetRegion[regionLen] = 0;
} else {
return;
}
} else if (regionLen < (int32_t)sizeof(fTargetRegion)) {
uprv_strcpy(fTargetRegion, region);
} else {
fTargetRegion[0] = 0;
}
fTimeZoneNames = TimeZoneNames::createInstance(locale, status);
fTimeZoneGenericNames = new TimeZoneGenericNames(locale, status);
if (U_SUCCESS(status) && fTimeZoneGenericNames == NULL) {
status = U_MEMORY_ALLOCATION_ERROR;
}
}
TimeZoneFormatImpl::~TimeZoneFormatImpl() {
if (fTimeZoneNames != NULL) {
delete fTimeZoneNames;
}
if (fTimeZoneGenericNames != NULL) {
delete fTimeZoneGenericNames;
}
}
const TimeZoneNames*
TimeZoneFormatImpl::getTimeZoneNames() const {
return fTimeZoneNames;
}
UnicodeString&
TimeZoneFormatImpl::format(UTimeZoneFormatStyle style, const TimeZone& tz, UDate date,
UnicodeString& name, UTimeZoneTimeType* timeType /* = NULL */) const {
if (timeType) {
*timeType = UTZFMT_TIME_TYPE_UNKNOWN;
}
switch (style) {
case UTZFMT_STYLE_LOCATION:
formatGeneric(tz, UTZGNM_LOCATION, date, name);
break;
case UTZFMT_STYLE_GENERIC_LONG:
formatGeneric(tz, UTZGNM_LONG, date, name);
break;
case UTZFMT_STYLE_GENERIC_SHORT:
formatGeneric(tz, UTZGNM_SHORT, date, name);
break;
case UTZFMT_STYLE_SPECIFIC_LONG:
formatSpecific(tz, UTZNM_LONG_STANDARD, UTZNM_LONG_DAYLIGHT, date, name, timeType);
break;
case UTZFMT_STYLE_SPECIFIC_SHORT:
formatSpecific(tz, UTZNM_SHORT_STANDARD, UTZNM_SHORT_DAYLIGHT, date, name, timeType);
break;
case UTZFMT_STYLE_SPECIFIC_SHORT_COMMONLY_USED:
formatSpecific(tz, UTZNM_SHORT_STANDARD_COMMONLY_USED, UTZNM_SHORT_DAYLIGHT_COMMONLY_USED, date, name, timeType);
break;
}
return name;
}
UnicodeString&
TimeZoneFormatImpl::parse(UTimeZoneFormatStyle style, const UnicodeString& text, ParsePosition& pos,
UnicodeString& tzID, UTimeZoneTimeType* timeType /* = NULL */) const {
if (timeType) {
*timeType = UTZFMT_TIME_TYPE_UNKNOWN;
}
tzID.setToBogus();
int32_t startIdx = pos.getIndex();
UBool isGeneric = FALSE;
uint32_t types = 0;
switch (style) {
case UTZFMT_STYLE_LOCATION:
isGeneric = TRUE;
types = UTZGNM_LOCATION;
break;
case UTZFMT_STYLE_GENERIC_LONG:
isGeneric = TRUE;
types = UTZGNM_LOCATION | UTZGNM_LONG;
break;
case UTZFMT_STYLE_GENERIC_SHORT:
isGeneric = TRUE;
types = UTZGNM_LOCATION | UTZGNM_SHORT;
break;
case UTZFMT_STYLE_SPECIFIC_LONG:
types = UTZNM_LONG_STANDARD | UTZNM_LONG_DAYLIGHT;
break;
case UTZFMT_STYLE_SPECIFIC_SHORT:
types = UTZNM_SHORT_STANDARD | UTZNM_SHORT_DAYLIGHT;
break;
case UTZFMT_STYLE_SPECIFIC_SHORT_COMMONLY_USED:
types = UTZNM_SHORT_STANDARD_COMMONLY_USED | UTZNM_SHORT_DAYLIGHT_COMMONLY_USED;
break;
}
UTimeZoneTimeType parsedTimeType = UTZFMT_TIME_TYPE_UNKNOWN;
UnicodeString parsedTzID;
UErrorCode status = U_ZERO_ERROR;
if (isGeneric) {
int32_t len = fTimeZoneGenericNames->findBestMatch(text, startIdx, types, parsedTzID, parsedTimeType, status);
if (U_FAILURE(status) || len == 0) {
pos.setErrorIndex(startIdx);
return tzID;
}
pos.setIndex(startIdx + len);
} else {
TimeZoneNameMatchInfo *matchInfo = fTimeZoneNames->find(text, startIdx, types, status);
if (U_FAILURE(status) || matchInfo == NULL) {
pos.setErrorIndex(startIdx);
return tzID;
}
int32_t bestLen = 0;
int32_t bestIdx = -1;
for (int32_t i = 0; i < matchInfo->size(); i++) {
int32_t matchLen = matchInfo->getMatchLength(i);
if (matchLen > bestLen) {
bestLen = matchLen;
bestIdx = i;
}
}
if (bestIdx >= 0) {
matchInfo->getTimeZoneID(bestIdx, parsedTzID);
if (parsedTzID.isEmpty()) {
UnicodeString mzID;
matchInfo->getMetaZoneID(bestIdx, mzID);
U_ASSERT(mzID.length() > 0);
fTimeZoneNames->getReferenceZoneID(mzID, fTargetRegion, parsedTzID);
}
UTimeZoneNameType nameType = matchInfo->getNameType(bestIdx);
switch (nameType) {
case UTZNM_LONG_STANDARD:
case UTZNM_SHORT_STANDARD:
case UTZNM_SHORT_STANDARD_COMMONLY_USED:
parsedTimeType = UTZFMT_TIME_TYPE_STANDARD;
break;
case UTZNM_LONG_DAYLIGHT:
case UTZNM_SHORT_DAYLIGHT:
case UTZNM_SHORT_DAYLIGHT_COMMONLY_USED:
parsedTimeType = UTZFMT_TIME_TYPE_DAYLIGHT;
break;
default:
parsedTimeType = UTZFMT_TIME_TYPE_UNKNOWN;
break;
}
pos.setIndex(startIdx + bestLen);
}
delete matchInfo;
}
if (timeType) {
*timeType = parsedTimeType;
}
tzID.setTo(parsedTzID);
return tzID;
}
UnicodeString&
TimeZoneFormatImpl::formatGeneric(const TimeZone& tz, UTimeZoneGenericNameType genType, UDate date, UnicodeString& name) const {
if (fTimeZoneGenericNames == NULL) {
name.setToBogus();
return name;
}
if (genType == UTZGNM_LOCATION) {
const UChar* canonicalID = ZoneMeta::getCanonicalCLDRID(tz);
if (canonicalID == NULL) {
name.setToBogus();
return name;
}
return fTimeZoneGenericNames->getGenericLocationName(UnicodeString(canonicalID), name);
}
return fTimeZoneGenericNames->getDisplayName(tz, genType, date, name);
}
UnicodeString&
TimeZoneFormatImpl::formatSpecific(const TimeZone& tz, UTimeZoneNameType stdType, UTimeZoneNameType dstType,
UDate date, UnicodeString& name, UTimeZoneTimeType *timeType) const {
if (fTimeZoneNames == NULL) {
name.setToBogus();
return name;
}
UErrorCode status = U_ZERO_ERROR;
UBool isDaylight = tz.inDaylightTime(date, status);
const UChar* canonicalID = ZoneMeta::getCanonicalCLDRID(tz);
if (U_FAILURE(status) || canonicalID == NULL) {
name.setToBogus();
return name;
}
if (isDaylight) {
fTimeZoneNames->getDisplayName(UnicodeString(canonicalID), dstType, date, name);
} else {
fTimeZoneNames->getDisplayName(UnicodeString(canonicalID), stdType, date, name);
}
if (timeType && !name.isEmpty()) {
*timeType = isDaylight ? UTZFMT_TIME_TYPE_DAYLIGHT : UTZFMT_TIME_TYPE_STANDARD;
}
return name;
}
// TimeZoneFormat object cache handling
static UMTX gTimeZoneFormatLock = NULL;
static UHashtable *gTimeZoneFormatCache = NULL;
static UBool gTimeZoneFormatCacheInitialized = FALSE;
// Access count - incremented every time up to SWEEP_INTERVAL,
// then reset to 0
static int32_t gAccessCount = 0;
// Interval for calling the cache sweep function - every 100 times
#define SWEEP_INTERVAL 100
// Cache expiration in millisecond. When a cached entry is no
// longer referenced and exceeding this threshold since last
// access time, then the cache entry will be deleted by the sweep
// function. For now, 3 minutes.
#define CACHE_EXPIRATION 180000.0
typedef struct TimeZoneFormatCacheEntry {
TimeZoneFormat* tzfmt;
int32_t refCount;
double lastAccess;
} TimeZoneNameFormatCacheEntry;
U_CDECL_BEGIN
/**
* Cleanup callback func
*/
static UBool U_CALLCONV timeZoneFormat_cleanup(void)
{
umtx_destroy(&gTimeZoneFormatLock);
if (gTimeZoneFormatCache != NULL) {
uhash_close(gTimeZoneFormatCache);
gTimeZoneFormatCache = NULL;
}
gTimeZoneFormatCacheInitialized = FALSE;
return TRUE;
}
/**
* Deleter for TimeZoneNamesCacheEntry
*/
static void U_CALLCONV
deleteTimeZoneFormatCacheEntry(void *obj) {
TimeZoneNameFormatCacheEntry *entry = (TimeZoneNameFormatCacheEntry *)obj;
delete (TimeZoneFormat *) entry->tzfmt;
uprv_free((void *)entry);
}
U_CDECL_END
/**
* Function used for removing unreferrenced cache entries exceeding
* the expiration time. This function must be called with in the mutex
* block.
*/
static void sweepCache() {
int32_t pos = -1;
const UHashElement* elem;
double now = (double)uprv_getUTCtime();
while ((elem = uhash_nextElement(gTimeZoneFormatCache, &pos))) {
TimeZoneFormatCacheEntry *entry = (TimeZoneFormatCacheEntry *)elem->value.pointer;
if (entry->refCount <= 0 && (now - entry->lastAccess) > CACHE_EXPIRATION) {
// delete this entry
uhash_removeElement(gTimeZoneFormatCache, elem);
}
}
}
// ---------------------------------------------------
// TimeZoneFormatDelegate
// This class wraps a TimeZoneFormatImpl singleton
// per locale and maintain the reference count.
// ---------------------------------------------------
class TimeZoneFormatDelegate : public TimeZoneFormat {
public:
TimeZoneFormatDelegate(const Locale& locale, UErrorCode& status);
virtual ~TimeZoneFormatDelegate();
const TimeZoneNames* getTimeZoneNames() const;
UnicodeString& format(UTimeZoneFormatStyle style, const TimeZone& tz, UDate date,
UnicodeString& name, UTimeZoneTimeType* timeType = NULL) const;
UnicodeString& parse(UTimeZoneFormatStyle style, const UnicodeString& text, ParsePosition& pos,
UnicodeString& tzID, UTimeZoneTimeType* timeType = NULL) const;
private:
TimeZoneFormatCacheEntry* fTZfmtCacheEntry;
};
TimeZoneFormatDelegate::TimeZoneFormatDelegate(const Locale& locale, UErrorCode& status) {
UBool initialized;
UMTX_CHECK(&gTimeZoneFormatLock, gTimeZoneFormatCacheInitialized, initialized);
if (!initialized) {
// Create empty hashtable
umtx_lock(&gTimeZoneFormatLock);
{
if (!gTimeZoneFormatCacheInitialized) {
gTimeZoneFormatCache = uhash_open(uhash_hashChars, uhash_compareChars, NULL, &status);
if (U_SUCCESS(status)) {
uhash_setKeyDeleter(gTimeZoneFormatCache, uhash_freeBlock);
uhash_setValueDeleter(gTimeZoneFormatCache, deleteTimeZoneFormatCacheEntry);
gTimeZoneFormatCacheInitialized = TRUE;
ucln_i18n_registerCleanup(UCLN_I18N_TIMEZONEFORMAT, timeZoneFormat_cleanup);
}
}
}
umtx_unlock(&gTimeZoneFormatLock);
}
// Check the cache, if not available, create new one and cache
TimeZoneFormatCacheEntry *cacheEntry = NULL;
umtx_lock(&gTimeZoneFormatLock);
{
const char *key = locale.getName();
cacheEntry = (TimeZoneFormatCacheEntry *)uhash_get(gTimeZoneFormatCache, key);
if (cacheEntry == NULL) {
TimeZoneFormat *tzfmt = NULL;
char *newKey = NULL;
tzfmt = new TimeZoneFormatImpl(locale, status);
if (tzfmt == NULL) {
status = U_MEMORY_ALLOCATION_ERROR;
}
if (U_SUCCESS(status)) {
newKey = (char *)uprv_malloc(uprv_strlen(key) + 1);
if (newKey == NULL) {
status = U_MEMORY_ALLOCATION_ERROR;
} else {
uprv_strcpy(newKey, key);
}
}
if (U_SUCCESS(status)) {
cacheEntry = (TimeZoneFormatCacheEntry *)uprv_malloc(sizeof(TimeZoneFormatCacheEntry));
if (cacheEntry == NULL) {
status = U_MEMORY_ALLOCATION_ERROR;
} else {
cacheEntry->tzfmt = tzfmt;
cacheEntry->refCount = 1;
cacheEntry->lastAccess = (double)uprv_getUTCtime();
uhash_put(gTimeZoneFormatCache, newKey, cacheEntry, &status);
}
}
if (U_FAILURE(status)) {
if (tzfmt != NULL) {
delete tzfmt;
}
if (newKey != NULL) {
uprv_free(newKey);
}
if (cacheEntry != NULL) {
uprv_free(cacheEntry);
}
return;
}
} else {
// Update the reference count
cacheEntry->refCount++;
cacheEntry->lastAccess = (double)uprv_getUTCtime();
}
gAccessCount++;
if (gAccessCount >= SWEEP_INTERVAL) {
// sweep
sweepCache();
gAccessCount = 0;
}
}
umtx_unlock(&gTimeZoneFormatLock);
fTZfmtCacheEntry = cacheEntry;
}
TimeZoneFormatDelegate::~TimeZoneFormatDelegate() {
umtx_lock(&gTimeZoneFormatLock);
{
U_ASSERT(fTZfmtCacheEntry->refCount > 0);
// Just decrement the reference count
fTZfmtCacheEntry->refCount--;
}
umtx_unlock(&gTimeZoneFormatLock);
}
const TimeZoneNames*
TimeZoneFormatDelegate::getTimeZoneNames() const {
return fTZfmtCacheEntry->tzfmt->getTimeZoneNames();
}
UnicodeString&
TimeZoneFormatDelegate::format(UTimeZoneFormatStyle style, const TimeZone& tz, UDate date,
UnicodeString& name, UTimeZoneTimeType* timeType /* = NULL */) const {
return fTZfmtCacheEntry->tzfmt->format(style, tz, date, name, timeType);
}
UnicodeString&
TimeZoneFormatDelegate::parse(UTimeZoneFormatStyle style, const UnicodeString& text, ParsePosition& pos,
UnicodeString& tzID, UTimeZoneTimeType* timeType /* = NULL */) const {
return fTZfmtCacheEntry->tzfmt->parse(style, text, pos, tzID, timeType);
}
// ---------------------------------------------------
// TimeZoneFormat base class
// ---------------------------------------------------
TimeZoneFormat::~TimeZoneFormat() {
}
TimeZone*
TimeZoneFormat::parse(UTimeZoneFormatStyle style, const UnicodeString& text, ParsePosition& pos,
UTimeZoneTimeType* timeType /*= NULL*/) const {
UnicodeString tzID;
parse(style, text, pos, tzID, timeType);
if (pos.getErrorIndex() < 0) {
return TimeZone::createTimeZone(tzID);
}
return NULL;
}
TimeZoneFormat* U_EXPORT2
TimeZoneFormat::createInstance(const Locale& locale, UErrorCode& status) {
TimeZoneFormat* tzfmt = new TimeZoneFormatDelegate(locale, status);
if (U_SUCCESS(status) && tzfmt == NULL) {
status = U_MEMORY_ALLOCATION_ERROR;
}
return tzfmt;
}
U_NAMESPACE_END
#endif

65
icu4c/source/i18n/tzfmt.h Normal file
View file

@ -0,0 +1,65 @@
/*
*******************************************************************************
* Copyright (C) 2011, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*/
#ifndef __TZFMT_H
#define __TZFMT_H
#include "unicode/utypes.h"
#if !UCONFIG_NO_FORMATTING
#include "unicode/uobject.h"
#include "unicode/uloc.h"
#include "unicode/unistr.h"
#include "unicode/format.h"
#include "unicode/timezone.h"
#include "tznames.h"
U_CDECL_BEGIN
typedef enum UTimeZoneFormatStyle {
UTZFMT_STYLE_LOCATION,
UTZFMT_STYLE_GENERIC_LONG,
UTZFMT_STYLE_GENERIC_SHORT,
UTZFMT_STYLE_SPECIFIC_LONG,
UTZFMT_STYLE_SPECIFIC_SHORT,
UTZFMT_STYLE_SPECIFIC_SHORT_COMMONLY_USED
} UTimeZoneFormatStyle;
typedef enum UTimeZoneTimeType {
UTZFMT_TIME_TYPE_UNKNOWN,
UTZFMT_TIME_TYPE_STANDARD,
UTZFMT_TIME_TYPE_DAYLIGHT
} UTimeZoneTimeType;
U_CDECL_END
U_NAMESPACE_BEGIN
class TimeZoneNames;
class U_I18N_API TimeZoneFormat : public UMemory {
public:
virtual ~TimeZoneFormat();
static TimeZoneFormat* U_EXPORT2 createInstance(const Locale& locale, UErrorCode& status);
virtual const TimeZoneNames* getTimeZoneNames() const = 0;
virtual UnicodeString& format(UTimeZoneFormatStyle style, const TimeZone& tz, UDate date,
UnicodeString& name, UTimeZoneTimeType* timeType = NULL) const = 0;
virtual UnicodeString& parse(UTimeZoneFormatStyle style, const UnicodeString& text, ParsePosition& pos,
UnicodeString& tzID, UTimeZoneTimeType* timeType = NULL) const = 0;
TimeZone* parse(UTimeZoneFormatStyle style, const UnicodeString& text, ParsePosition& pos,
UTimeZoneTimeType* timeType = NULL) const;
};
U_NAMESPACE_END
#endif
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,115 @@
/*
*******************************************************************************
* Copyright (C) 2011, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*/
#ifndef __TZGNAMES_H
#define __TZGNAMES_H
/**
* \file
* \brief C API: Time zone generic names classe
*/
#include "unicode/utypes.h"
#if !UCONFIG_NO_FORMATTING
#include "unicode/locid.h"
#include "unicode/timezone.h"
#include "unicode/unistr.h"
#include "tznames.h"
#include "tznames_impl.h"
#include "tzfmt.h"
#include "uhash.h"
#include "umutex.h"
U_CDECL_BEGIN
typedef enum UTimeZoneGenericNameType {
UTZGNM_UNKNOWN = 0x00,
UTZGNM_LOCATION = 0x01,
UTZGNM_LONG = 0x02,
UTZGNM_SHORT = 0x04
} UTimeZoneGenericNameType;
U_CDECL_END
U_NAMESPACE_BEGIN
class LocaleDisplayNames;
class MessageFormat;
class TimeZone;
class TimeZoneGenericNameMatchInfo : public UMemory {
public:
TimeZoneGenericNameMatchInfo(UVector* matches);
~TimeZoneGenericNameMatchInfo();
int32_t size() const;
UTimeZoneGenericNameType getGenericNameType(int32_t index) const;
int32_t getMatchLength(int32_t index) const;
UnicodeString& getTimeZoneID(int32_t index, UnicodeString& tzID) const;
private:
UVector* fMatches; // vector of MatchEntry
};
class U_I18N_API TimeZoneGenericNames : public UMemory {
public:
TimeZoneGenericNames(const Locale& locale, UErrorCode& status);
virtual ~TimeZoneGenericNames();
UnicodeString& getDisplayName(const TimeZone& tz, UTimeZoneGenericNameType type,
UDate date, UnicodeString& name) const;
UnicodeString& getGenericLocationName(const UnicodeString& tzCanonicalID, UnicodeString& name) const;
int32_t findBestMatch(const UnicodeString& text, int32_t start, uint32_t types,
UnicodeString& tzID, UTimeZoneTimeType& timeType, UErrorCode& status) const;
private:
Locale fLocale;
UMTX fLock;
const TimeZoneNames* fTimeZoneNames;
UHashtable* fLocationNamesMap;
UHashtable* fPartialLocationNamesMap;
MessageFormat* fRegionFormat;
MessageFormat* fFallbackRegionFormat;
MessageFormat* fFallbackFormat;
LocaleDisplayNames* fLocaleDisplayNames;
ZNStringPool fStringPool;
TextTrieMap fGNamesTrie;
UBool fGNamesTrieFullyLoaded;
char fTargetRegion[ULOC_COUNTRY_CAPACITY];
void initialize(const Locale& locale, UErrorCode& status);
void cleanup();
void loadStrings(const UnicodeString& tzCanonicalID);
const UChar* getGenericLocationName(const UnicodeString& tzCanonicalID);
UnicodeString& formatGenericNonLocationName(const TimeZone& tz, UTimeZoneGenericNameType type,
UDate date, UnicodeString& name) const;
UnicodeString& getPartialLocationName(const UnicodeString& tzCanonicalID,
const UnicodeString& mzID, UBool isLong, const UnicodeString& mzDisplayName,
UnicodeString& name) const;
const UChar* getPartialLocationName(const UnicodeString& tzCanonicalID,
const UnicodeString& mzID, UBool isLong, const UnicodeString& mzDisplayName);
TimeZoneGenericNameMatchInfo* findLocal(const UnicodeString& text, int32_t start, uint32_t types, UErrorCode& status) const;
TimeZoneNameMatchInfo* findTimeZoneNames(const UnicodeString& text, int32_t start, uint32_t types, UErrorCode& status) const;
};
U_NAMESPACE_END
#endif
#endif

View file

@ -0,0 +1,299 @@
/*
*******************************************************************************
* Copyright (C) 2011, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*/
#include "unicode/utypes.h"
#if !UCONFIG_NO_FORMATTING
#include "tznames.h"
#include "tznames_impl.h"
#include "unicode/locid.h"
#include "unicode/uenum.h"
#include "cmemory.h"
#include "cstring.h"
#include "putilimp.h"
#include "uassert.h"
#include "ucln_in.h"
#include "uhash.h"
#include "umutex.h"
U_NAMESPACE_BEGIN
static const UChar gEtcPrefix[] = { 0x45, 0x74, 0x63, 0x2F }; // "Etc/"
static const int32_t gEtcPrefixLen = 4;
static const UChar gSystemVPrefix[] = { 0x53, 0x79, 0x73, 0x74, 0x65, 0x6D, 0x56, 0x2F }; // "SystemV/
static const int32_t gSystemVPrefixLen = 8;
static const UChar gRiyadh8[] = { 0x52, 0x69, 0x79, 0x61, 0x64, 0x68, 0x38 }; // "Riyadh8"
static const int32_t gRiyadh8Len = 7;
// TimeZoneNames object cache handling
static UMTX gTimeZoneNamesLock = NULL;
static UHashtable *gTimeZoneNamesCache = NULL;
static UBool gTimeZoneNamesCacheInitialized = FALSE;
// Access count - incremented every time up to SWEEP_INTERVAL,
// then reset to 0
static int32_t gAccessCount = 0;
// Interval for calling the cache sweep function - every 100 times
#define SWEEP_INTERVAL 100
// Cache expiration in millisecond. When a cached entry is no
// longer referenced and exceeding this threshold since last
// access time, then the cache entry will be deleted by the sweep
// function. For now, 3 minutes.
#define CACHE_EXPIRATION 180000.0
typedef struct TimeZoneNamesCacheEntry {
TimeZoneNames* names;
int32_t refCount;
double lastAccess;
} TimeZoneNamesCacheEntry;
U_CDECL_BEGIN
/**
* Cleanup callback func
*/
static UBool U_CALLCONV timeZoneNames_cleanup(void)
{
umtx_destroy(&gTimeZoneNamesLock);
if (gTimeZoneNamesCache != NULL) {
uhash_close(gTimeZoneNamesCache);
gTimeZoneNamesCache = NULL;
}
gTimeZoneNamesCacheInitialized = FALSE;
return TRUE;
}
/**
* Deleter for TimeZoneNamesCacheEntry
*/
static void U_CALLCONV
deleteTimeZoneNamesCacheEntry(void *obj) {
U_NAMESPACE_QUALIFIER TimeZoneNamesCacheEntry *entry = (U_NAMESPACE_QUALIFIER TimeZoneNamesCacheEntry*)obj;
delete (U_NAMESPACE_QUALIFIER TimeZoneNamesImpl*) entry->names;
uprv_free(entry);
}
U_CDECL_END
/**
* Function used for removing unreferrenced cache entries exceeding
* the expiration time. This function must be called with in the mutex
* block.
*/
static void sweepCache() {
int32_t pos = -1;
const UHashElement* elem;
double now = (double)uprv_getUTCtime();
while ((elem = uhash_nextElement(gTimeZoneNamesCache, &pos))) {
TimeZoneNamesCacheEntry *entry = (TimeZoneNamesCacheEntry *)elem->value.pointer;
if (entry->refCount <= 0 && (now - entry->lastAccess) > CACHE_EXPIRATION) {
// delete this entry
uhash_removeElement(gTimeZoneNamesCache, elem);
}
}
}
class TimeZoneNamesDelegate : public TimeZoneNames {
public:
TimeZoneNamesDelegate(const Locale& locale, UErrorCode& status);
virtual ~TimeZoneNamesDelegate();
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:
TimeZoneNamesCacheEntry* fTZnamesCacheEntry;
};
TimeZoneNamesDelegate::TimeZoneNamesDelegate(const Locale& locale, UErrorCode& status) {
UBool initialized;
UMTX_CHECK(&gTimeZoneNamesLock, gTimeZoneNamesCacheInitialized, initialized);
if (!initialized) {
// Create empty hashtable
umtx_lock(&gTimeZoneNamesLock);
{
if (!gTimeZoneNamesCacheInitialized) {
gTimeZoneNamesCache = uhash_open(uhash_hashChars, uhash_compareChars, NULL, &status);
if (U_SUCCESS(status)) {
uhash_setKeyDeleter(gTimeZoneNamesCache, uhash_freeBlock);
uhash_setValueDeleter(gTimeZoneNamesCache, deleteTimeZoneNamesCacheEntry);
gTimeZoneNamesCacheInitialized = TRUE;
ucln_i18n_registerCleanup(UCLN_I18N_TIMEZONENAMES, timeZoneNames_cleanup);
}
}
}
umtx_unlock(&gTimeZoneNamesLock);
if (U_FAILURE(status)) {
return;
}
}
// Check the cache, if not available, create new one and cache
TimeZoneNamesCacheEntry *cacheEntry = NULL;
umtx_lock(&gTimeZoneNamesLock);
{
const char *key = locale.getName();
cacheEntry = (TimeZoneNamesCacheEntry *)uhash_get(gTimeZoneNamesCache, key);
if (cacheEntry == NULL) {
TimeZoneNames *tznames = NULL;
char *newKey = NULL;
tznames = new TimeZoneNamesImpl(locale, status);
if (tznames == NULL) {
status = U_MEMORY_ALLOCATION_ERROR;
}
if (U_SUCCESS(status)) {
newKey = (char *)uprv_malloc(uprv_strlen(key) + 1);
if (newKey == NULL) {
status = U_MEMORY_ALLOCATION_ERROR;
} else {
uprv_strcpy(newKey, key);
}
}
if (U_SUCCESS(status)) {
cacheEntry = (TimeZoneNamesCacheEntry *)uprv_malloc(sizeof(TimeZoneNamesCacheEntry));
if (cacheEntry == NULL) {
status = U_MEMORY_ALLOCATION_ERROR;
} else {
cacheEntry->names = tznames;
cacheEntry->refCount = 1;
cacheEntry->lastAccess = (double)uprv_getUTCtime();
uhash_put(gTimeZoneNamesCache, newKey, cacheEntry, &status);
}
}
if (U_FAILURE(status)) {
if (tznames != NULL) {
delete tznames;
}
if (newKey != NULL) {
uprv_free(newKey);
}
if (cacheEntry != NULL) {
uprv_free(cacheEntry);
}
cacheEntry = NULL;
}
} else {
// Update the reference count
cacheEntry->refCount++;
cacheEntry->lastAccess = (double)uprv_getUTCtime();
}
gAccessCount++;
if (gAccessCount >= SWEEP_INTERVAL) {
// sweep
sweepCache();
gAccessCount = 0;
}
}
umtx_unlock(&gTimeZoneNamesLock);
fTZnamesCacheEntry = cacheEntry;
}
TimeZoneNamesDelegate::~TimeZoneNamesDelegate() {
umtx_lock(&gTimeZoneNamesLock);
{
U_ASSERT(fTZnamesCacheEntry->refCount > 0);
// Just decrement the reference count
fTZnamesCacheEntry->refCount--;
}
umtx_unlock(&gTimeZoneNamesLock);
}
StringEnumeration*
TimeZoneNamesDelegate::getAvailableMetaZoneIDs(UErrorCode& status) const {
return fTZnamesCacheEntry->names->getAvailableMetaZoneIDs(status);
}
StringEnumeration*
TimeZoneNamesDelegate::getAvailableMetaZoneIDs(const UnicodeString& tzID, UErrorCode& status) const {
return fTZnamesCacheEntry->names->getAvailableMetaZoneIDs(tzID, status);
}
UnicodeString&
TimeZoneNamesDelegate::getMetaZoneID(const UnicodeString& tzID, UDate date, UnicodeString& mzID) const {
return fTZnamesCacheEntry->names->getMetaZoneID(tzID, date, mzID);
}
UnicodeString&
TimeZoneNamesDelegate::getReferenceZoneID(const UnicodeString& mzID, const char* region, UnicodeString& tzID) const {
return fTZnamesCacheEntry->names->getReferenceZoneID(mzID, region, tzID);
}
UnicodeString&
TimeZoneNamesDelegate::getMetaZoneDisplayName(const UnicodeString& mzID, UTimeZoneNameType type, UnicodeString& name) const {
return fTZnamesCacheEntry->names->getMetaZoneDisplayName(mzID, type, name);
}
UnicodeString&
TimeZoneNamesDelegate::getTimeZoneDisplayName(const UnicodeString& tzID, UTimeZoneNameType type, UnicodeString& name) const {
return fTZnamesCacheEntry->names->getTimeZoneDisplayName(tzID, type, name);
}
UnicodeString&
TimeZoneNamesDelegate::getExemplarLocationName(const UnicodeString& tzID, UnicodeString& name) const {
return fTZnamesCacheEntry->names->getExemplarLocationName(tzID, name);
}
TimeZoneNameMatchInfo*
TimeZoneNamesDelegate::find(const UnicodeString& text, int32_t start, uint32_t types, UErrorCode& status) const {
return fTZnamesCacheEntry->names->find(text, start, types, status);
}
TimeZoneNames*
TimeZoneNames::createInstance(const Locale& locale, UErrorCode& status) {
return new TimeZoneNamesDelegate(locale, status);
}
UnicodeString&
TimeZoneNames::getExemplarLocationName(const UnicodeString& tzID, UnicodeString& name) const {
if (tzID.isEmpty() || tzID.startsWith(gEtcPrefix, gEtcPrefixLen)
|| tzID.startsWith(gSystemVPrefix, gSystemVPrefixLen) || tzID.indexOf(gRiyadh8, gRiyadh8Len, 0) > 0) {
name.setToBogus();
return name;
}
int32_t sep = tzID.lastIndexOf((UChar)0x2F /* '/' */);
if (sep > 0 && sep + 1 < tzID.length()) {
name.setTo(tzID, sep + 1);
name.findAndReplace("_", " ");
} else {
name.setToBogus();
}
return name;
}
UnicodeString&
TimeZoneNames::getDisplayName(const UnicodeString& tzID, UTimeZoneNameType type, UDate date, UnicodeString& name) const {
getTimeZoneDisplayName(tzID, type, name);
if (name.isEmpty()) {
UnicodeString mzID;
getMetaZoneID(tzID, date, mzID);
getMetaZoneDisplayName(mzID, type, name);
}
return name;
}
U_NAMESPACE_END
#endif

View file

@ -0,0 +1,81 @@
/*
*******************************************************************************
* Copyright (C) 2011, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*/
#ifndef __TZNAMES_H
#define __TZNAMES_H
/**
* \file
* \brief C API: Time zone names class
*/
#include "unicode/utypes.h"
#if !UCONFIG_NO_FORMATTING
#include "unicode/uloc.h"
#include "unicode/unistr.h"
U_CDECL_BEGIN
typedef enum UTimeZoneNameType {
UTZNM_UNKNOWN = 0x00,
UTZNM_LONG_GENERIC = 0x01,
UTZNM_LONG_STANDARD = 0x02,
UTZNM_LONG_DAYLIGHT = 0x04,
UTZNM_SHORT_GENERIC = 0x08,
UTZNM_SHORT_STANDARD = 0x10,
UTZNM_SHORT_DAYLIGHT = 0x20,
UTZNM_SHORT_STANDARD_COMMONLY_USED = 0x40,
UTZNM_SHORT_DAYLIGHT_COMMONLY_USED = 0x80
} UTimeZoneNameType;
U_CDECL_END
U_NAMESPACE_BEGIN
class U_I18N_API TimeZoneNameMatchInfo : public UMemory {
public:
virtual ~TimeZoneNameMatchInfo();
virtual int32_t size() const = 0;
virtual UTimeZoneNameType getNameType(int32_t index) const = 0;
virtual int32_t getMatchLength(int32_t index) const = 0;
virtual UnicodeString& getTimeZoneID(int32_t index, UnicodeString& tzID) const = 0;
virtual UnicodeString& getMetaZoneID(int32_t index, UnicodeString& mzID) const = 0;
};
inline
TimeZoneNameMatchInfo::~TimeZoneNameMatchInfo() {
}
class U_I18N_API TimeZoneNames : public UMemory {
public:
virtual ~TimeZoneNames();
static TimeZoneNames* U_EXPORT2 createInstance(const Locale& locale, UErrorCode& status);
virtual StringEnumeration* getAvailableMetaZoneIDs(UErrorCode& status) const = 0;
virtual StringEnumeration* getAvailableMetaZoneIDs(const UnicodeString& tzID, UErrorCode& status) const = 0;
virtual UnicodeString& getMetaZoneID(const UnicodeString& tzID, UDate date, UnicodeString& mzID) const = 0;
virtual UnicodeString& getReferenceZoneID(const UnicodeString& mzID, const char* region, UnicodeString& tzID) const = 0;
virtual UnicodeString& getMetaZoneDisplayName(const UnicodeString& mzID, UTimeZoneNameType type, UnicodeString& name) const = 0;
virtual UnicodeString& getTimeZoneDisplayName(const UnicodeString& tzID, UTimeZoneNameType type, UnicodeString& name) const = 0;
virtual UnicodeString& getExemplarLocationName(const UnicodeString& tzID, UnicodeString& name) const;
virtual UnicodeString& getDisplayName(const UnicodeString& tzID, UTimeZoneNameType type, UDate date, UnicodeString& name) const;
virtual TimeZoneNameMatchInfo* find(const UnicodeString& text, int32_t start, uint32_t types, UErrorCode& status) const = 0;
};
inline
TimeZoneNames::~TimeZoneNames() {
}
U_NAMESPACE_END
#endif
#endif

File diff suppressed because it is too large Load diff

View file

@ -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
//

View file

@ -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,

View file

@ -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.
* <p><b>Note:<b> 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
*/

View file

@ -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

View file

@ -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

View file

@ -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<const OlsonTimeZone *>(&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 */

View file

@ -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

File diff suppressed because it is too large Load diff

View file

@ -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 &region) 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

View file

@ -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

View file

@ -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" },

View file

@ -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(""),
};

View file

@ -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);

View file

@ -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, ""}
};