mirror of
https://github.com/unicode-org/icu.git
synced 2025-04-06 22:15:31 +00:00
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:
parent
607f78619b
commit
4d7569c743
30 changed files with 4558 additions and 3088 deletions
|
@ -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
|
||||
|
|
|
@ -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. *
|
||||
*******************************************************************************
|
||||
*
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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">
|
||||
|
|
|
@ -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">
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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(¶m, 1, appendTo, fpos, status);
|
||||
}
|
||||
Formattable param(offset, Formattable::kIsDate);
|
||||
FieldPosition fpos(0);
|
||||
fGMTFormatters[type]->format(¶m, 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 */
|
||||
|
|
|
@ -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
502
icu4c/source/i18n/tzfmt.cpp
Normal 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
65
icu4c/source/i18n/tzfmt.h
Normal 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
|
1053
icu4c/source/i18n/tzgnames.cpp
Normal file
1053
icu4c/source/i18n/tzgnames.cpp
Normal file
File diff suppressed because it is too large
Load diff
115
icu4c/source/i18n/tzgnames.h
Normal file
115
icu4c/source/i18n/tzgnames.h
Normal 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
|
299
icu4c/source/i18n/tznames.cpp
Normal file
299
icu4c/source/i18n/tznames.cpp
Normal 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
|
81
icu4c/source/i18n/tznames.h
Normal file
81
icu4c/source/i18n/tznames.h
Normal 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
|
1451
icu4c/source/i18n/tznames_impl.cpp
Normal file
1451
icu4c/source/i18n/tznames_impl.cpp
Normal file
File diff suppressed because it is too large
Load diff
212
icu4c/source/i18n/tznames_impl.h
Normal file
212
icu4c/source/i18n/tznames_impl.h
Normal 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
|
||||
//
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
*/
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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
|
@ -1,526 +0,0 @@
|
|||
/*
|
||||
*******************************************************************************
|
||||
* Copyright (C) 2007-2011, International Business Machines Corporation and *
|
||||
* others. All Rights Reserved. *
|
||||
*******************************************************************************
|
||||
*/
|
||||
#ifndef ZSTRFMT_H
|
||||
#define ZSTRFMT_H
|
||||
|
||||
#include "unicode/utypes.h"
|
||||
|
||||
#if !UCONFIG_NO_FORMATTING
|
||||
|
||||
#include "unicode/unistr.h"
|
||||
#include "unicode/calendar.h"
|
||||
#include "uhash.h"
|
||||
#include "uvector.h"
|
||||
|
||||
U_NAMESPACE_BEGIN
|
||||
|
||||
/*
|
||||
* Character node used by TextTrieMap
|
||||
*/
|
||||
struct CharacterNode {
|
||||
// No constructor or destructor.
|
||||
// We malloc and free an uninitalized array of CharacterNode objects
|
||||
// and clear and delete them ourselves.
|
||||
|
||||
void clear();
|
||||
void deleteValues();
|
||||
|
||||
void addValue(void *value, UErrorCode &status);
|
||||
inline UBool hasValues() const;
|
||||
inline int32_t countValues() const;
|
||||
inline const void *getValue(int32_t index) const;
|
||||
|
||||
void *fValues; // Union of one single value vs. UVector of values.
|
||||
UChar fCharacter; // UTF-16 code unit.
|
||||
uint16_t fFirstChild; // 0 if no children.
|
||||
uint16_t fNextSibling; // 0 terminates the list.
|
||||
UBool fHasValuesVector;
|
||||
UBool fPadding;
|
||||
|
||||
// No value: fValues == NULL and fHasValuesVector == FALSE
|
||||
// One value: fValues == value and fHasValuesVector == FALSE
|
||||
// >=2 values: fValues == UVector of values and fHasValuesVector == TRUE
|
||||
};
|
||||
|
||||
inline UBool CharacterNode::hasValues() const {
|
||||
return (UBool)(fValues != NULL);
|
||||
}
|
||||
|
||||
inline int32_t CharacterNode::countValues() const {
|
||||
return
|
||||
fValues == NULL ? 0 :
|
||||
!fHasValuesVector ? 1 :
|
||||
((const UVector *)fValues)->size();
|
||||
}
|
||||
|
||||
inline const void *CharacterNode::getValue(int32_t index) const {
|
||||
if (!fHasValuesVector) {
|
||||
return fValues; // Assume index == 0.
|
||||
} else {
|
||||
return ((const UVector *)fValues)->elementAt(index);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Search result handler callback interface used by TextTrieMap search.
|
||||
*/
|
||||
class TextTrieMapSearchResultHandler : public UMemory {
|
||||
public:
|
||||
virtual UBool handleMatch(int32_t matchLength,
|
||||
const CharacterNode *node, UErrorCode& status) = 0;
|
||||
virtual ~TextTrieMapSearchResultHandler(); //added to avoid warning
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* ZSFStringPool Pool of (UChar *) strings. Provides for sharing of repeated
|
||||
* strings within ZoneStringFormats.
|
||||
*/
|
||||
struct ZSFStringPoolChunk;
|
||||
class ZSFStringPool: public UMemory {
|
||||
public:
|
||||
ZSFStringPool(UErrorCode &status);
|
||||
~ZSFStringPool();
|
||||
|
||||
/* Get the pooled string that is equal to the supplied string s.
|
||||
* Copy the string into the pool if it is not already present.
|
||||
*
|
||||
* Life time of the returned string is that of the pool.
|
||||
*/
|
||||
const UChar *get(const UChar *s, UErrorCode &status);
|
||||
|
||||
/* Get the pooled string that is equal to the supplied string s.
|
||||
* Copy the string into the pool if it is not already present.
|
||||
*/
|
||||
const UChar *get(const UnicodeString &s, UErrorCode &status);
|
||||
|
||||
/* Adopt a string into the pool, without copying it.
|
||||
* Used for strings from resource bundles, which will persist without copying.
|
||||
*/
|
||||
const UChar *adopt(const UChar *s, UErrorCode &status);
|
||||
|
||||
/* Freeze the string pool. Discards the hash table that is used
|
||||
* for looking up a string. All pointers to pooled strings remain valid.
|
||||
*/
|
||||
void freeze();
|
||||
|
||||
private:
|
||||
ZSFStringPoolChunk *fChunks;
|
||||
UHashtable *fHash;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* TextTrieMap is a trie implementation for supporting
|
||||
* fast prefix match for the string key.
|
||||
*/
|
||||
class TextTrieMap : public UMemory {
|
||||
public:
|
||||
TextTrieMap(UBool ignoreCase);
|
||||
virtual ~TextTrieMap();
|
||||
|
||||
void put(const UnicodeString &key, void *value, ZSFStringPool &sp, UErrorCode &status);
|
||||
void search(const UnicodeString &text, int32_t start,
|
||||
TextTrieMapSearchResultHandler *handler, UErrorCode& status) const;
|
||||
int32_t isEmpty() const;
|
||||
|
||||
private:
|
||||
UBool fIgnoreCase;
|
||||
CharacterNode *fNodes;
|
||||
int32_t fNodesCapacity;
|
||||
int32_t fNodesCount;
|
||||
|
||||
UVector *fLazyContents;
|
||||
UBool fIsEmpty;
|
||||
|
||||
UBool growNodes();
|
||||
CharacterNode* addChildNode(CharacterNode *parent, UChar c, UErrorCode &status);
|
||||
CharacterNode* getChildNode(CharacterNode *parent, UChar c) const;
|
||||
|
||||
void putImpl(const UnicodeString &key, void *value, UErrorCode &status);
|
||||
void buildTrie(UErrorCode &status);
|
||||
void search(CharacterNode *node, const UnicodeString &text, int32_t start,
|
||||
int32_t index, TextTrieMapSearchResultHandler *handler, UErrorCode &status) const;
|
||||
};
|
||||
|
||||
|
||||
// Name types, these bit flag are used for zone string lookup
|
||||
enum TimeZoneTranslationType {
|
||||
LOCATION = 0x0001,
|
||||
GENERIC_LONG = 0x0002,
|
||||
GENERIC_SHORT = 0x0004,
|
||||
STANDARD_LONG = 0x0008,
|
||||
STANDARD_SHORT = 0x0010,
|
||||
DAYLIGHT_LONG = 0x0020,
|
||||
DAYLIGHT_SHORT = 0x0040
|
||||
};
|
||||
|
||||
// Name type index, these constants are used for index in the zone strings array.
|
||||
enum TimeZoneTranslationTypeIndex {
|
||||
ZSIDX_LOCATION = 0,
|
||||
ZSIDX_LONG_STANDARD,
|
||||
ZSIDX_SHORT_STANDARD,
|
||||
ZSIDX_LONG_DAYLIGHT,
|
||||
ZSIDX_SHORT_DAYLIGHT,
|
||||
ZSIDX_LONG_GENERIC,
|
||||
ZSIDX_SHORT_GENERIC,
|
||||
|
||||
ZSIDX_COUNT
|
||||
};
|
||||
|
||||
class MessageFormat;
|
||||
|
||||
|
||||
/*
|
||||
* ZoneStringInfo is a class holding a localized zone string
|
||||
* information.
|
||||
*/
|
||||
class ZoneStringInfo : public UMemory {
|
||||
public:
|
||||
virtual ~ZoneStringInfo();
|
||||
|
||||
inline UnicodeString& getID(UnicodeString &result) const;
|
||||
inline UnicodeString& getString(UnicodeString &result) const;
|
||||
inline UBool isStandard(void) const;
|
||||
inline UBool isDaylight(void) const;
|
||||
inline UBool isGeneric(void) const;
|
||||
|
||||
private:
|
||||
friend class ZoneStringFormat;
|
||||
friend class ZoneStringSearchResultHandler;
|
||||
|
||||
ZoneStringInfo(const UnicodeString &id, const UnicodeString &str,
|
||||
TimeZoneTranslationType type, ZSFStringPool &sp, UErrorCode &status);
|
||||
|
||||
const UChar *fId;
|
||||
const UChar *fStr;
|
||||
TimeZoneTranslationType fType;
|
||||
};
|
||||
|
||||
inline UnicodeString& ZoneStringInfo::getID(UnicodeString &result) const {
|
||||
return result.setTo(fId, -1);
|
||||
}
|
||||
|
||||
inline UnicodeString& ZoneStringInfo::getString(UnicodeString &result) const {
|
||||
return result.setTo(fStr, -1);
|
||||
}
|
||||
|
||||
inline UBool ZoneStringInfo::isStandard(void) const {
|
||||
return (fType == STANDARD_LONG || fType == STANDARD_SHORT);
|
||||
}
|
||||
|
||||
inline UBool ZoneStringInfo::isDaylight(void) const {
|
||||
return (fType == DAYLIGHT_LONG || fType == DAYLIGHT_SHORT);
|
||||
}
|
||||
|
||||
inline UBool ZoneStringInfo::isGeneric(void) const {
|
||||
return (fType == LOCATION || fType == GENERIC_LONG || fType == GENERIC_SHORT);
|
||||
}
|
||||
|
||||
class SafeZoneStringFormatPtr;
|
||||
|
||||
class ZoneStringFormat : public UMemory {
|
||||
public:
|
||||
ZoneStringFormat(const UnicodeString* const* strings, int32_t rowCount, int32_t columnCount, UErrorCode &status);
|
||||
ZoneStringFormat(const Locale& locale, UErrorCode &status);
|
||||
virtual ~ZoneStringFormat();
|
||||
|
||||
/* Gets zone string format from cache if available, create it if not cached. */
|
||||
static SafeZoneStringFormatPtr* getZoneStringFormat(const Locale& locale, UErrorCode &status);
|
||||
|
||||
/*
|
||||
* Create a snapshot of old zone strings array for the given date
|
||||
*/
|
||||
UnicodeString** createZoneStringsArray(UDate date, int32_t &rowCount, int32_t &colCount, UErrorCode &status) const;
|
||||
|
||||
/* TODO: There is no implementation for this function. Delete declaration? */
|
||||
const UnicodeString** getZoneStrings(int32_t &rowCount, int32_t &columnCount) const;
|
||||
|
||||
UnicodeString& getSpecificLongString(const Calendar &cal,
|
||||
UnicodeString &result, UErrorCode &status) const;
|
||||
|
||||
UnicodeString& getSpecificShortString(const Calendar &cal,
|
||||
UBool commonlyUsedOnly, UnicodeString &result, UErrorCode &status) const;
|
||||
|
||||
UnicodeString& getGenericLongString(const Calendar &cal,
|
||||
UnicodeString &result, UErrorCode &status) const;
|
||||
|
||||
UnicodeString& getGenericShortString(const Calendar &cal,
|
||||
UBool commonlyUsedOnly, UnicodeString &result, UErrorCode &status) const;
|
||||
|
||||
UnicodeString& getGenericLocationString(const Calendar &cal,
|
||||
UnicodeString &result, UErrorCode &status) const;
|
||||
|
||||
const ZoneStringInfo* findSpecificLong(const UnicodeString &text, int32_t start,
|
||||
int32_t &matchLength, UErrorCode &status) const;
|
||||
const ZoneStringInfo* findSpecificShort(const UnicodeString &text, int32_t start,
|
||||
int32_t &matchLength, UErrorCode &status) const;
|
||||
const ZoneStringInfo* findGenericLong(const UnicodeString &text, int32_t start,
|
||||
int32_t &matchLength, UErrorCode &status) const;
|
||||
const ZoneStringInfo* findGenericShort(const UnicodeString &text, int32_t start,
|
||||
int32_t &matchLength, UErrorCode &status) const;
|
||||
const ZoneStringInfo* findGenericLocation(const UnicodeString &text, int32_t start,
|
||||
int32_t &matchLength, UErrorCode &status) const;
|
||||
|
||||
// Following APIs are not used by SimpleDateFormat, but public for testing purpose
|
||||
inline UnicodeString& getLongStandard(const UnicodeString &tzid, UDate date,
|
||||
UnicodeString &result) const;
|
||||
inline UnicodeString& getLongDaylight(const UnicodeString &tzid, UDate date,
|
||||
UnicodeString &result) const;
|
||||
inline UnicodeString& getLongGenericNonLocation(const UnicodeString &tzid, UDate date,
|
||||
UnicodeString &result) const;
|
||||
inline UnicodeString& getLongGenericPartialLocation(const UnicodeString &tzid, UDate date,
|
||||
UnicodeString &result) const;
|
||||
inline UnicodeString& getShortStandard(const UnicodeString &tzid, UDate date, UBool commonlyUsedOnly,
|
||||
UnicodeString &result) const;
|
||||
inline UnicodeString& getShortDaylight(const UnicodeString &tzid, UDate date, UBool commonlyUsedOnly,
|
||||
UnicodeString &result) const;
|
||||
inline UnicodeString& getShortGenericNonLocation(const UnicodeString &tzid, UDate date, UBool commonlyUsedOnly,
|
||||
UnicodeString &result) const;
|
||||
inline UnicodeString& getShortGenericPartialLocation(const UnicodeString &tzid, UDate date, UBool commonlyUsedOnly,
|
||||
UnicodeString &result) const;
|
||||
inline UnicodeString& getGenericLocation(const UnicodeString &tzid, UnicodeString &result) const;
|
||||
|
||||
private:
|
||||
Locale fLocale;
|
||||
UHashtable *fTzidToStrings;
|
||||
UHashtable *fMzidToStrings;
|
||||
|
||||
TextTrieMap fZoneStringsTrie;
|
||||
ZSFStringPool fStringPool;
|
||||
|
||||
UResourceBundle *fZoneStringsArray;
|
||||
UResourceBundle *fMetazoneItem;
|
||||
UResourceBundle *fZoneItem;
|
||||
|
||||
UBool fIsFullyLoaded;
|
||||
|
||||
void loadZone(const UnicodeString &utzid, UErrorCode &status);
|
||||
void addSingleZone(UnicodeString &utzid, UErrorCode &status);
|
||||
void loadFull(UErrorCode &status);
|
||||
|
||||
|
||||
/*
|
||||
* Private method to get a zone string except generic partial location types.
|
||||
*/
|
||||
UnicodeString& getString(const UnicodeString &tzid, TimeZoneTranslationTypeIndex typeIdx, UDate date,
|
||||
UBool commonlyUsedOnly, UnicodeString& result) const;
|
||||
|
||||
/*
|
||||
* Private method to get a generic string, with fallback logic involved,
|
||||
* that is,
|
||||
*
|
||||
* 1. If a generic non-location string is avaiable for the zone, return it.
|
||||
* 2. If a generic non-location string is associated with a metazone and
|
||||
* the zone never use daylight time around the given date, use the standard
|
||||
* string (if available).
|
||||
*
|
||||
* Note: In CLDR1.5.1, the same localization is used for generic and standard.
|
||||
* In this case, we do not use the standard string and do the rest.
|
||||
*
|
||||
* 3. If a generic non-location string is associated with a metazone and
|
||||
* the offset at the given time is different from the preferred zone for the
|
||||
* current locale, then return the generic partial location string (if avaiable)
|
||||
* 4. If a generic non-location string is not available, use generic location
|
||||
* string.
|
||||
*/
|
||||
UnicodeString& getGenericString(const Calendar &cal, UBool isShort, UBool commonlyUsedOnly,
|
||||
UnicodeString &result, UErrorCode &status) const;
|
||||
|
||||
/*
|
||||
* Private method to get a generic partial location string
|
||||
*/
|
||||
UnicodeString& getGenericPartialLocationString(const UnicodeString &tzid, UBool isShort,
|
||||
UDate date, UBool commonlyUsedOnly, UnicodeString &result) const;
|
||||
|
||||
/*
|
||||
* Find a prefix matching time zone for the given zone string types.
|
||||
* @param text The text contains a time zone string
|
||||
* @param start The start index within the text
|
||||
* @param types The bit mask representing a set of requested types
|
||||
* @param matchLength Receives the match length
|
||||
* @param status
|
||||
* @return If any zone string matched for the requested types, returns a
|
||||
* ZoneStringInfo for the longest match. If no matches are found for
|
||||
* the requested types, returns a ZoneStringInfo for the longest match
|
||||
* for any other types. If nothing matches at all, returns null.
|
||||
*/
|
||||
const ZoneStringInfo* find(const UnicodeString &text, int32_t start, int32_t types,
|
||||
int32_t &matchLength, UErrorCode &status) const;
|
||||
const ZoneStringInfo* subFind(const UnicodeString &text, int32_t start, int32_t types,
|
||||
int32_t &matchLength, UErrorCode &status) const;
|
||||
|
||||
UnicodeString& getRegion(UnicodeString ®ion) const;
|
||||
|
||||
static MessageFormat* getFallbackFormat(const Locale &locale, UErrorCode &status);
|
||||
static MessageFormat* getRegionFormat(const Locale &locale, UErrorCode &status);
|
||||
const UChar* getZoneStringFromBundle(const UResourceBundle *zoneitem, const char *key);
|
||||
static UBool isCommonlyUsed(const UResourceBundle *zoneitem);
|
||||
static UnicodeString& getLocalizedCountry(const UnicodeString &countryCode, const Locale &locale,
|
||||
UnicodeString &displayCountry);
|
||||
};
|
||||
|
||||
inline UnicodeString&
|
||||
ZoneStringFormat::getLongStandard(const UnicodeString &tzid, UDate date,
|
||||
UnicodeString &result) const {
|
||||
return getString(tzid, ZSIDX_LONG_STANDARD, date, FALSE /* not used */, result);
|
||||
}
|
||||
|
||||
inline UnicodeString&
|
||||
ZoneStringFormat::getLongDaylight(const UnicodeString &tzid, UDate date,
|
||||
UnicodeString &result) const {
|
||||
return getString(tzid, ZSIDX_LONG_DAYLIGHT, date, FALSE /* not used */, result);
|
||||
}
|
||||
|
||||
inline UnicodeString&
|
||||
ZoneStringFormat::getLongGenericNonLocation(const UnicodeString &tzid, UDate date,
|
||||
UnicodeString &result) const {
|
||||
return getString(tzid, ZSIDX_LONG_GENERIC, date, FALSE /* not used */, result);
|
||||
}
|
||||
|
||||
inline UnicodeString&
|
||||
ZoneStringFormat::getLongGenericPartialLocation(const UnicodeString &tzid, UDate date,
|
||||
UnicodeString &result) const {
|
||||
return getGenericPartialLocationString(tzid, FALSE, date, FALSE /* not used */, result);
|
||||
}
|
||||
|
||||
inline UnicodeString&
|
||||
ZoneStringFormat::getShortStandard(const UnicodeString &tzid, UDate date, UBool commonlyUsedOnly,
|
||||
UnicodeString &result) const {
|
||||
return getString(tzid, ZSIDX_SHORT_STANDARD, date, commonlyUsedOnly, result);
|
||||
}
|
||||
|
||||
inline UnicodeString&
|
||||
ZoneStringFormat::getShortDaylight(const UnicodeString &tzid, UDate date, UBool commonlyUsedOnly,
|
||||
UnicodeString &result) const {
|
||||
return getString(tzid, ZSIDX_SHORT_DAYLIGHT, date, commonlyUsedOnly, result);
|
||||
}
|
||||
|
||||
inline UnicodeString&
|
||||
ZoneStringFormat::getShortGenericNonLocation(const UnicodeString &tzid, UDate date, UBool commonlyUsedOnly,
|
||||
UnicodeString &result) const {
|
||||
return getString(tzid, ZSIDX_SHORT_GENERIC, date, commonlyUsedOnly, result);
|
||||
}
|
||||
|
||||
inline UnicodeString&
|
||||
ZoneStringFormat::getShortGenericPartialLocation(const UnicodeString &tzid, UDate date, UBool commonlyUsedOnly,
|
||||
UnicodeString &result) const {
|
||||
return getGenericPartialLocationString(tzid, TRUE, date, commonlyUsedOnly, result);
|
||||
}
|
||||
|
||||
inline UnicodeString&
|
||||
ZoneStringFormat::getGenericLocation(const UnicodeString &tzid, UnicodeString &result) const {
|
||||
return getString(tzid, ZSIDX_LOCATION, 0 /*not used*/, FALSE /*not used*/, result);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* ZoneStrings is a container of localized zone strings used by ZoneStringFormat
|
||||
*/
|
||||
class ZoneStrings : public UMemory {
|
||||
public:
|
||||
ZoneStrings(UnicodeString *strings,
|
||||
int32_t stringsCount,
|
||||
UBool commonlyUsed,
|
||||
UnicodeString **genericPartialLocationStrings,
|
||||
int32_t genericRowCount,
|
||||
int32_t genericColCount,
|
||||
ZSFStringPool &sp,
|
||||
UErrorCode &status);
|
||||
virtual ~ZoneStrings();
|
||||
|
||||
UnicodeString& getString(int32_t typeIdx, UnicodeString &result) const;
|
||||
inline UBool isShortFormatCommonlyUsed(void) const;
|
||||
UnicodeString& getGenericPartialLocationString(const UnicodeString &mzid, UBool isShort,
|
||||
UBool commonlyUsedOnly, UnicodeString &result) const;
|
||||
|
||||
private:
|
||||
const UChar **fStrings;
|
||||
int32_t fStringsCount;
|
||||
UBool fIsCommonlyUsed;
|
||||
const UChar * **fGenericPartialLocationStrings;
|
||||
int32_t fGenericPartialLocationRowCount;
|
||||
int32_t fGenericPartialLocationColCount;
|
||||
};
|
||||
|
||||
inline UBool
|
||||
ZoneStrings::isShortFormatCommonlyUsed(void) const {
|
||||
return fIsCommonlyUsed;
|
||||
}
|
||||
|
||||
/*
|
||||
* ZoneStringSearchResultHandler is an implementation of
|
||||
* TextTrieMapSearchHandler. This class is used by ZoneStringFormat
|
||||
* for collecting search results for localized zone strings.
|
||||
*/
|
||||
class ZoneStringSearchResultHandler : public TextTrieMapSearchResultHandler {
|
||||
public:
|
||||
ZoneStringSearchResultHandler(UErrorCode &status);
|
||||
virtual ~ZoneStringSearchResultHandler();
|
||||
|
||||
virtual UBool handleMatch(int32_t matchLength, const CharacterNode *node, UErrorCode &status);
|
||||
int32_t countMatches(void);
|
||||
const ZoneStringInfo* getMatch(int32_t index, int32_t &matchLength);
|
||||
void clear(void);
|
||||
|
||||
private:
|
||||
UVector fResults;
|
||||
int32_t fMatchLen[ZSIDX_COUNT];
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* ZoneStringFormat cache implementation
|
||||
*/
|
||||
class ZSFCacheEntry : public UMemory {
|
||||
public:
|
||||
~ZSFCacheEntry();
|
||||
|
||||
void delRef(void);
|
||||
const ZoneStringFormat* getZoneStringFormat(void);
|
||||
|
||||
private:
|
||||
friend class ZSFCache;
|
||||
|
||||
ZSFCacheEntry(const Locale &locale, ZoneStringFormat *zsf, ZSFCacheEntry *next);
|
||||
|
||||
Locale fLocale;
|
||||
ZoneStringFormat *fZoneStringFormat;
|
||||
ZSFCacheEntry *fNext;
|
||||
int32_t fRefCount;
|
||||
};
|
||||
|
||||
class SafeZoneStringFormatPtr : public UMemory {
|
||||
public:
|
||||
~SafeZoneStringFormatPtr();
|
||||
const ZoneStringFormat* get() const;
|
||||
|
||||
private:
|
||||
friend class ZSFCache;
|
||||
|
||||
SafeZoneStringFormatPtr(ZSFCacheEntry *cacheEntry);
|
||||
|
||||
ZSFCacheEntry *fCacheEntry;
|
||||
};
|
||||
|
||||
class ZSFCache : public UMemory {
|
||||
public:
|
||||
ZSFCache(int32_t capacity);
|
||||
~ZSFCache();
|
||||
|
||||
SafeZoneStringFormatPtr* get(const Locale &locale, UErrorCode &status);
|
||||
|
||||
private:
|
||||
int32_t fCapacity;
|
||||
ZSFCacheEntry *fFirst;
|
||||
};
|
||||
|
||||
U_NAMESPACE_END
|
||||
|
||||
#endif /* #if !UCONFIG_NO_FORMATTING */
|
||||
|
||||
#endif // ZSTRFMT_H
|
|
@ -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
|
||||
|
|
|
@ -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" },
|
||||
|
|
|
@ -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(""),
|
||||
};
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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, ""}
|
||||
};
|
||||
|
|
Loading…
Add table
Reference in a new issue