ICU-8513 Merging TimeZoneNames/TimeZoneFormat APIs (as 49 technology preview) into trunk.

X-SVN-Rev: 31469
This commit is contained in:
Yoshito Umaoka 2012-02-21 11:06:50 +00:00
parent 733a433be7
commit 1641940f00
23 changed files with 4034 additions and 1616 deletions

View file

@ -174,12 +174,10 @@ Global
{77C78066-746F-4EA6-B3FE-B8C8A4A97891}.Release|x64.Build.0 = Release|x64
{0178B127-6269-407D-B112-93877BB62776}.Debug|Win32.ActiveCfg = Debug|Win32
{0178B127-6269-407D-B112-93877BB62776}.Debug|Win32.Build.0 = Debug|Win32
{0178B127-6269-407D-B112-93877BB62776}.Debug|x64.ActiveCfg = Debug|x64
{0178B127-6269-407D-B112-93877BB62776}.Debug|x64.Build.0 = Debug|x64
{0178B127-6269-407D-B112-93877BB62776}.Debug|x64.ActiveCfg = Debug|Win32
{0178B127-6269-407D-B112-93877BB62776}.Release|Win32.ActiveCfg = Release|Win32
{0178B127-6269-407D-B112-93877BB62776}.Release|Win32.Build.0 = Release|Win32
{0178B127-6269-407D-B112-93877BB62776}.Release|x64.ActiveCfg = Release|x64
{0178B127-6269-407D-B112-93877BB62776}.Release|x64.Build.0 = Release|x64
{0178B127-6269-407D-B112-93877BB62776}.Release|x64.ActiveCfg = Release|Win32
{73632960-B3A6-464D-83A3-4B43365F19B8}.Debug|Win32.ActiveCfg = Debug|Win32
{73632960-B3A6-464D-83A3-4B43365F19B8}.Debug|Win32.Build.0 = Debug|Win32
{73632960-B3A6-464D-83A3-4B43365F19B8}.Debug|x64.ActiveCfg = Debug|x64

View file

@ -26,6 +26,7 @@
#include "unicode/dtfmtsym.h"
#include "unicode/smpdtfmt.h"
#include "unicode/msgfmt.h"
#include "unicode/tznames.h"
#include "cpputils.h"
#include "ucln_in.h"
#include "umutex.h"
@ -36,7 +37,6 @@
#include "hash.h"
#include "uresimp.h"
#include "ureslocs.h"
#include "tznames.h"
// *****************************************************************************
// class DateFormatSymbols
@ -120,31 +120,6 @@ 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" */
//};
static const UChar gLastResortGmtZero[] =
{0x0047, 0x004D, 0x0054, 0x0000}; /* GMT */
static const UChar gLastResortGmtFormat[] =
{0x0047, 0x004D, 0x0054, 0x007B, 0x0030, 0x007D, 0x0000}; /* GMT{0} */
static const UChar gLastResortGmtHourFormats[4][10] =
{
{0x002D, 0x0048, 0x0048, 0x003A, 0x006D, 0x006D, 0x003A, 0x0073, 0x0073, 0x0000}, /* -HH:mm:ss */
{0x002D, 0x0048, 0x0048, 0x003A, 0x006D, 0x006D, 0x0000, 0x0000, 0x0000, 0x0000}, /* -HH:mm */
{0x002B, 0x0048, 0x0048, 0x003A, 0x006D, 0x006D, 0x003A, 0x0073, 0x0073, 0x0000}, /* +HH:mm:ss */
{0x002B, 0x0048, 0x0048, 0x003A, 0x006D, 0x006D, 0x0000, 0x0000, 0x0000, 0x0000} /* +HH:mm */
};
/* Sizes for the last resort string arrays */
typedef enum LastResortSize {
kMonthNum = 13,
@ -197,9 +172,6 @@ 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";
static const char gLocalPatternCharsTag[]="localPatternChars";
@ -352,9 +324,6 @@ DateFormatSymbols::copyData(const DateFormatSymbols& other) {
fShortYearNames = NULL;
fShortYearNamesCount = 0;
}
fGmtZero = other.fGmtZero;
fGmtFormat = other.fGmtFormat;
assignArray(fGmtHourFormats, fGmtHourFormatsCount, other.fGmtHourFormats, other.fGmtHourFormatsCount);
if (other.fZoneStrings != NULL) {
fZoneStringsColCount = other.fZoneStringsColCount;
@ -416,7 +385,6 @@ void DateFormatSymbols::dispose()
if (fStandaloneShortQuarters) delete[] fStandaloneShortQuarters;
if (fLeapMonthPatterns) delete[] fLeapMonthPatterns;
if (fShortYearNames) delete[] fShortYearNames;
if (fGmtHourFormats) delete[] fGmtHourFormats;
disposeZoneStrings();
}
@ -485,9 +453,6 @@ DateFormatSymbols::operator==(const DateFormatSymbols& other) const
fStandaloneShortQuartersCount == other.fStandaloneShortQuartersCount &&
fLeapMonthPatternsCount == other.fLeapMonthPatternsCount &&
fShortYearNamesCount == other.fShortYearNamesCount &&
fGmtHourFormatsCount == other.fGmtHourFormatsCount &&
fGmtZero == other.fGmtZero &&
fGmtFormat == other.fGmtFormat &&
(uprv_memcmp(fCapitalization, other.fCapitalization, sizeof(fCapitalization))==0))
{
// Now compare the arrays themselves
@ -512,8 +477,7 @@ DateFormatSymbols::operator==(const DateFormatSymbols& other) const
arrayCompare(fStandaloneQuarters, other.fStandaloneQuarters, fStandaloneQuartersCount) &&
arrayCompare(fStandaloneShortQuarters, other.fStandaloneShortQuarters, fStandaloneShortQuartersCount) &&
arrayCompare(fLeapMonthPatterns, other.fLeapMonthPatterns, fLeapMonthPatternsCount) &&
arrayCompare(fShortYearNames, other.fShortYearNames, fShortYearNamesCount) &&
arrayCompare(fGmtHourFormats, other.fGmtHourFormats, fGmtHourFormatsCount))
arrayCompare(fShortYearNames, other.fShortYearNames, fShortYearNamesCount))
{
// Compare the contents of fZoneStrings
if (fZoneStrings == NULL && other.fZoneStrings == NULL) {
@ -1333,8 +1297,6 @@ DateFormatSymbols::initializeData(const Locale& locale, const char *type, UError
fLeapMonthPatternsCount = 0;
fShortYearNames = NULL;
fShortYearNamesCount = 0;
fGmtHourFormats = NULL;
fGmtHourFormatsCount = 0;
fZoneStringsRowCount = 0;
fZoneStringsColCount = 0;
fZoneStrings = NULL;
@ -1356,12 +1318,6 @@ DateFormatSymbols::initializeData(const Locale& locale, const char *type, UError
*/
CalendarData calData(locale, type, status);
/**
* Use the localeBundle for getting zone GMT formatting patterns
*/
UResourceBundle *zoneBundle = ures_open(U_ICUDATA_ZONE, locale.getName(), &status);
UResourceBundle *zoneStringsArray = ures_getByKeyWithFallback(zoneBundle, gZoneStringsTag, NULL, &status);
// load the first data item
UResourceBundle *erasMain = calData.getByKey(gErasTag, status);
UResourceBundle *eras = ures_getByKeyWithFallback(erasMain, gNamesAbbrTag, NULL, &status);
@ -1488,9 +1444,6 @@ DateFormatSymbols::initializeData(const Locale& locale, const char *type, UError
initField(&fShortQuarters, fShortQuartersCount, (const UChar *)gLastResortQuarters, kQuarterNum, kQuarterLen, status);
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);
}
goto cleanup;
@ -1555,50 +1508,6 @@ 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) {
fGmtFormat.setTo(TRUE, resStr, len);
}
resStr = ures_getStringByKeyWithFallback(zoneStringsArray, gHourFormatTag, &len, &status);
if (len > 0) {
UChar *sep = u_strchr(resStr, (UChar)0x003B /* ';' */);
if (sep != NULL) {
fGmtHourFormats = newUnicodeStringArray(GMT_HOUR_COUNT);
if (fGmtHourFormats == NULL) {
status = U_MEMORY_ALLOCATION_ERROR;
} else {
fGmtHourFormatsCount = GMT_HOUR_COUNT;
fGmtHourFormats[GMT_NEGATIVE_HM].setTo(TRUE, sep + 1, -1);
fGmtHourFormats[GMT_POSITIVE_HM].setTo(FALSE, resStr, (int32_t)(sep - resStr));
// CLDR 1.5 does not have GMT offset pattern including second field.
// For now, append "ss" to the end.
if (fGmtHourFormats[GMT_NEGATIVE_HM].indexOf((UChar)0x003A /* ':' */) != -1) {
fGmtHourFormats[GMT_NEGATIVE_HMS] = fGmtHourFormats[GMT_NEGATIVE_HM] + UNICODE_STRING_SIMPLE(":ss");
} else if (fGmtHourFormats[GMT_NEGATIVE_HM].indexOf((UChar)0x002E /* '.' */) != -1) {
fGmtHourFormats[GMT_NEGATIVE_HMS] = fGmtHourFormats[GMT_NEGATIVE_HM] + UNICODE_STRING_SIMPLE(".ss");
} else {
fGmtHourFormats[GMT_NEGATIVE_HMS] = fGmtHourFormats[GMT_NEGATIVE_HM] + UNICODE_STRING_SIMPLE("ss");
}
if (fGmtHourFormats[GMT_POSITIVE_HM].indexOf((UChar)0x003A /* ':' */) != -1) {
fGmtHourFormats[GMT_POSITIVE_HMS] = fGmtHourFormats[GMT_POSITIVE_HM] + UNICODE_STRING_SIMPLE(":ss");
} else if (fGmtHourFormats[GMT_POSITIVE_HM].indexOf((UChar)0x002E /* '.' */) != -1) {
fGmtHourFormats[GMT_POSITIVE_HMS] = fGmtHourFormats[GMT_POSITIVE_HM] + UNICODE_STRING_SIMPLE(".ss");
} else {
fGmtHourFormats[GMT_POSITIVE_HMS] = fGmtHourFormats[GMT_POSITIVE_HM] + UNICODE_STRING_SIMPLE("ss");
}
}
}
}
// ICU 3.8 or later version no longer uses localized date-time pattern characters by default (ticket#5597)
/*
// fastCopyFrom()/setTo() - see assignArray comments
@ -1737,8 +1646,6 @@ cleanup:
ures_close(eras);
ures_close(eraNames);
ures_close(narrowEras);
ures_close(zoneStringsArray);
ures_close(zoneBundle);
}
Locale

View file

@ -579,9 +579,7 @@
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
</CustomBuild>
<ClInclude Include="numsys_impl.h" />
<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" />
@ -617,6 +615,14 @@
</Command>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
</CustomBuild>
<CustomBuild Include="unicode\tzfmt.h">
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy "%(FullPath)" ..\..\include\unicode</Command>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
</CustomBuild>
<CustomBuild Include="unicode\tznames.h">
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy "%(FullPath)" ..\..\include\unicode</Command>
</CustomBuild>
<ClInclude Include="usrchimp.h" />
<ClInclude Include="astro.h" />
<CustomBuild Include="unicode\basictz.h">

View file

@ -768,15 +768,9 @@
<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>
@ -1001,5 +995,11 @@
<CustomBuild Include="unicode\alphaindex.h">
<Filter>collation</Filter>
</CustomBuild>
<CustomBuild Include="unicode\tzfmt.h">
<Filter>formatting</Filter>
</CustomBuild>
<CustomBuild Include="unicode\tznames.h">
<Filter>formatting</Filter>
</CustomBuild>
</ItemGroup>
</Project>

View file

@ -45,6 +45,7 @@
#include "unicode/basictz.h"
#include "unicode/simpletz.h"
#include "unicode/rbtz.h"
#include "unicode/tzfmt.h"
#include "unicode/utf16.h"
#include "unicode/vtzone.h"
#include "olsontz.h"
@ -56,7 +57,6 @@
#include "uassert.h"
#include "cmemory.h"
#include "umutex.h"
#include "tzfmt.h"
#include <float.h>
#include "smpdtfst.h"
@ -212,15 +212,6 @@ UOBJECT_DEFINE_RTTI_IMPLEMENTATION(SimpleDateFormat)
SimpleDateFormat::~SimpleDateFormat()
{
delete fSymbols;
if (fGMTFormatters) {
for (int32_t i = 0; i < kNumGMTFormatters; i++) {
if (fGMTFormatters[i]) {
delete fGMTFormatters[i];
}
}
uprv_free(fGMTFormatters);
}
if (fNumberFormatters) {
uprv_free(fNumberFormatters);
}
@ -242,7 +233,6 @@ SimpleDateFormat::SimpleDateFormat(UErrorCode& status)
: fLocale(Locale::getDefault()),
fSymbols(NULL),
fTimeZoneFormat(NULL),
fGMTFormatters(NULL),
fNumberFormatters(NULL),
fOverrideList(NULL),
fDefaultCapitalizationContext(UDAT_CAPITALIZATION_UNKNOWN)
@ -259,7 +249,6 @@ SimpleDateFormat::SimpleDateFormat(const UnicodeString& pattern,
fLocale(Locale::getDefault()),
fSymbols(NULL),
fTimeZoneFormat(NULL),
fGMTFormatters(NULL),
fNumberFormatters(NULL),
fOverrideList(NULL),
fDefaultCapitalizationContext(UDAT_CAPITALIZATION_UNKNOWN)
@ -280,7 +269,6 @@ SimpleDateFormat::SimpleDateFormat(const UnicodeString& pattern,
fLocale(Locale::getDefault()),
fSymbols(NULL),
fTimeZoneFormat(NULL),
fGMTFormatters(NULL),
fNumberFormatters(NULL),
fOverrideList(NULL),
fDefaultCapitalizationContext(UDAT_CAPITALIZATION_UNKNOWN)
@ -303,7 +291,6 @@ SimpleDateFormat::SimpleDateFormat(const UnicodeString& pattern,
: fPattern(pattern),
fLocale(locale),
fTimeZoneFormat(NULL),
fGMTFormatters(NULL),
fNumberFormatters(NULL),
fOverrideList(NULL),
fDefaultCapitalizationContext(UDAT_CAPITALIZATION_UNKNOWN)
@ -326,7 +313,6 @@ SimpleDateFormat::SimpleDateFormat(const UnicodeString& pattern,
: fPattern(pattern),
fLocale(locale),
fTimeZoneFormat(NULL),
fGMTFormatters(NULL),
fNumberFormatters(NULL),
fOverrideList(NULL),
fDefaultCapitalizationContext(UDAT_CAPITALIZATION_UNKNOWN)
@ -352,7 +338,6 @@ SimpleDateFormat::SimpleDateFormat(const UnicodeString& pattern,
fLocale(Locale::getDefault()),
fSymbols(symbolsToAdopt),
fTimeZoneFormat(NULL),
fGMTFormatters(NULL),
fNumberFormatters(NULL),
fOverrideList(NULL),
fDefaultCapitalizationContext(UDAT_CAPITALIZATION_UNKNOWN)
@ -375,7 +360,6 @@ SimpleDateFormat::SimpleDateFormat(const UnicodeString& pattern,
fLocale(Locale::getDefault()),
fSymbols(new DateFormatSymbols(symbols)),
fTimeZoneFormat(NULL),
fGMTFormatters(NULL),
fNumberFormatters(NULL),
fOverrideList(NULL),
fDefaultCapitalizationContext(UDAT_CAPITALIZATION_UNKNOWN)
@ -399,7 +383,6 @@ SimpleDateFormat::SimpleDateFormat(EStyle timeStyle,
: fLocale(locale),
fSymbols(NULL),
fTimeZoneFormat(NULL),
fGMTFormatters(NULL),
fNumberFormatters(NULL),
fOverrideList(NULL),
fDefaultCapitalizationContext(UDAT_CAPITALIZATION_UNKNOWN)
@ -423,7 +406,6 @@ SimpleDateFormat::SimpleDateFormat(const Locale& locale,
fLocale(locale),
fSymbols(NULL),
fTimeZoneFormat(NULL),
fGMTFormatters(NULL),
fNumberFormatters(NULL),
fOverrideList(NULL),
fDefaultCapitalizationContext(UDAT_CAPITALIZATION_UNKNOWN)
@ -458,7 +440,6 @@ SimpleDateFormat::SimpleDateFormat(const SimpleDateFormat& other)
: DateFormat(other),
fSymbols(NULL),
fTimeZoneFormat(NULL),
fGMTFormatters(NULL),
fNumberFormatters(NULL),
fOverrideList(NULL),
fDefaultCapitalizationContext(UDAT_CAPITALIZATION_UNKNOWN)
@ -1042,374 +1023,7 @@ _appendSymbolWithMonthPattern(UnicodeString& dst, int32_t value, const UnicodeSt
}
}
//---------------------------------------------------------------------
void
SimpleDateFormat::appendGMT(NumberFormat *currentNumberFormat,UnicodeString &appendTo, Calendar& cal, UErrorCode& status) const{
int32_t offset = cal.get(UCAL_ZONE_OFFSET, status) + cal.get(UCAL_DST_OFFSET, status);
if (U_FAILURE(status)) {
return;
}
if (offset == 0) {
// use GMT zero format
appendTo += fSymbols->fGmtZero;
} else {
if (isDefaultGMTFormat()) {
formatGMTDefault(currentNumberFormat,appendTo, offset);
} else {
((SimpleDateFormat*)this)->initGMTFormatters(status);
if (U_SUCCESS(status)) {
int32_t type;
if (offset < 0) {
offset = -offset;
type = (offset % U_MILLIS_PER_MINUTE) == 0 ? kGMTNegativeHM : kGMTNegativeHMS;
} else {
type = (offset % U_MILLIS_PER_MINUTE) == 0 ? kGMTPositiveHM : kGMTPositiveHMS;
}
Formattable param(offset, Formattable::kIsDate);
FieldPosition fpos(0);
fGMTFormatters[type]->format(&param, 1, appendTo, fpos, status);
}
}
}
}
int32_t
SimpleDateFormat::parseGMT(const UnicodeString &text, ParsePosition &pos) const {
if (!isDefaultGMTFormat()) {
int32_t start = pos.getIndex();
// Quick check
UBool prefixMatch = FALSE;
int32_t prefixLen = fSymbols->fGmtFormat.indexOf((UChar)0x007B /* '{' */);
if (prefixLen > 0 && text.compare(start, prefixLen, fSymbols->fGmtFormat, 0, prefixLen) == 0) {
prefixMatch = TRUE;
}
if (prefixMatch) {
// Prefix matched
UErrorCode status = U_ZERO_ERROR;
((SimpleDateFormat*)this)->initGMTFormatters(status);
if (U_SUCCESS(status)) {
Formattable parsed;
int32_t parsedCount;
// Try negative Hms
fGMTFormatters[kGMTNegativeHMS]->parseObject(text, parsed, pos);
if (pos.getErrorIndex() == -1 &&
(pos.getIndex() - start) >= fGMTFormatHmsMinLen[kGMTNegativeHMSMinLenIdx]) {
parsed.getArray(parsedCount);
if (parsedCount == 1 && parsed[0].getType() == Formattable::kDate) {
return (int32_t)(-1 * (int64_t)parsed[0].getDate());
}
}
// Reset ParsePosition
pos.setIndex(start);
pos.setErrorIndex(-1);
// Try positive Hms
fGMTFormatters[kGMTPositiveHMS]->parseObject(text, parsed, pos);
if (pos.getErrorIndex() == -1 &&
(pos.getIndex() - start) >= fGMTFormatHmsMinLen[kGMTPositiveHMSMinLenIdx]) {
parsed.getArray(parsedCount);
if (parsedCount == 1 && parsed[0].getType() == Formattable::kDate) {
return (int32_t)((int64_t)parsed[0].getDate());
}
}
// Reset ParsePosition
pos.setIndex(start);
pos.setErrorIndex(-1);
// Try negative Hm
fGMTFormatters[kGMTNegativeHM]->parseObject(text, parsed, pos);
if (pos.getErrorIndex() == -1 && pos.getIndex() > start) {
parsed.getArray(parsedCount);
if (parsedCount == 1 && parsed[0].getType() == Formattable::kDate) {
return (int32_t)(-1 * (int64_t)parsed[0].getDate());
}
}
// Reset ParsePosition
pos.setIndex(start);
pos.setErrorIndex(-1);
// Try positive Hm
fGMTFormatters[kGMTPositiveHM]->parseObject(text, parsed, pos);
if (pos.getErrorIndex() == -1 && pos.getIndex() > start) {
parsed.getArray(parsedCount);
if (parsedCount == 1 && parsed[0].getType() == Formattable::kDate) {
return (int32_t)((int64_t)parsed[0].getDate());
}
}
// Reset ParsePosition
pos.setIndex(start);
pos.setErrorIndex(-1);
}
// fall through to the default GMT parsing method
}
}
return parseGMTDefault(text, pos);
}
void
SimpleDateFormat::formatGMTDefault(NumberFormat *currentNumberFormat,UnicodeString &appendTo, int32_t offset) const {
if (offset < 0) {
appendTo.append(gGmtMinus, 4);
offset = -offset; // suppress the '-' sign for text display.
}else{
appendTo.append(gGmtPlus, 4);
}
offset /= U_MILLIS_PER_SECOND; // now in seconds
int32_t sec = offset % 60;
offset /= 60;
int32_t min = offset % 60;
int32_t hour = offset / 60;
zeroPaddingNumber(currentNumberFormat,appendTo, hour, 2, 2);
appendTo += (UChar)0x003A /*':'*/;
zeroPaddingNumber(currentNumberFormat,appendTo, min, 2, 2);
if (sec != 0) {
appendTo += (UChar)0x003A /*':'*/;
zeroPaddingNumber(currentNumberFormat,appendTo, sec, 2, 2);
}
}
int32_t
SimpleDateFormat::parseGMTDefault(const UnicodeString &text, ParsePosition &pos) const {
int32_t start = pos.getIndex();
NumberFormat *currentNumberFormat = getNumberFormatByIndex(UDAT_TIMEZONE_RFC_FIELD);
if (start + kUtLen + 1 >= text.length()) {
pos.setErrorIndex(start);
return 0;
}
int32_t cur = start;
// "GMT"
if (text.compare(start, kGmtLen, gGmt) == 0) {
cur += kGmtLen;
} else if (text.compare(start, kUtLen, gUt) == 0) {
cur += kUtLen;
} else {
pos.setErrorIndex(start);
return 0;
}
// Sign
UBool negative = FALSE;
if (text.charAt(cur) == (UChar)0x002D /* minus */) {
negative = TRUE;
} else if (text.charAt(cur) != (UChar)0x002B /* plus */) {
pos.setErrorIndex(cur);
return 0;
}
cur++;
// Numbers
int32_t numLen;
pos.setIndex(cur);
Formattable number;
parseInt(text, number, 6, pos, FALSE,currentNumberFormat);
numLen = pos.getIndex() - cur;
if (numLen <= 0) {
pos.setIndex(start);
pos.setErrorIndex(cur);
return 0;
}
int32_t numVal = number.getLong();
int32_t hour = 0;
int32_t min = 0;
int32_t sec = 0;
if (numLen <= 2) {
// H[H][:mm[:ss]]
hour = numVal;
cur += numLen;
if (cur + 2 < text.length() && text.charAt(cur) == (UChar)0x003A /* colon */) {
cur++;
pos.setIndex(cur);
parseInt(text, number, 2, pos, FALSE,currentNumberFormat);
numLen = pos.getIndex() - cur;
if (numLen == 2) {
// got minute field
min = number.getLong();
cur += numLen;
if (cur + 2 < text.length() && text.charAt(cur) == (UChar)0x003A /* colon */) {
cur++;
pos.setIndex(cur);
parseInt(text, number, 2, pos, FALSE,currentNumberFormat);
numLen = pos.getIndex() - cur;
if (numLen == 2) {
// got second field
sec = number.getLong();
} else {
// reset position
pos.setIndex(cur - 1);
pos.setErrorIndex(-1);
}
}
} else {
// reset postion
pos.setIndex(cur - 1);
pos.setErrorIndex(-1);
}
}
} else if (numLen == 3 || numLen == 4) {
// Hmm or HHmm
hour = numVal / 100;
min = numVal % 100;
} else if (numLen == 5 || numLen == 6) {
// Hmmss or HHmmss
hour = numVal / 10000;
min = (numVal % 10000) / 100;
sec = numVal % 100;
} else {
// HHmmss followed by bogus numbers
pos.setIndex(cur + 6);
int32_t shift = numLen - 6;
while (shift > 0) {
numVal /= 10;
shift--;
}
hour = numVal / 10000;
min = (numVal % 10000) / 100;
sec = numVal % 100;
}
int32_t offset = ((hour*60 + min)*60 + sec)*1000;
if (negative) {
offset = -offset;
}
return offset;
}
UBool
SimpleDateFormat::isDefaultGMTFormat() const {
// GMT pattern
if (fSymbols->fGmtFormat.length() == 0) {
// No GMT pattern is set
return TRUE;
} else if (fSymbols->fGmtFormat.compare(gDefGmtPat, kGmtPatLen) != 0) {
return FALSE;
}
// Hour patterns
if (fSymbols->fGmtHourFormats == NULL || fSymbols->fGmtHourFormatsCount != DateFormatSymbols::GMT_HOUR_COUNT) {
// No Hour pattern is set
return TRUE;
} else if ((fSymbols->fGmtHourFormats[DateFormatSymbols::GMT_NEGATIVE_HMS].compare(gDefGmtNegHmsPat, kNegHmsLen) != 0)
|| (fSymbols->fGmtHourFormats[DateFormatSymbols::GMT_NEGATIVE_HM].compare(gDefGmtNegHmPat, kNegHmLen) != 0)
|| (fSymbols->fGmtHourFormats[DateFormatSymbols::GMT_POSITIVE_HMS].compare(gDefGmtPosHmsPat, kPosHmsLen) != 0)
|| (fSymbols->fGmtHourFormats[DateFormatSymbols::GMT_POSITIVE_HM].compare(gDefGmtPosHmPat, kPosHmLen) != 0)) {
return FALSE;
}
return TRUE;
}
void
SimpleDateFormat::formatRFC822TZ(UnicodeString &appendTo, int32_t offset) const {
UChar sign = 0x002B /* '+' */;
if (offset < 0) {
offset = -offset;
sign = 0x002D /* '-' */;
}
appendTo.append(sign);
int32_t offsetH = offset / U_MILLIS_PER_HOUR;
offset = offset % U_MILLIS_PER_HOUR;
int32_t offsetM = offset / U_MILLIS_PER_MINUTE;
offset = offset % U_MILLIS_PER_MINUTE;
int32_t offsetS = offset / U_MILLIS_PER_SECOND;
int32_t num = 0, denom = 0;
if (offsetS == 0) {
offset = offsetH*100 + offsetM; // HHmm
num = offset % 10000;
denom = 1000;
} else {
offset = offsetH*10000 + offsetM*100 + offsetS; // HHmmss
num = offset % 1000000;
denom = 100000;
}
while (denom >= 1) {
UChar digit = (UChar)0x0030 + (num / denom);
appendTo.append(digit);
num = num % denom;
denom /= 10;
}
}
void
SimpleDateFormat::initGMTFormatters(UErrorCode &status) {
if (U_FAILURE(status)) {
return;
}
umtx_lock(&LOCK);
if (fGMTFormatters == NULL) {
fGMTFormatters = (MessageFormat**)uprv_malloc(kNumGMTFormatters * sizeof(MessageFormat*));
if (fGMTFormatters) {
for (int32_t i = 0; i < kNumGMTFormatters; i++) {
const UnicodeString *hourPattern = NULL; //initialized it to avoid warning
switch (i) {
case kGMTNegativeHMS:
hourPattern = &(fSymbols->fGmtHourFormats[DateFormatSymbols::GMT_NEGATIVE_HMS]);
break;
case kGMTNegativeHM:
hourPattern = &(fSymbols->fGmtHourFormats[DateFormatSymbols::GMT_NEGATIVE_HM]);
break;
case kGMTPositiveHMS:
hourPattern = &(fSymbols->fGmtHourFormats[DateFormatSymbols::GMT_POSITIVE_HMS]);
break;
case kGMTPositiveHM:
hourPattern = &(fSymbols->fGmtHourFormats[DateFormatSymbols::GMT_POSITIVE_HM]);
break;
}
fGMTFormatters[i] = new MessageFormat(fSymbols->fGmtFormat, status);
GregorianCalendar *gcal = new GregorianCalendar(TimeZone::createTimeZone(UnicodeString(gEtcUTC)), status);
if (U_FAILURE(status)) {
break;
}
SimpleDateFormat *sdf = (SimpleDateFormat*)this->clone();
sdf->adoptCalendar(gcal);
sdf->applyPattern(*hourPattern);
// This prevents an hours format pattern like "-HH:mm:ss" from matching
// in a string like "GMT-07:00 10:08:11 PM"
sdf->setLenient(FALSE);
fGMTFormatters[i]->adoptFormat(0, sdf);
// For parsing, we only allow Hms patterns to be equal or longer
// than its length with fixed minutes/seconds digits.
// See #6880
if (i == kGMTNegativeHMS || i == kGMTPositiveHMS) {
UnicodeString tmp;
Formattable tmpParam(60*60*1000, Formattable::kIsDate);
FieldPosition fpos(0);
fGMTFormatters[i]->format(&tmpParam, 1, tmp, fpos, status);
if (U_FAILURE(status)) {
break;
}
if (i == kGMTNegativeHMS) {
fGMTFormatHmsMinLen[kGMTNegativeHMSMinLenIdx] = tmp.length();
} else {
fGMTFormatHmsMinLen[kGMTPositiveHMSMinLenIdx] = tmp.length();
}
}
}
} else {
status = U_MEMORY_ALLOCATION_ERROR;
}
}
umtx_unlock(&LOCK);
}
//----------------------------------------------------------------------
void
SimpleDateFormat::initNumberFormatters(const Locale &locale,UErrorCode &status) {
if (U_FAILURE(status)) {
@ -1627,11 +1241,11 @@ SimpleDateFormat::subFormat(UnicodeString &appendTo,
break;
case UDAT_YEAR_NAME_FIELD:
if (fSymbols->fShortYearNames != NULL && value <= fSymbols->fShortYearNamesCount) {
if (fSymbols->fShortYearNames != NULL && value <= fSymbols->fShortYearNamesCount) {
// the Calendar YEAR field runs 1 through 60 for cyclic years
_appendSymbol(appendTo, value - 1, fSymbols->fShortYearNames, fSymbols->fShortYearNamesCount);
break;
}
}
// else fall through to numeric year handling, do not break here
// OLD: for "yyyy", write out the whole year; for "yy", write out the last 2 digits
@ -1817,12 +1431,24 @@ SimpleDateFormat::subFormat(UnicodeString &appendTo,
case UDAT_TIMEZONE_FIELD:
case UDAT_TIMEZONE_GENERIC_FIELD:
case UDAT_TIMEZONE_SPECIAL_FIELD:
case UDAT_TIMEZONE_RFC_FIELD: // 'Z' - TIMEZONE_RFC
{
UnicodeString zoneString;
const TimeZone& tz = cal.getTimeZone();
UDate date = cal.getTime(status);
if (U_SUCCESS(status)) {
if (patternCharIndex == UDAT_TIMEZONE_FIELD) {
if (patternCharIndex == UDAT_TIMEZONE_RFC_FIELD) {
if (count < 4) {
// "Z"
tzFormat()->format(UTZFMT_STYLE_RFC822, tz, date, zoneString);
} else if (count == 5) {
// "ZZZZZ"
tzFormat()->format(UTZFMT_STYLE_ISO8601, tz, date, zoneString);
} else {
// "ZZ", "ZZZ", "ZZZZ"
tzFormat()->format(UTZFMT_STYLE_LOCALIZED_GMT, tz, date, zoneString);
}
} else if (patternCharIndex == UDAT_TIMEZONE_FIELD) {
if (count < 4) {
// "z", "zz", "zzz"
tzFormat()->format(UTZFMT_STYLE_SPECIFIC_SHORT, tz, date, zoneString);
@ -1849,27 +1475,12 @@ SimpleDateFormat::subFormat(UnicodeString &appendTo,
capContextUsageType = DateFormatSymbols::kCapContextUsageMetazoneShort;
} else if (count == 4) {
// "VVVV"
tzFormat()->format(UTZFMT_STYLE_LOCATION, tz, date, zoneString);
tzFormat()->format(UTZFMT_STYLE_GENERIC_LOCATION, tz, date, zoneString);
capContextUsageType = DateFormatSymbols::kCapContextUsageZoneLong;
}
}
}
if (zoneString.isEmpty()) {
appendGMT(currentNumberFormat,appendTo, cal, status);
} else {
appendTo += zoneString;
}
}
break;
case UDAT_TIMEZONE_RFC_FIELD: // 'Z' - TIMEZONE_RFC
if (count < 4) {
// RFC822 format, must use ASCII digits
value = (cal.get(UCAL_ZONE_OFFSET, status) + cal.get(UCAL_DST_OFFSET, status));
formatRFC822TZ(appendTo, value);
} else {
// long form, localized GMT pattern
appendGMT(currentNumberFormat,appendTo, cal, status);
appendTo += zoneString;
}
break;
@ -1987,7 +1598,7 @@ SimpleDateFormat::parse(const UnicodeString& text, Calendar& cal, ParsePosition&
UBool lenient = isLenient();
// hack, reset tztype, cast away const
((SimpleDateFormat*)this)->tztype = TZTYPE_UNK;
((SimpleDateFormat*)this)->tztype = UTZFMT_TIME_TYPE_UNKNOWN;
// For parsing abutting numeric fields. 'abutPat' is the
// offset into 'pattern' of the first of 2 or more abutting
@ -2189,7 +1800,7 @@ SimpleDateFormat::parse(const UnicodeString& text, Calendar& cal, ParsePosition&
// when the two-digit year is equal to the start year, and thus might fall at the
// front or the back of the default century. This only works because we adjust
// the year correctly to start with in other cases -- see subParse().
if (ambiguousYear[0] || tztype != TZTYPE_UNK) // If this is true then the two-digit year == the default start year
if (ambiguousYear[0] || tztype != UTZFMT_TIME_TYPE_UNKNOWN) // If this is true then the two-digit year == the default start year
{
// We need a copy of the fields, and we need to avoid triggering a call to
// complete(), which will recalculate the fields. Since we can't access
@ -2212,7 +1823,7 @@ SimpleDateFormat::parse(const UnicodeString& text, Calendar& cal, ParsePosition&
delete copy;
}
if (tztype != TZTYPE_UNK) {
if (tztype != UTZFMT_TIME_TYPE_UNKNOWN) {
copy = cal.clone();
// Check for failed cloning.
if (copy == NULL) {
@ -2238,7 +1849,7 @@ SimpleDateFormat::parse(const UnicodeString& text, Calendar& cal, ParsePosition&
// matches the rule used by the parsed time zone.
int32_t raw, dst;
if (btz != NULL) {
if (tztype == TZTYPE_STD) {
if (tztype == UTZFMT_TIME_TYPE_STANDARD) {
btz->getOffsetFromLocal(localMillis,
BasicTimeZone::kStandard, BasicTimeZone::kStandard, raw, dst, status);
} else {
@ -2253,7 +1864,7 @@ SimpleDateFormat::parse(const UnicodeString& text, Calendar& cal, ParsePosition&
// Now, compare the results with parsed type, either standard or daylight saving time
int32_t resolvedSavings = dst;
if (tztype == TZTYPE_STD) {
if (tztype == UTZFMT_TIME_TYPE_STANDARD) {
if (dst != 0) {
// Override DST_OFFSET = 0 in the result calendar
resolvedSavings = 0;
@ -3166,178 +2777,51 @@ int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UC
break;
case UDAT_TIMEZONE_FIELD:
case UDAT_TIMEZONE_RFC_FIELD:
case UDAT_TIMEZONE_GENERIC_FIELD:
case UDAT_TIMEZONE_SPECIAL_FIELD:
{
int32_t offset = 0;
UBool parsed = FALSE;
// Step 1
// Check if this is a long GMT offset string (either localized or default)
offset = parseGMT(text, pos);
if (pos.getIndex() - start > 0) {
parsed = TRUE;
}
if (!parsed) {
// Step 2
// Check if this is an RFC822 time zone offset.
// ICU supports the standard RFC822 format [+|-]HHmm
// and its extended form [+|-]HHmmSS.
do {
int32_t sign = 0;
UChar signChar = text.charAt(start);
if (signChar == (UChar)0x002B /* '+' */) {
sign = 1;
} else if (signChar == (UChar)0x002D /* '-' */) {
sign = -1;
} else {
// Not an RFC822 offset string
break;
}
// Parse digits
int32_t orgPos = start + 1;
pos.setIndex(orgPos);
parseInt(text, number, 6, pos, FALSE,currentNumberFormat);
int32_t numLen = pos.getIndex() - orgPos;
if (numLen <= 0) {
break;
}
// Followings are possible format (excluding sign char)
// HHmmSS
// HmmSS
// HHmm
// Hmm
// HH
// H
int32_t val = number.getLong();
int32_t hour = 0, min = 0, sec = 0;
switch(numLen) {
case 1: // H
case 2: // HH
hour = val;
break;
case 3: // Hmm
case 4: // HHmm
hour = val / 100;
min = val % 100;
break;
case 5: // Hmmss
case 6: // HHmmss
hour = val / 10000;
min = (val % 10000) / 100;
sec = val % 100;
break;
}
if (hour > 23 || min > 59 || sec > 59) {
// Invalid value range
break;
}
offset = (((hour * 60) + min) * 60 + sec) * 1000 * sign;
parsed = TRUE;
} while (FALSE);
if (!parsed) {
// Failed to parse. Reset the position.
pos.setIndex(start);
}
}
if (parsed) {
// offset was successfully parsed as either a long GMT string or RFC822 zone offset
// string. Create normalized zone ID for the offset.
UnicodeString tzID(gGmt);
formatRFC822TZ(tzID, offset);
//TimeZone *customTZ = TimeZone::createTimeZone(tzID);
TimeZone *customTZ = new SimpleTimeZone(offset, tzID); // faster than TimeZone::createTimeZone
cal.adoptTimeZone(customTZ);
UTimeZoneFormatTimeType tzTimeType = UTZFMT_TIME_TYPE_UNKNOWN;
UTimeZoneFormatStyle style = (count < 4) ? UTZFMT_STYLE_SPECIFIC_SHORT : UTZFMT_STYLE_SPECIFIC_LONG;
TimeZone *tz = tzFormat()->parse(style, text, pos, &tzTimeType);
if (tz != NULL) {
((SimpleDateFormat*)this)->tztype = tzTimeType;
cal.adoptTimeZone(tz);
return pos.getIndex();
}
// Step 3
// Is this standalone Localized GMT zero or GMT/UT/UTC?
int32_t gmtLen = 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(UNICODE_STRING("Etc/GMT", 7));
}
break;
case UDAT_TIMEZONE_RFC_FIELD:
{
UTimeZoneFormatTimeType tzTimeType = UTZFMT_TIME_TYPE_UNKNOWN;
UTimeZoneFormatStyle style = (count < 4) ? UTZFMT_STYLE_RFC822 : ((count == 5) ? UTZFMT_STYLE_ISO8601: UTZFMT_STYLE_LOCALIZED_GMT);
TimeZone *tz = tzFormat()->parse(style, text, pos, &tzTimeType);
if (tz != NULL) {
((SimpleDateFormat*)this)->tztype = tzTimeType;
cal.adoptTimeZone(tz);
return start + gmtLen;
return pos.getIndex();
}
// 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, 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;
default:
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(UNICODE_STRING("Etc/GMT", 7));
return -start;
}
case UDAT_TIMEZONE_GENERIC_FIELD:
{
UTimeZoneFormatTimeType tzTimeType = UTZFMT_TIME_TYPE_UNKNOWN;
UTimeZoneFormatStyle style = (count < 4) ? UTZFMT_STYLE_GENERIC_SHORT : UTZFMT_STYLE_GENERIC_LONG;
TimeZone *tz = tzFormat()->parse(style, text, pos, &tzTimeType);
if (tz != NULL) {
((SimpleDateFormat*)this)->tztype = tzTimeType;
cal.adoptTimeZone(tz);
return start + gmtLen;
return pos.getIndex();
}
return -start;
}
case UDAT_TIMEZONE_SPECIAL_FIELD:
{
UTimeZoneFormatTimeType tzTimeType = UTZFMT_TIME_TYPE_UNKNOWN;
UTimeZoneFormatStyle style = (count < 4) ? UTZFMT_STYLE_SPECIFIC_SHORT : UTZFMT_STYLE_GENERIC_LOCATION;
TimeZone *tz = tzFormat()->parse(style, text, pos, &tzTimeType);
if (tz != NULL) {
((SimpleDateFormat*)this)->tztype = tzTimeType;
cal.adoptTimeZone(tz);
return pos.getIndex();
}
// complete failure
return -start;
}
@ -3579,6 +3063,27 @@ SimpleDateFormat::setDateFormatSymbols(const DateFormatSymbols& newFormatSymbols
fSymbols = new DateFormatSymbols(newFormatSymbols);
}
//----------------------------------------------------------------------
const TimeZoneFormat*
SimpleDateFormat::getTimeZoneFormat(void) const {
return (const TimeZoneFormat*)tzFormat();
}
//----------------------------------------------------------------------
void
SimpleDateFormat::adoptTimeZoneFormat(TimeZoneFormat* timeZoneFormatToAdopt)
{
delete fTimeZoneFormat;
fTimeZoneFormat = timeZoneFormatToAdopt;
}
//----------------------------------------------------------------------
void
SimpleDateFormat::setTimeZoneFormat(const TimeZoneFormat& newTimeZoneFormat)
{
delete fTimeZoneFormat;
fTimeZoneFormat = new TimeZoneFormat(newTimeZoneFormat);
}
//----------------------------------------------------------------------
@ -3845,6 +3350,7 @@ SimpleDateFormat::tzFormat() const {
}
return fTimeZoneFormat;
}
U_NAMESPACE_END
#endif /* #if !UCONFIG_NO_FORMATTING */

View file

@ -1,6 +1,6 @@
/*
*******************************************************************************
* Copyright (C) 1997-2011, International Business Machines Corporation and *
* Copyright (C) 1997-2012, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*
@ -68,10 +68,11 @@ static char gStrBuf[256];
#if !UCONFIG_NO_FORMATTING
#include "unicode/simpletz.h"
#include "unicode/smpdtfmt.h"
#include "unicode/calendar.h"
#include "unicode/gregocal.h"
#include "unicode/ures.h"
#include "unicode/tzfmt.h"
#include "unicode/numfmt.h"
#include "gregoimp.h"
#include "uresimp.h" // struct UResourceBundle
#include "olsontz.h"
@ -1238,127 +1239,75 @@ TimeZone::getDSTSavings()const {
UnicodeString&
TimeZone::getDisplayName(UBool daylight, EDisplayType style, const Locale& locale, UnicodeString& result) const
{
// SRL TODO: cache the SDF, just like java.
UErrorCode status = U_ZERO_ERROR;
#ifdef U_DEBUG_TZ
char buf[128];
fID.extract(0, sizeof(buf)-1, buf, sizeof(buf), "");
#endif
UDate date = Calendar::getNow();
UTimeZoneFormatTimeType timeType;
int32_t offset;
// select the proper format string
const UChar* patUChars;
switch(style){
case LONG:
patUChars = ZZZZ_STR;
break;
case SHORT_GENERIC:
patUChars = V_STR;
break;
case LONG_GENERIC:
patUChars = VVVV_STR;
break;
case SHORT_GMT:
patUChars = Z_UC_STR;
break;
case LONG_GMT:
patUChars = ZZZZ_UC_STR;
break;
case SHORT_COMMONLY_USED:
//patUChars = V_UC_STR;
patUChars = Z_STR;
break;
case GENERIC_LOCATION:
patUChars = VVVV_UC_STR;
break;
default: // SHORT
//patUChars = Z_STR;
patUChars = V_UC_STR;
break;
}
UnicodeString pat(TRUE, patUChars, -1);
SimpleDateFormat format(pat, locale, status);
U_DEBUG_TZ_MSG(("getDisplayName(%s)\n", buf));
if(!U_SUCCESS(status))
{
#ifdef U_DEBUG_TZ
char buf2[128];
result.extract(0, sizeof(buf2)-1, buf2, sizeof(buf2), "");
U_DEBUG_TZ_MSG(("getDisplayName(%s) -> %s\n", buf, buf2));
#endif
return result.remove();
}
UDate d = Calendar::getNow();
int32_t rawOffset;
int32_t dstOffset;
this->getOffset(d, FALSE, rawOffset, dstOffset, status);
if (U_FAILURE(status)) {
return result.remove();
}
if ((daylight && dstOffset != 0) ||
(!daylight && dstOffset == 0) ||
(style == SHORT_GENERIC) ||
(style == LONG_GENERIC)
) {
// Current time and the request (daylight / not daylight) agree.
format.setTimeZone(*this);
return format.format(d, result);
}
// Create a new SimpleTimeZone as a stand-in for this zone; the
// stand-in will have no DST, or DST during July, but the same ID and offset,
// and hence the same display name.
// We don't cache these because they're small and cheap to create.
UnicodeString tempID;
getID(tempID);
SimpleTimeZone *tz = NULL;
if(daylight && useDaylightTime()){
// The display name for daylight saving time was requested, but currently not in DST
// Set a fixed date (July 1) in this Gregorian year
GregorianCalendar cal(*this, status);
if (U_FAILURE(status)) {
return result.remove();
if (style == GENERIC_LOCATION || style == LONG_GENERIC || style == SHORT_GENERIC) {
LocalPointer<TimeZoneFormat> tzfmt(TimeZoneFormat::createInstance(locale, status));
// Generic format
switch (style) {
case GENERIC_LOCATION:
tzfmt->format(UTZFMT_STYLE_GENERIC_LOCATION, *this, date, result, &timeType);
break;
case LONG_GENERIC:
tzfmt->format(UTZFMT_STYLE_GENERIC_LONG, *this, date, result, &timeType);
break;
case SHORT_GENERIC:
tzfmt->format(UTZFMT_STYLE_GENERIC_SHORT, *this, date, result, &timeType);
break;
default:
U_ASSERT(FALSE);
}
cal.set(UCAL_MONTH, UCAL_JULY);
cal.set(UCAL_DATE, 1);
// Get July 1 date
d = cal.getTime(status);
// Check if it is in DST
if (cal.get(UCAL_DST_OFFSET, status) == 0) {
// We need to create a fake time zone
tz = new SimpleTimeZone(rawOffset, tempID,
UCAL_JUNE, 1, 0, 0,
UCAL_AUGUST, 1, 0, 0,
getDSTSavings(), status);
if (U_FAILURE(status) || tz == NULL) {
if (U_SUCCESS(status)) {
status = U_MEMORY_ALLOCATION_ERROR;
}
return result.remove();
}
format.adoptTimeZone(tz);
} else {
format.setTimeZone(*this);
// Generic format many use Localized GMT as the final fallback.
// When Localized GMT format is used, the result might not be
// appropriate for the requested daylight value.
if ((daylight && timeType == UTZFMT_TIME_TYPE_STANDARD) || (!daylight && timeType == UTZFMT_TIME_TYPE_DAYLIGHT)) {
offset = daylight ? getRawOffset() + getDSTSavings() : getRawOffset();
tzfmt->formatOffsetLocalizedGMT(offset, result, status);
}
} else if (style == LONG_GMT || style == SHORT_GMT) {
LocalPointer<TimeZoneFormat> tzfmt(TimeZoneFormat::createInstance(locale, status));
offset = daylight && useDaylightTime() ? getRawOffset() + getDSTSavings() : getRawOffset();
switch (style) {
case LONG_GMT:
tzfmt->formatOffsetLocalizedGMT(offset, result, status);
break;
case SHORT_GMT:
tzfmt->formatOffsetRFC822(offset, result, status);
break;
default:
U_ASSERT(FALSE);
}
} else {
// The display name for standard time was requested, but currently in DST
// or display name for daylight saving time was requested, but this zone no longer
// observes DST.
tz = new SimpleTimeZone(rawOffset, tempID);
if (U_FAILURE(status) || tz == NULL) {
if (U_SUCCESS(status)) {
status = U_MEMORY_ALLOCATION_ERROR;
}
return result.remove();
U_ASSERT(style == LONG || style == SHORT || style == SHORT_COMMONLY_USED);
UTimeZoneNameType nameType = UTZNM_UNKNOWN;
switch (style) {
case LONG:
nameType = daylight ? UTZNM_LONG_DAYLIGHT : UTZNM_LONG_STANDARD;
break;
case SHORT:
case SHORT_COMMONLY_USED:
nameType = daylight ? UTZNM_SHORT_DAYLIGHT : UTZNM_SHORT_STANDARD;
break;
default:
U_ASSERT(FALSE);
}
LocalPointer<TimeZoneNames> tznames(TimeZoneNames::createInstance(locale, status));
UnicodeString canonicalID(ZoneMeta::getCanonicalCLDRID(*this));
tznames->getDisplayName(canonicalID, nameType, date, result);
if (result.isEmpty()) {
// Fallback to localized GMT
LocalPointer<TimeZoneFormat> tzfmt(TimeZoneFormat::createInstance(locale, status));
offset = daylight && useDaylightTime() ? getRawOffset() + getDSTSavings() : getRawOffset();
tzfmt->formatOffsetLocalizedGMT(offset, result, status);
}
format.adoptTimeZone(tz);
}
format.format(d, result, status);
if (U_FAILURE(status)) {
result.remove();
}
return result;
}

File diff suppressed because it is too large Load diff

View file

@ -1,64 +0,0 @@
/*
*******************************************************************************
* 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
} 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

View file

@ -1,6 +1,6 @@
/*
*******************************************************************************
* Copyright (C) 2012, International Business Machines Corporation and
* Copyright (C) 2011-2012, International Business Machines Corporation and
* others. All Rights Reserved.
*******************************************************************************
*/
@ -28,6 +28,7 @@
#include "zonemeta.h"
#include "tznames_impl.h"
#include "olsontz.h"
#include "ucln_in.h"
U_NAMESPACE_BEGIN
@ -112,7 +113,7 @@ typedef struct GNameInfo {
typedef struct GMatchInfo {
const GNameInfo* gnameInfo;
int32_t matchLength;
UTimeZoneTimeType timeType;
UTimeZoneFormatTimeType timeType;
} ZMatchInfo;
U_CDECL_END
@ -120,6 +121,20 @@ U_CDECL_END
// ---------------------------------------------------
// The class stores time zone generic name match information
// ---------------------------------------------------
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
};
TimeZoneGenericNameMatchInfo::TimeZoneGenericNameMatchInfo(UVector* matches)
: fMatches(matches) {
}
@ -252,14 +267,69 @@ GNameSearchHandler::getMatches(int32_t& maxMatchLen) {
return results;
}
class TZGNCore : public UMemory {
public:
TZGNCore(const Locale& locale, UErrorCode& status);
virtual ~TZGNCore();
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, UTimeZoneFormatTimeType& 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;
TimeZoneNames::MatchInfoCollection* findTimeZoneNames(const UnicodeString& text, int32_t start, uint32_t types, UErrorCode& status) const;
};
// ---------------------------------------------------
// TimeZoneGenericNames
// TZGNCore - core implmentation of TimeZoneGenericNames
//
// TimeZoneGenericNames is parallel to TimeZoneNames,
// but handles run-time generated time zone names.
// This is the main part of this module.
// ---------------------------------------------------
TimeZoneGenericNames::TimeZoneGenericNames(const Locale& locale, UErrorCode& status)
TZGNCore::TZGNCore(const Locale& locale, UErrorCode& status)
: fLocale(locale),
fLock(NULL),
fTimeZoneNames(NULL),
@ -275,13 +345,13 @@ TimeZoneGenericNames::TimeZoneGenericNames(const Locale& locale, UErrorCode& sta
initialize(locale, status);
}
TimeZoneGenericNames::~TimeZoneGenericNames() {
TZGNCore::~TZGNCore() {
cleanup();
umtx_destroy(&fLock);
}
void
TimeZoneGenericNames::initialize(const Locale& locale, UErrorCode& status) {
TZGNCore::initialize(const Locale& locale, UErrorCode& status) {
if (U_FAILURE(status)) {
return;
}
@ -384,7 +454,7 @@ TimeZoneGenericNames::initialize(const Locale& locale, UErrorCode& status) {
}
void
TimeZoneGenericNames::cleanup() {
TZGNCore::cleanup() {
if (fRegionFormat != NULL) {
delete fRegionFormat;
}
@ -405,8 +475,9 @@ TimeZoneGenericNames::cleanup() {
uhash_close(fPartialLocationNamesMap);
}
UnicodeString&
TimeZoneGenericNames::getDisplayName(const TimeZone& tz, UTimeZoneGenericNameType type, UDate date, UnicodeString& name) const {
TZGNCore::getDisplayName(const TimeZone& tz, UTimeZoneGenericNameType type, UDate date, UnicodeString& name) const {
name.setToBogus();
switch (type) {
case UTZGNM_LOCATION:
@ -434,14 +505,14 @@ TimeZoneGenericNames::getDisplayName(const TimeZone& tz, UTimeZoneGenericNameTyp
}
UnicodeString&
TimeZoneGenericNames::getGenericLocationName(const UnicodeString& tzCanonicalID, UnicodeString& name) const {
TZGNCore::getGenericLocationName(const UnicodeString& tzCanonicalID, UnicodeString& name) const {
if (tzCanonicalID.isEmpty()) {
name.setToBogus();
return name;
}
const UChar *locname = NULL;
TimeZoneGenericNames *nonConstThis = const_cast<TimeZoneGenericNames *>(this);
TZGNCore *nonConstThis = const_cast<TZGNCore *>(this);
umtx_lock(&nonConstThis->fLock);
{
locname = nonConstThis->getGenericLocationName(tzCanonicalID);
@ -451,7 +522,7 @@ TimeZoneGenericNames::getGenericLocationName(const UnicodeString& tzCanonicalID,
if (locname == NULL) {
name.setToBogus();
} else {
name.setTo(TRUE, locname, -1);
name.setTo(locname, u_strlen(locname));
}
return name;
@ -461,7 +532,7 @@ TimeZoneGenericNames::getGenericLocationName(const UnicodeString& tzCanonicalID,
* This method updates the cache and must be called with a lock
*/
const UChar*
TimeZoneGenericNames::getGenericLocationName(const UnicodeString& tzCanonicalID) {
TZGNCore::getGenericLocationName(const UnicodeString& tzCanonicalID) {
U_ASSERT(!tzCanonicalID.isEmpty());
if (tzCanonicalID.length() > ZID_KEY_MAX) {
return NULL;
@ -556,7 +627,7 @@ TimeZoneGenericNames::getGenericLocationName(const UnicodeString& tzCanonicalID)
}
UnicodeString&
TimeZoneGenericNames::formatGenericNonLocationName(const TimeZone& tz, UTimeZoneGenericNameType type, UDate date, UnicodeString& name) const {
TZGNCore::formatGenericNonLocationName(const TimeZone& tz, UTimeZoneGenericNameType type, UDate date, UnicodeString& name) const {
U_ASSERT(type == UTZGNM_LONG || type == UTZGNM_SHORT);
name.setToBogus();
@ -694,7 +765,7 @@ TimeZoneGenericNames::formatGenericNonLocationName(const TimeZone& tz, UTimeZone
}
UnicodeString&
TimeZoneGenericNames::getPartialLocationName(const UnicodeString& tzCanonicalID,
TZGNCore::getPartialLocationName(const UnicodeString& tzCanonicalID,
const UnicodeString& mzID, UBool isLong, const UnicodeString& mzDisplayName,
UnicodeString& name) const {
name.setToBogus();
@ -703,7 +774,7 @@ TimeZoneGenericNames::getPartialLocationName(const UnicodeString& tzCanonicalID,
}
const UChar *uplname = NULL;
TimeZoneGenericNames *nonConstThis = const_cast<TimeZoneGenericNames *>(this);
TZGNCore *nonConstThis = const_cast<TZGNCore *>(this);
umtx_lock(&nonConstThis->fLock);
{
uplname = nonConstThis->getPartialLocationName(tzCanonicalID, mzID, isLong, mzDisplayName);
@ -722,7 +793,7 @@ TimeZoneGenericNames::getPartialLocationName(const UnicodeString& tzCanonicalID,
* This method updates the cache and must be called with a lock
*/
const UChar*
TimeZoneGenericNames::getPartialLocationName(const UnicodeString& tzCanonicalID,
TZGNCore::getPartialLocationName(const UnicodeString& tzCanonicalID,
const UnicodeString& mzID, UBool isLong, const UnicodeString& mzDisplayName) {
U_ASSERT(!tzCanonicalID.isEmpty());
U_ASSERT(!mzID.isEmpty());
@ -810,7 +881,7 @@ TimeZoneGenericNames::getPartialLocationName(const UnicodeString& tzCanonicalID,
* except initializer.
*/
void
TimeZoneGenericNames::loadStrings(const UnicodeString& tzCanonicalID) {
TZGNCore::loadStrings(const UnicodeString& tzCanonicalID) {
// load the generic location name
getGenericLocationName(tzCanonicalID);
@ -851,8 +922,8 @@ TimeZoneGenericNames::loadStrings(const UnicodeString& tzCanonicalID) {
}
int32_t
TimeZoneGenericNames::findBestMatch(const UnicodeString& text, int32_t start, uint32_t types,
UnicodeString& tzID, UTimeZoneTimeType& timeType, UErrorCode& status) const {
TZGNCore::findBestMatch(const UnicodeString& text, int32_t start, uint32_t types,
UnicodeString& tzID, UTimeZoneFormatTimeType& timeType, UErrorCode& status) const {
timeType = UTZFMT_TIME_TYPE_UNKNOWN;
tzID.setToBogus();
@ -861,13 +932,13 @@ TimeZoneGenericNames::findBestMatch(const UnicodeString& text, int32_t start, ui
}
// Find matches in the TimeZoneNames first
TimeZoneNameMatchInfo *tznamesMatches = findTimeZoneNames(text, start, types, status);
TimeZoneNames::MatchInfoCollection *tznamesMatches = findTimeZoneNames(text, start, types, status);
if (U_FAILURE(status)) {
return 0;
}
int32_t bestMatchLen = 0;
UTimeZoneTimeType bestMatchTimeType = UTZFMT_TIME_TYPE_UNKNOWN;
UTimeZoneFormatTimeType bestMatchTimeType = UTZFMT_TIME_TYPE_UNKNOWN;
UnicodeString bestMatchTzID;
// UBool isLongStandard = FALSE; // workaround - see the comments below
UBool isStandard = FALSE; // TODO: Temporary hack (on hack) for short standard name/location name conflict (found in zh_Hant), should be removed after CLDR 21m1 integration
@ -875,17 +946,19 @@ TimeZoneGenericNames::findBestMatch(const UnicodeString& text, int32_t start, ui
if (tznamesMatches != NULL) {
UnicodeString mzID;
for (int32_t i = 0; i < tznamesMatches->size(); i++) {
int32_t len = tznamesMatches->getMatchLength(i);
int32_t len = tznamesMatches->getMatchLengthAt(i);
if (len > bestMatchLen) {
bestMatchLen = len;
tznamesMatches->getTimeZoneID(i, bestMatchTzID);
if (bestMatchTzID.isEmpty()) {
if (!tznamesMatches->getTimeZoneIDAt(i, bestMatchTzID)) {
// name for a meta zone
tznamesMatches->getMetaZoneID(i, mzID);
U_ASSERT(mzID.length() > 0);
fTimeZoneNames->getReferenceZoneID(mzID, fTargetRegion, bestMatchTzID);
if (tznamesMatches->getMetaZoneIDAt(i, mzID)) {
fTimeZoneNames->getReferenceZoneID(mzID, fTargetRegion, bestMatchTzID);
}
}
UTimeZoneNameType nameType = tznamesMatches->getNameTypeAt(i);
if (U_FAILURE(status)) {
break;
}
UTimeZoneNameType nameType = tznamesMatches->getNameType(i);
switch (nameType) {
case UTZNM_LONG_STANDARD:
// isLongStandard = TRUE;
@ -903,6 +976,9 @@ TimeZoneGenericNames::findBestMatch(const UnicodeString& text, int32_t start, ui
}
}
delete tznamesMatches;
if (U_FAILURE(status)) {
return 0;
}
if (bestMatchLen == (text.length() - start)) {
// Full match
@ -967,10 +1043,10 @@ TimeZoneGenericNames::findBestMatch(const UnicodeString& text, int32_t start, ui
}
TimeZoneGenericNameMatchInfo*
TimeZoneGenericNames::findLocal(const UnicodeString& text, int32_t start, uint32_t types, UErrorCode& status) const {
TZGNCore::findLocal(const UnicodeString& text, int32_t start, uint32_t types, UErrorCode& status) const {
GNameSearchHandler handler(types);
TimeZoneGenericNames *nonConstThis = const_cast<TimeZoneGenericNames *>(this);
TZGNCore *nonConstThis = const_cast<TZGNCore *>(this);
umtx_lock(&nonConstThis->fLock);
{
@ -1051,10 +1127,8 @@ TimeZoneGenericNames::findLocal(const UnicodeString& text, int32_t start, uint32
return gmatchInfo;
}
TimeZoneNameMatchInfo*
TimeZoneGenericNames::findTimeZoneNames(const UnicodeString& text, int32_t start, uint32_t types, UErrorCode& status) const {
TimeZoneNameMatchInfo *matchInfo = NULL;
TimeZoneNames::MatchInfoCollection*
TZGNCore::findTimeZoneNames(const UnicodeString& text, int32_t start, uint32_t types, UErrorCode& status) const {
// Check if the target name typs is really in the TimeZoneNames
uint32_t nameTypes = 0;
if (types & UTZGNM_LONG) {
@ -1066,10 +1140,236 @@ TimeZoneGenericNames::findTimeZoneNames(const UnicodeString& text, int32_t start
if (types) {
// Find matches in the TimeZoneNames
matchInfo = fTimeZoneNames->find(text, start, nameTypes, status);
return fTimeZoneNames->find(text, start, nameTypes, status);
}
return matchInfo;
return NULL;
}
typedef struct TZGNCoreRef {
TZGNCore* obj;
int32_t refCount;
double lastAccess;
} TZGNCoreRef;
// TZGNCore object cache handling
static UMTX gTZGNLock = NULL;
static UHashtable *gTZGNCoreCache = NULL;
static UBool gTZGNCoreCacheInitialized = 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
U_CDECL_BEGIN
/**
* Cleanup callback func
*/
static UBool U_CALLCONV tzgnCore_cleanup(void)
{
umtx_destroy(&gTZGNLock);
if (gTZGNCoreCache != NULL) {
uhash_close(gTZGNCoreCache);
gTZGNCoreCache = NULL;
}
gTZGNCoreCacheInitialized = FALSE;
return TRUE;
}
/**
* Deleter for TZGNCoreRef
*/
static void U_CALLCONV
deleteTZGNCoreRef(void *obj) {
icu::TZGNCoreRef *entry = (icu::TZGNCoreRef*)obj;
delete (icu::TZGNCore*) entry->obj;
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(gTZGNCoreCache, &pos))) {
TZGNCoreRef *entry = (TZGNCoreRef *)elem->value.pointer;
if (entry->refCount <= 0 && (now - entry->lastAccess) > CACHE_EXPIRATION) {
// delete this entry
uhash_removeElement(gTZGNCoreCache, elem);
}
}
}
TimeZoneGenericNames::TimeZoneGenericNames()
: fRef(0) {
}
TimeZoneGenericNames::~TimeZoneGenericNames() {
umtx_lock(&gTZGNLock);
{
U_ASSERT(fRef->refCount > 0);
// Just decrement the reference count
fRef->refCount--;
}
umtx_unlock(&gTZGNLock);
}
TimeZoneGenericNames*
TimeZoneGenericNames::createInstance(const Locale& locale, UErrorCode& status) {
if (U_FAILURE(status)) {
return NULL;
}
TimeZoneGenericNames* instance = new TimeZoneGenericNames();
if (instance == NULL) {
status = U_MEMORY_ALLOCATION_ERROR;
return NULL;
}
UBool initialized;
UMTX_CHECK(&gTZGNLock, gTZGNCoreCacheInitialized, initialized);
if (!initialized) {
// Create empty hashtable
umtx_lock(&gTZGNLock);
{
if (!gTZGNCoreCacheInitialized) {
gTZGNCoreCache = uhash_open(uhash_hashChars, uhash_compareChars, NULL, &status);
if (U_SUCCESS(status)) {
uhash_setKeyDeleter(gTZGNCoreCache, uprv_free);
uhash_setValueDeleter(gTZGNCoreCache, deleteTZGNCoreRef);
gTZGNCoreCacheInitialized = TRUE;
ucln_i18n_registerCleanup(UCLN_I18N_TIMEZONEGENERICNAMES, tzgnCore_cleanup);
}
}
}
umtx_unlock(&gTZGNLock);
if (U_FAILURE(status)) {
return NULL;
}
}
// Check the cache, if not available, create new one and cache
TZGNCoreRef *cacheEntry = NULL;
umtx_lock(&gTZGNLock);
{
const char *key = locale.getName();
cacheEntry = (TZGNCoreRef *)uhash_get(gTZGNCoreCache, key);
if (cacheEntry == NULL) {
TZGNCore *tzgnCore = NULL;
char *newKey = NULL;
tzgnCore = new TZGNCore(locale, status);
if (tzgnCore == 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 = (TZGNCoreRef *)uprv_malloc(sizeof(TZGNCoreRef));
if (cacheEntry == NULL) {
status = U_MEMORY_ALLOCATION_ERROR;
} else {
cacheEntry->obj = tzgnCore;
cacheEntry->refCount = 1;
cacheEntry->lastAccess = (double)uprv_getUTCtime();
uhash_put(gTZGNCoreCache, newKey, cacheEntry, &status);
}
}
if (U_FAILURE(status)) {
if (tzgnCore != NULL) {
delete tzgnCore;
}
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(&gTZGNLock);
if (cacheEntry == NULL) {
delete instance;
return NULL;
}
instance->fRef = cacheEntry;
return instance;
}
UBool
TimeZoneGenericNames::operator==(const TimeZoneGenericNames& other) const {
// Just compare if the other object also use the same
// ref entry
return fRef == other.fRef;
}
TimeZoneGenericNames*
TimeZoneGenericNames::clone() const {
TimeZoneGenericNames* other = new TimeZoneGenericNames();
if (other) {
umtx_lock(&gTZGNLock);
{
// Just increments the reference count
fRef->refCount++;
other->fRef = fRef;
}
umtx_unlock(&gTZGNLock);
}
return other;
}
UnicodeString&
TimeZoneGenericNames::getDisplayName(const TimeZone& tz, UTimeZoneGenericNameType type,
UDate date, UnicodeString& name) const {
return fRef->obj->getDisplayName(tz, type, date, name);
}
UnicodeString&
TimeZoneGenericNames::getGenericLocationName(const UnicodeString& tzCanonicalID, UnicodeString& name) const {
return fRef->obj->getGenericLocationName(tzCanonicalID, name);
}
int32_t
TimeZoneGenericNames::findBestMatch(const UnicodeString& text, int32_t start, uint32_t types,
UnicodeString& tzID, UTimeZoneFormatTimeType& timeType, UErrorCode& status) const {
return fRef->obj->findBestMatch(text, start, types, tzID, timeType, status);
}
U_NAMESPACE_END

View file

@ -1,6 +1,6 @@
/*
*******************************************************************************
* Copyright (C) 2011, International Business Machines Corporation and *
* Copyright (C) 2011-2012, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*/
@ -17,13 +17,9 @@
#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"
#include "unicode/tzfmt.h"
#include "unicode/tznames.h"
U_CDECL_BEGIN
@ -38,76 +34,30 @@ 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
};
struct TZGNCoreRef;
class U_I18N_API TimeZoneGenericNames : public UMemory {
public:
TimeZoneGenericNames(const Locale& locale, UErrorCode& status);
virtual ~TimeZoneGenericNames();
static TimeZoneGenericNames* createInstance(const Locale& locale, UErrorCode& status);
virtual UBool operator==(const TimeZoneGenericNames& other) const;
virtual UBool operator!=(const TimeZoneGenericNames& other) const {return !operator==(other);};
virtual TimeZoneGenericNames* clone() const;
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;
UnicodeString& tzID, UTimeZoneFormatTimeType& 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;
TimeZoneGenericNames();
TZGNCoreRef* fRef;
};
U_NAMESPACE_END

View file

@ -1,6 +1,6 @@
/*
*******************************************************************************
* Copyright (C) 2011, International Business Machines Corporation and *
* Copyright (C) 2011-2012, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*/
@ -9,18 +9,18 @@
#if !UCONFIG_NO_FORMATTING
#include "tznames.h"
#include "tznames_impl.h"
#include "unicode/locid.h"
#include "unicode/tznames.h"
#include "unicode/uenum.h"
#include "cmemory.h"
#include "cstring.h"
#include "putilimp.h"
#include "tznames_impl.h"
#include "uassert.h"
#include "ucln_in.h"
#include "uhash.h"
#include "umutex.h"
#include "uvector.h"
U_NAMESPACE_BEGIN
@ -102,14 +102,18 @@ static void sweepCache() {
}
}
TimeZoneNameMatchInfo::~TimeZoneNameMatchInfo() {
}
// ---------------------------------------------------
// TimeZoneNamesDelegate
// ---------------------------------------------------
class TimeZoneNamesDelegate : public TimeZoneNames {
public:
TimeZoneNamesDelegate(const Locale& locale, UErrorCode& status);
virtual ~TimeZoneNamesDelegate();
virtual UBool operator==(const TimeZoneNames& other) const;
virtual UBool operator!=(const TimeZoneNames& other) const {return !operator==(other);};
virtual TimeZoneNames* clone() const;
StringEnumeration* getAvailableMetaZoneIDs(UErrorCode& status) const;
StringEnumeration* getAvailableMetaZoneIDs(const UnicodeString& tzID, UErrorCode& status) const;
UnicodeString& getMetaZoneID(const UnicodeString& tzID, UDate date, UnicodeString& mzID) const;
@ -120,11 +124,16 @@ public:
UnicodeString& getExemplarLocationName(const UnicodeString& tzID, UnicodeString& name) const;
TimeZoneNameMatchInfo* find(const UnicodeString& text, int32_t start, uint32_t types, UErrorCode& status) const;
MatchInfoCollection* find(const UnicodeString& text, int32_t start, uint32_t types, UErrorCode& status) const;
private:
TimeZoneNamesDelegate();
TimeZoneNamesCacheEntry* fTZnamesCacheEntry;
};
TimeZoneNamesDelegate::TimeZoneNamesDelegate()
: fTZnamesCacheEntry(0) {
}
TimeZoneNamesDelegate::TimeZoneNamesDelegate(const Locale& locale, UErrorCode& status) {
UBool initialized;
UMTX_CHECK(&gTimeZoneNamesLock, gTimeZoneNamesCacheInitialized, initialized);
@ -215,13 +224,44 @@ TimeZoneNamesDelegate::TimeZoneNamesDelegate(const Locale& locale, UErrorCode& s
TimeZoneNamesDelegate::~TimeZoneNamesDelegate() {
umtx_lock(&gTimeZoneNamesLock);
{
U_ASSERT(fTZnamesCacheEntry->refCount > 0);
// Just decrement the reference count
fTZnamesCacheEntry->refCount--;
if (fTZnamesCacheEntry) {
U_ASSERT(fTZnamesCacheEntry->refCount > 0);
// Just decrement the reference count
fTZnamesCacheEntry->refCount--;
}
}
umtx_unlock(&gTimeZoneNamesLock);
}
UBool
TimeZoneNamesDelegate::operator==(const TimeZoneNames& other) const {
if (this == &other) {
return TRUE;
}
// Just compare if the other object also use the same
// cache entry
const TimeZoneNamesDelegate* rhs = dynamic_cast<const TimeZoneNamesDelegate*>(&other);
if (rhs) {
return fTZnamesCacheEntry == rhs->fTZnamesCacheEntry;
}
return FALSE;
}
TimeZoneNames*
TimeZoneNamesDelegate::clone() const {
TimeZoneNamesDelegate* other = new TimeZoneNamesDelegate();
if (other != NULL) {
umtx_lock(&gTimeZoneNamesLock);
{
// Just increment the reference count
fTZnamesCacheEntry->refCount++;
other->fTZnamesCacheEntry = fTZnamesCacheEntry;
}
umtx_unlock(&gTimeZoneNamesLock);
}
return other;
}
StringEnumeration*
TimeZoneNamesDelegate::getAvailableMetaZoneIDs(UErrorCode& status) const {
return fTZnamesCacheEntry->names->getAvailableMetaZoneIDs(status);
@ -257,12 +297,15 @@ TimeZoneNamesDelegate::getExemplarLocationName(const UnicodeString& tzID, Unicod
return fTZnamesCacheEntry->names->getExemplarLocationName(tzID, name);
}
TimeZoneNameMatchInfo*
TimeZoneNames::MatchInfoCollection*
TimeZoneNamesDelegate::find(const UnicodeString& text, int32_t start, uint32_t types, UErrorCode& status) const {
return fTZnamesCacheEntry->names->find(text, start, types, status);
}
// ---------------------------------------------------
// TimeZoneNames base class
// ---------------------------------------------------
UOBJECT_DEFINE_NO_RTTI_IMPLEMENTATION(TimeZoneNames)
TimeZoneNames::~TimeZoneNames() {
}
@ -302,5 +345,146 @@ TimeZoneNames::getDisplayName(const UnicodeString& tzID, UTimeZoneNameType type,
return name;
}
struct MatchInfo : UMemory {
UTimeZoneNameType nameType;
UnicodeString id;
int32_t matchLength;
UBool isTZID;
MatchInfo(UTimeZoneNameType nameType, int32_t matchLength, const UnicodeString* tzID, const UnicodeString* mzID) {
this->nameType = nameType;
this->matchLength = matchLength;
if (tzID != NULL) {
this->id.setTo(*tzID);
this->isTZID = TRUE;
} else {
this->id.setTo(*mzID);
this->isTZID = FALSE;
}
}
};
U_CDECL_BEGIN
static void U_CALLCONV
deleteMatchInfo(void *obj) {
delete static_cast<MatchInfo *>(obj);
}
U_CDECL_END
// ---------------------------------------------------
// MatchInfoCollection class
// ---------------------------------------------------
TimeZoneNames::MatchInfoCollection::MatchInfoCollection()
: fMatches(NULL) {
}
TimeZoneNames::MatchInfoCollection::~MatchInfoCollection() {
if (fMatches != NULL) {
delete fMatches;
}
}
void
TimeZoneNames::MatchInfoCollection::addZone(UTimeZoneNameType nameType, int32_t matchLength,
const UnicodeString& tzID, UErrorCode& status) {
if (U_FAILURE(status)) {
return;
}
MatchInfo* matchInfo = new MatchInfo(nameType, matchLength, &tzID, NULL);
if (matchInfo == NULL) {
status = U_MEMORY_ALLOCATION_ERROR;
return;
}
matches(status)->addElement(matchInfo, status);
if (U_FAILURE(status)) {
delete matchInfo;
}
}
void
TimeZoneNames::MatchInfoCollection::addMetaZone(UTimeZoneNameType nameType, int32_t matchLength,
const UnicodeString& mzID, UErrorCode& status) {
if (U_FAILURE(status)) {
return;
}
MatchInfo* matchInfo = new MatchInfo(nameType, matchLength, NULL, &mzID);
if (matchInfo == NULL) {
status = U_MEMORY_ALLOCATION_ERROR;
return;
}
matches(status)->addElement(matchInfo, status);
if (U_FAILURE(status)) {
delete matchInfo;
}
}
int32_t
TimeZoneNames::MatchInfoCollection::size() const {
if (fMatches == NULL) {
return 0;
}
return fMatches->size();
}
UTimeZoneNameType
TimeZoneNames::MatchInfoCollection::getNameTypeAt(int32_t idx) const {
const MatchInfo* match = (const MatchInfo*)fMatches->elementAt(idx);
if (match) {
return match->nameType;
}
return UTZNM_UNKNOWN;
}
int32_t
TimeZoneNames::MatchInfoCollection::getMatchLengthAt(int32_t idx) const {
const MatchInfo* match = (const MatchInfo*)fMatches->elementAt(idx);
if (match) {
return match->matchLength;
}
return 0;
}
UBool
TimeZoneNames::MatchInfoCollection::getTimeZoneIDAt(int32_t idx, UnicodeString& tzID) const {
tzID.remove();
const MatchInfo* match = (const MatchInfo*)fMatches->elementAt(idx);
if (match && match->isTZID) {
tzID.setTo(match->id);
return TRUE;
}
return FALSE;
}
UBool
TimeZoneNames::MatchInfoCollection::getMetaZoneIDAt(int32_t idx, UnicodeString& mzID) const {
mzID.remove();
const MatchInfo* match = (const MatchInfo*)fMatches->elementAt(idx);
if (match && !match->isTZID) {
mzID.setTo(match->id);
return TRUE;
}
return FALSE;
}
UVector*
TimeZoneNames::MatchInfoCollection::matches(UErrorCode& status) {
if (U_FAILURE(status)) {
return NULL;
}
if (fMatches != NULL) {
return fMatches;
}
fMatches = new UVector(deleteMatchInfo, NULL, status);
if (fMatches == NULL) {
status = U_MEMORY_ALLOCATION_ERROR;
} else if (U_FAILURE(status)) {
delete fMatches;
fMatches = NULL;
}
return fMatches;
}
U_NAMESPACE_END
#endif

View file

@ -1,71 +0,0 @@
/*
*******************************************************************************
* 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
} 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;
};
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;
};
U_NAMESPACE_END
#endif
#endif

View file

@ -1,6 +1,6 @@
/*
*******************************************************************************
* Copyright (C) 2011, International Business Machines Corporation and
* Copyright (C) 2011-2012, International Business Machines Corporation and
* others. All Rights Reserved.
*******************************************************************************
*
@ -52,7 +52,7 @@ static const UTimeZoneNameType ALL_NAME_TYPES[] = {
#define DEFAULT_CHARACTERNODE_CAPACITY 1
// ---------------------------------------------------
// CaracterNode class implementation
// CharacterNode class implementation
// ---------------------------------------------------
void CharacterNode::clear() {
uprv_memset(this, 0, sizeof(*this));
@ -722,81 +722,6 @@ typedef struct ZMatchInfo {
} ZMatchInfo;
U_CDECL_END
// ---------------------------------------------------
// The class stores time zone name match information
// ---------------------------------------------------
class TimeZoneNameMatchInfoImpl : public TimeZoneNameMatchInfo {
public:
TimeZoneNameMatchInfoImpl(UVector* matches);
~TimeZoneNameMatchInfoImpl();
int32_t size() const;
UTimeZoneNameType getNameType(int32_t index) const;
int32_t getMatchLength(int32_t index) const;
UnicodeString& getTimeZoneID(int32_t index, UnicodeString& tzID) const;
UnicodeString& getMetaZoneID(int32_t index, UnicodeString& mzID) const;
private:
UVector* fMatches; // vector of MatchEntry
};
TimeZoneNameMatchInfoImpl::TimeZoneNameMatchInfoImpl(UVector* matches)
: fMatches(matches) {
}
TimeZoneNameMatchInfoImpl::~TimeZoneNameMatchInfoImpl() {
if (fMatches != NULL) {
delete fMatches;
}
}
int32_t
TimeZoneNameMatchInfoImpl::size() const {
if (fMatches == NULL) {
return 0;
}
return fMatches->size();
}
UTimeZoneNameType
TimeZoneNameMatchInfoImpl::getNameType(int32_t index) const {
ZMatchInfo *minfo = (ZMatchInfo *)fMatches->elementAt(index);
if (minfo != NULL) {
return minfo->znameInfo->type;
}
return UTZNM_UNKNOWN;
}
int32_t
TimeZoneNameMatchInfoImpl::getMatchLength(int32_t index) const {
ZMatchInfo *minfo = (ZMatchInfo *)fMatches->elementAt(index);
if (minfo != NULL) {
return minfo->matchLength;
}
return -1;
}
UnicodeString&
TimeZoneNameMatchInfoImpl::getTimeZoneID(int32_t index, UnicodeString& tzID) const {
ZMatchInfo *minfo = (ZMatchInfo *)fMatches->elementAt(index);
if (minfo != NULL && minfo->znameInfo->tzID != NULL) {
tzID.setTo(TRUE, minfo->znameInfo->tzID, -1);
} else {
tzID.setToBogus();
}
return tzID;
}
UnicodeString&
TimeZoneNameMatchInfoImpl::getMetaZoneID(int32_t index, UnicodeString& mzID) const {
ZMatchInfo *minfo = (ZMatchInfo *)fMatches->elementAt(index);
if (minfo != NULL && minfo->znameInfo->mzID != NULL) {
mzID.setTo(TRUE, minfo->znameInfo->mzID, -1);
} else {
mzID.setToBogus();
}
return mzID;
}
// ---------------------------------------------------
// ZNameSearchHandler
@ -807,16 +732,16 @@ public:
virtual ~ZNameSearchHandler();
UBool handleMatch(int32_t matchLength, const CharacterNode *node, UErrorCode &status);
UVector* getMatches(int32_t& maxMatchLen);
TimeZoneNames::MatchInfoCollection* getMatches(int32_t& maxMatchLen);
private:
uint32_t fTypes;
UVector* fResults;
int32_t fMaxMatchLen;
TimeZoneNames::MatchInfoCollection* fResults;
};
ZNameSearchHandler::ZNameSearchHandler(uint32_t types)
: fTypes(types), fResults(NULL), fMaxMatchLen(0) {
: fTypes(types), fMaxMatchLen(0), fResults(NULL) {
}
ZNameSearchHandler::~ZNameSearchHandler() {
@ -840,28 +765,21 @@ ZNameSearchHandler::handleMatch(int32_t matchLength, const CharacterNode *node,
if ((nameinfo->type & fTypes) != 0) {
// matches a requested type
if (fResults == NULL) {
fResults = new UVector(uprv_free, NULL, status);
fResults = new TimeZoneNames::MatchInfoCollection();
if (fResults == NULL) {
status = U_MEMORY_ALLOCATION_ERROR;
}
}
if (U_SUCCESS(status)) {
U_ASSERT(fResults != NULL);
ZMatchInfo *zmatch = (ZMatchInfo *)uprv_malloc(sizeof(ZMatchInfo));
if (zmatch == NULL) {
status = U_MEMORY_ALLOCATION_ERROR;
if (nameinfo->tzID) {
fResults->addZone(nameinfo->type, matchLength, UnicodeString(nameinfo->tzID, -1), status);
} else {
// add the match to the vector
zmatch->znameInfo = nameinfo;
zmatch->matchLength = matchLength;
fResults->addElement(zmatch, status);
if (U_FAILURE(status)) {
uprv_free(zmatch);
} else {
if (matchLength > fMaxMatchLen) {
fMaxMatchLen = matchLength;
}
}
U_ASSERT(nameinfo->mzID);
fResults->addMetaZone(nameinfo->type, matchLength, UnicodeString(nameinfo->mzID, -1), status);
}
if (U_SUCCESS(status) && matchLength > fMaxMatchLen) {
fMaxMatchLen = matchLength;
}
}
}
@ -870,10 +788,10 @@ ZNameSearchHandler::handleMatch(int32_t matchLength, const CharacterNode *node,
return TRUE;
}
UVector*
TimeZoneNames::MatchInfoCollection*
ZNameSearchHandler::getMatches(int32_t& maxMatchLen) {
// give the ownership to the caller
UVector *results = fResults;
TimeZoneNames::MatchInfoCollection* results = fResults;
maxMatchLen = fMaxMatchLen;
// reset
@ -1012,6 +930,21 @@ TimeZoneNamesImpl::cleanup() {
}
}
UBool
TimeZoneNamesImpl::operator==(const TimeZoneNames& other) const {
if (this == &other) {
return TRUE;
}
// No implementation for now
return FALSE;
}
TimeZoneNames*
TimeZoneNamesImpl::clone() const {
UErrorCode status = U_ZERO_ERROR;
return new TimeZoneNamesImpl(fLocale, status);
}
StringEnumeration*
TimeZoneNamesImpl::getAvailableMetaZoneIDs(UErrorCode& status) const {
if (U_FAILURE(status)) {
@ -1307,7 +1240,7 @@ TimeZoneNamesImpl::loadTimeZoneNames(const UnicodeString& tzID) {
return tznames;
}
TimeZoneNameMatchInfo*
TimeZoneNames::MatchInfoCollection*
TimeZoneNamesImpl::find(const UnicodeString& text, int32_t start, uint32_t types, UErrorCode& status) const {
ZNameSearchHandler handler(types);
@ -1323,24 +1256,14 @@ TimeZoneNamesImpl::find(const UnicodeString& text, int32_t start, uint32_t types
return NULL;
}
TimeZoneNameMatchInfoImpl *matchInfo = NULL;
int32_t maxLen = 0;
UVector *results = handler.getMatches(maxLen);
if (results != NULL && ((maxLen == (text.length() - start)) || fNamesTrieFullyLoaded)) {
TimeZoneNames::MatchInfoCollection* matches = handler.getMatches(maxLen);
if (matches != NULL && ((maxLen == (text.length() - start)) || fNamesTrieFullyLoaded)) {
// perfect match
matchInfo = new TimeZoneNameMatchInfoImpl(results);
if (matchInfo == NULL) {
status = U_MEMORY_ALLOCATION_ERROR;
delete results;
return NULL;
}
return matchInfo;
return matches;
}
if (results != NULL) {
delete results;
}
delete matches;
// All names are not yet loaded into the trie
umtx_lock(&nonConstThis->fLock);
@ -1380,20 +1303,9 @@ TimeZoneNamesImpl::find(const UnicodeString& text, int32_t start, uint32_t types
}
umtx_unlock(&nonConstThis->fLock);
results = handler.getMatches(maxLen);
if (results != NULL && maxLen > 0) {
matchInfo = new TimeZoneNameMatchInfoImpl(results);
if (matchInfo == NULL) {
status = U_MEMORY_ALLOCATION_ERROR;
delete results;
return NULL;
}
}
return matchInfo;
return handler.getMatches(maxLen);
}
U_NAMESPACE_END

View file

@ -1,6 +1,6 @@
/*
*******************************************************************************
* Copyright (C) 2011, International Business Machines Corporation and *
* Copyright (C) 2011-2012, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*/
@ -18,7 +18,7 @@
#if !UCONFIG_NO_FORMATTING
#include "tznames.h"
#include "unicode/tznames.h"
#include "unicode/ures.h"
#include "unicode/locid.h"
#include "uhash.h"
@ -168,6 +168,9 @@ public:
virtual ~TimeZoneNamesImpl();
virtual UBool operator==(const TimeZoneNames& other) const;
virtual TimeZoneNames* clone() const;
StringEnumeration* getAvailableMetaZoneIDs(UErrorCode& status) const;
StringEnumeration* getAvailableMetaZoneIDs(const UnicodeString& tzID, UErrorCode& status) const;
@ -179,7 +182,7 @@ public:
UnicodeString& getExemplarLocationName(const UnicodeString& tzID, UnicodeString& name) const;
TimeZoneNameMatchInfo* find(const UnicodeString& text, int32_t start, uint32_t types, UErrorCode& status) const;
TimeZoneNames::MatchInfoCollection* find(const UnicodeString& text, int32_t start, uint32_t types, UErrorCode& status) const;
private:

View file

@ -1,7 +1,7 @@
/*
******************************************************************************
* *
* Copyright (C) 2001-2011, International Business Machines *
* Copyright (C) 2001-2012, International Business Machines *
* Corporation and others. All Rights Reserved. *
* *
******************************************************************************
@ -33,7 +33,7 @@ typedef enum ECleanupI18NType {
UCLN_I18N_HEBREW_CALENDAR,
UCLN_I18N_ASTRO_CALENDAR,
UCLN_I18N_CALENDAR,
UCLN_I18N_TIMEZONEFORMAT,
UCLN_I18N_TIMEZONEGENERICNAMES,
UCLN_I18N_TIMEZONENAMES,
UCLN_I18N_ZONEMETA,
UCLN_I18N_TIMEZONE,

View file

@ -713,30 +713,6 @@ private:
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}"
*/
UnicodeString fGmtFormat;
/**
* Pattern strings used for formatting zone offset in a localized time zone GMT string.
*/
UnicodeString *fGmtHourFormats;
int32_t fGmtHourFormatsCount;
enum GMTHourType {
GMT_NEGATIVE_HMS = 0,
GMT_NEGATIVE_HM,
GMT_POSITIVE_HMS,
GMT_POSITIVE_HM,
GMT_HOUR_COUNT
};
/**
* Localized date-time pattern characters. For example: use 'u' as 'y'.
*/

View file

@ -94,6 +94,7 @@ class TimeZoneFormat;
* zzzz time zone (Text) Pacific Standard Time
* Z time zone (RFC 822) (Number) -0800
* ZZZZ time zone (RFC 822) (Text & Number) GMT-08:00
* ZZZZZ time zone (ISO 8601) (Text & Number) -08:00 & Z
* v time zone (generic) (Text) PT
* vvvv time zone (generic) (Text) Pacific Time
* V time zone (abreviation) (Text) PST
@ -831,6 +832,31 @@ public:
*/
virtual int32_t getDefaultContext(UDateFormatContextType type, UErrorCode& status) const;
#ifndef U_HIDE_INTERNAL_API
/**
* Sets the TimeZoneFormat to be used by this date/time formatter.
* The caller should not delete the TimeZoneFormat object after
* it is adopted by this call.
* @param timeZoneFormatToAdopt The TimeZoneFormat object to be adopted.
* @internal ICU 49 technology preview
*/
virtual void adoptTimeZoneFormat(TimeZoneFormat* timeZoneFormatToAdopt);
/**
* Sets the TimeZoneFormat to be used by this date/time formatter.
* @param newTimeZoneFormat The TimeZoneFormat object to copy.
* @internal ICU 49 technology preview
*/
virtual void setTimeZoneFormat(const TimeZoneFormat& newTimeZoneFormat);
/**
* Gets the time zone format object associated with this date/time formatter.
* @return the time zone format associated with this date/time formatter.
* @internal ICU 49 technology preview
*/
virtual const TimeZoneFormat* getTimeZoneFormat(void) const;
#endif /* U_HIDE_INTERNAL_API */
#ifndef U_HIDE_INTERNAL_API
/**
* This is for ICU internal use only. Please do not use.
@ -1127,22 +1153,6 @@ private:
*/
int32_t skipUWhiteSpace(const UnicodeString& text, int32_t pos) const;
/**
* Private methods for formatting/parsing GMT string
*/
void appendGMT(NumberFormat *currentNumberFormat,UnicodeString &appendTo, Calendar& cal, UErrorCode& status) const;
void formatGMTDefault(NumberFormat *currentNumberFormat,UnicodeString &appendTo, int32_t offset) const;
int32_t parseGMT(const UnicodeString &text, ParsePosition &pos) const;
int32_t parseGMTDefault(const UnicodeString &text, ParsePosition &pos) const;
UBool isDefaultGMTFormat() const;
void formatRFC822TZ(UnicodeString &appendTo, int32_t offset) const;
/**
* Initialize MessageFormat instances used for GMT formatting/parsing
*/
void initGMTFormatters(UErrorCode &status);
/**
* Initialize NumberFormat instances used for numbering system overrides.
*/
@ -1229,13 +1239,7 @@ private:
*/
/*transient*/ int32_t fDefaultCenturyStartYear;
enum ParsedTZType {
TZTYPE_UNK,
TZTYPE_STD,
TZTYPE_DST
};
ParsedTZType tztype; // here to avoid api change
int32_t tztype; // here to avoid api change
typedef struct NSOverride {
NumberFormat *nf;
@ -1243,34 +1247,6 @@ private:
NSOverride *next;
} NSOverride;
/*
* MessageFormat instances used for localized GMT format
*/
enum {
kGMTNegativeHMS = 0,
kGMTNegativeHM,
kGMTPositiveHMS,
kGMTPositiveHM,
kNumGMTFormatters
};
enum {
kGMTNegativeHMSMinLenIdx = 0,
kGMTPositiveHMSMinLenIdx,
kNumGMTFormatMinLengths
};
MessageFormat **fGMTFormatters;
// If a GMT hour format has a second field, we need to make sure
// the length of input localized GMT string must match the expected
// length. Otherwise, sub DateForamt handling offset format may
// unexpectedly success parsing input GMT string without second field.
// See #6880 about this issue.
// TODO: SimpleDateFormat should provide an option to invalidate
//
int32_t fGMTFormatHmsMinLen[kNumGMTFormatMinLengths];
NumberFormat **fNumberFormatters;
NSOverride *fOverrideList;

View file

@ -0,0 +1,829 @@
/*
*******************************************************************************
* Copyright (C) 2011-2012, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*/
#ifndef __TZFMT_H
#define __TZFMT_H
/**
* \file
* \brief C++ API: TimeZoneFormat
*/
#include "unicode/utypes.h"
#if !UCONFIG_NO_FORMATTING
#ifndef U_HIDE_INTERNAL_API
#include "unicode/format.h"
#include "unicode/timezone.h"
#include "unicode/tznames.h"
U_CDECL_BEGIN
/**
* Constants for time zone display format style used by format/parse APIs
* in TimeZoneFormat.
* @internal ICU 49 technology preview
*/
typedef enum UTimeZoneFormatStyle {
/**
* Generic location format, such as "United States Time (New York)", "Italy Time"
* @internal ICU 49 technology preview
*/
UTZFMT_STYLE_GENERIC_LOCATION,
/**
* Generic long non-location format, such as "Eastern Time".
* @internal ICU 49 technology preview
*/
UTZFMT_STYLE_GENERIC_LONG,
/**
* Generic short non-location format, such as "ET".
* @internal ICU 49 technology preview
*/
UTZFMT_STYLE_GENERIC_SHORT,
/**
* Specific long format, such as "Eastern Standard Time".
* @internal ICU 49 technology preview
*/
UTZFMT_STYLE_SPECIFIC_LONG,
/**
* Specific short format, such as "EST", "PDT".
* @internal ICU 49 technology preview
*/
UTZFMT_STYLE_SPECIFIC_SHORT,
/**
* RFC822 format, such as "-0500"
* @internal ICU 49 technology preview
*/
UTZFMT_STYLE_RFC822,
/**
* Localized GMT offset format, such as "GMT-05:00", "UTC+0100"
* @internal ICU 49 technology preview
*/
UTZFMT_STYLE_LOCALIZED_GMT,
/**
* ISO 8601 format (extended), such as "-05:00", "Z"(UTC)
* @internal ICU 49 technology preview
*/
UTZFMT_STYLE_ISO8601
} UTimeZoneFormatStyle;
/**
* Constants for GMT offset pattern types.
* @internal ICU 49 technology preview
*/
typedef enum UTimeZoneFormatGMTOffsetPatternType {
/**
* Positive offset with hour and minute fields
* @internal ICU 49 technology preview
*/
UTZFMT_PAT_POSITIVE_HM,
/**
* Positive offset with hour, minute and second fields
* @internal ICU 49 technology preview
*/
UTZFMT_PAT_POSITIVE_HMS,
/**
* Negative offset with hour and minute fields
* @internal ICU 49 technology preview
*/
UTZFMT_PAT_NEGATIVE_HM,
/**
* Negative offset with hour, minute and second fields
* @internal ICU 49 technology preview
*/
UTZFMT_PAT_NEGATIVE_HMS
} UTimeZoneFormatGMTOffsetPatternType;
/**
* Constants for time types used by TimeZoneFormat APIs for
* receiving time type (standard time, daylight time or unknown).
* @internal ICU 49 technology preview
*/
typedef enum UTimeZoneFormatTimeType {
/**
* Unknown
* @internal ICU 49 technology preview
*/
UTZFMT_TIME_TYPE_UNKNOWN,
/**
* Standard time
* @internal ICU 49 technology preview
*/
UTZFMT_TIME_TYPE_STANDARD,
/**
* Daylight saving time
* @internal ICU 49 technology preview
*/
UTZFMT_TIME_TYPE_DAYLIGHT
} UTimeZoneFormatTimeType;
/**
* Constants for parse option flags, used for specifying optional parse behavior.
* @internal ICU 49 technology preview
*/
typedef enum UTimeZoneFormatParseOption {
/**
* No option.
* @internal ICU 49 technology preview
*/
UTZFMT_PARSE_OPTION_NONE = 0x00,
/**
* When a time zone display name is not found within a set of display names
* used for the specified style, look for the name from display names used
* by other styles.
* @internal ICU 49 technology preview
*/
UTZFMT_PARSE_OPTION_ALL_STYLES = 0x01
} UTimeZoneFormatParseOption;
U_CDECL_END
typedef void *UMTX;
U_NAMESPACE_BEGIN
class TimeZoneGenericNames;
class UVector;
/**
* <code>TimeZoneFormat</code> supports time zone display name formatting and parsing.
* An instance of TimeZoneFormat works as a subformatter of {@link SimpleDateFormat},
* but you can also directly get a new instance of <code>TimeZoneFormat</code> and
* formatting/parsing time zone display names.
* <p>
* ICU implements the time zone display names defined by <a href="http://www.unicode.org/reports/tr35/">UTS#35
* Unicode Locale Data Markup Language (LDML)</a>. {@link TimeZoneNames} represents the
* time zone display name data model and this class implements the algorithm for actual
* formatting and parsing.
*
* @see SimpleDateFormat
* @see TimeZoneNames
* @internal ICU 49 technology preview
*/
class U_I18N_API TimeZoneFormat : public Format {
public:
/**
* Copy constructor.
* @internal ICU 49 technology preview
*/
TimeZoneFormat(const TimeZoneFormat& other);
/**
* Destructor.
* @internal ICU 49 technology preview
*/
virtual ~TimeZoneFormat();
/**
* Assignment operator.
* @internal ICU 49 technology preview
*/
TimeZoneFormat& operator=(const TimeZoneFormat& other);
/**
* Return true if the given Format objects are semantically equal.
* Objects of different subclasses are considered unequal.
* @param other The object to be compared with.
* @return Return TRUE if the given Format objects are semantically equal.
* Objects of different subclasses are considered unequal.
* @internal ICU 49 technology preview
*/
virtual UBool operator==(const Format& other) const;
/**
* Clone this object polymorphically. The caller is responsible
* for deleting the result when done.
* @return A copy of the object
* @internal ICU 49 technology preview
*/
virtual Format* clone() const;
/**
* Creates an instance of <code>TimeZoneFormat</code> for the given locale.
* @param locale The locale.
* @param status Recevies the status.
* @return An instance of <code>TimeZoneFormat</code> for the given locale,
* owned by the caller.
* @internal ICU 49 technology preview
*/
static TimeZoneFormat* U_EXPORT2 createInstance(const Locale& locale, UErrorCode& status);
/**
* Returns the time zone display name data used by this instance.
* @return The time zone display name data.
* @internal ICU 49 technology preview
*/
const TimeZoneNames* getTimeZoneNames() const;
/**
* Sets the time zone display name data to this format instnace.
* The caller should not delete the TimeZoenNames object after it is adopted
* by this call.
* @param tznames TimeZoneNames object to be adopted.
* @internal ICU 49 technology preview
*/
void adoptTimeZoneNames(TimeZoneNames *tznames);
/**
* Sets the time zone display name data to this format instnace.
* @param tznames TimeZoneNames object to be set.
* @internal ICU 49 technology preview
*/
void setTimeZoneNames(const TimeZoneNames &tznames);
/**
* Returns the localized GMT format pattern.
* @param pattern Receives the localized GMT format pattern.
* @return A reference to the result pattern.
* @see #setGMTPattern
* @internal ICU 49 technology preview
*/
UnicodeString& getGMTPattern(UnicodeString& pattern) const;
/**
* Sets the localized GMT format pattern. The pattern must contain
* a single argument {0}, for example "GMT {0}".
* @param pattern The localized GMT format pattern to be used by this object.
* @param status Recieves the status.
* @see #getGMTPattern
* @internal ICU 49 technology preview
*/
void setGMTPattern(const UnicodeString& pattern, UErrorCode& status);
/**
* Returns the offset pattern used for localized GMT format.
* @param type The offset pattern type enum.
* @param pattern Receives the offset pattern.
* @return A reference to the result pattern.
* @see #setGMTOffsetPattern
* @internal ICU 49 technology preview
*/
UnicodeString& getGMTOffsetPattern(UTimeZoneFormatGMTOffsetPatternType type, UnicodeString& pattern) const;
/**
* Sets the offset pattern for the given offset type.
* @param type The offset pattern type enum.
* @param pattern The offset pattern used for localized GMT format for the type.
* @param status Receives the status.
* @see #getGMTOffsetPattern
* @internal ICU 49 technology preview
*/
void setGMTOffsetPattern(UTimeZoneFormatGMTOffsetPatternType type, const UnicodeString& pattern, UErrorCode& status);
/**
* Returns the decimal digit characters used for localized GMT format in a single string
* containing from 0 to 9 in the ascending order.
* @param digits Receives the decimal digits used for localized GMT format.
* @see #setGMTOffsetDigits
*/
UnicodeString& getGMTOffsetDigits(UnicodeString& digits) const;
/**
* Sets the decimal digit characters used for localized GMT format.
* @param digits The decimal digits used for localized GMT format.
* @param status Receives the status.
* @see #getGMTOffsetDigits
*/
void setGMTOffsetDigits(const UnicodeString& digits, UErrorCode& status);
/**
* Returns the localized GMT format string for GMT(UTC) itself (GMT offset is 0).
* @param gmtZeroFormat Receives the localized GMT string string for GMT(UTC) itself.
* @return A reference to the result GMT string.
* @see #setGMTZeroFormat
*/
UnicodeString& getGMTZeroFormat(UnicodeString& gmtZeroFormat) const;
/**
* Sets the localized GMT format string for GMT(UTC) itself (GMT offset is 0).
* @param gmtZeroFormat The localized GMT format string for GMT(UTC).
* @param status Receives the status.
* @see #getGMTZeroFormat
*/
void setGMTZeroFormat(const UnicodeString& gmtZeroFormat, UErrorCode& status);
/**
* Returns the bitwise flags of UTimeZoneFormatParseOption representing the default parse
* options used by this object.
* @return the default parse options.
* @see ParseOption
* @internal ICU 49 technology preview
*/
int32_t getDefaultParseOptions(void) const;
/**
* Sets the default parse options.
* <p><b>Note</b>: By default, an instance of <code>TimeZoneFormat</code>
* created by {@link #createInstance} has no parse options set (UTZFMT_PARSE_OPTION_NONE).
* To specify multipe options, use bitwise flags of UTimeZoneFormatParseOption.
* @see #UTimeZoneFormatParseOption
* @internal ICU 49 technology preview
*/
void setDefaultParseOptions(int32_t flags);
/**
* Returns the RFC822 style time zone string for the given offset.
* For example, "-0800".
* @param offset The offset from GMT(UTC) in milliseconds.
* @param result Recevies the RFC822 style GMT(UTC) offset format.
* @return A reference to the result.
* @see #parseOffsetRFC822
* @internal ICU 49 technology preview
*/
UnicodeString& formatOffsetRFC822(int32_t offset, UnicodeString& result, UErrorCode& status) const;
/**
* Returns the ISO 8601 style time zone string for the given offset.
* For example, "-08:00" and "Z".
* @param offset The offset from GMT(UTC) in milliseconds.
* @param result Recevies the ISO 8601 style GMT(UTC) offset format.
* @return A reference to the result.
* @see #parseOffsetISO8601
* @internal ICU 49 technology preview
*/
UnicodeString& formatOffsetISO8601(int32_t offset, UnicodeString& result, UErrorCode& status) const;
/**
* Returns the localized GMT(UTC) offset format for the given offset.
* The localized GMT offset is defined by;
* <ul>
* <li>GMT format pattern (e.g. "GMT {0}" - see {@link #getGMTPattern})
* <li>Offset time pattern (e.g. "+HH:mm" - see {@link #getGMTOffsetPattern})
* <li>Offset digits (e.g. "0123456789" - see {@link #getGMTOffsetDigits})
* <li>GMT zero format (e.g. "GMT" - see {@link #getGMTZeroFormat})
* </ul>
* @param offset the offset from GMT(UTC) in milliseconds.
* @param result Receives the localized GMT format string.
* @return A reference to the result.
* @see #parseOffsetLocalizedGMT
* @internal ICU 49 technology preview
*/
UnicodeString& formatOffsetLocalizedGMT(int32_t offset, UnicodeString& result, UErrorCode& status) const;
/**
* Returns the display name of the time zone at the given date for the style.
* @param style The style (e.g. <code>UTZFMT_STYLE_GENERIC_LONG</code>, <code>UTZFMT_STYLE_LOCALIZED_GMT</code>...)
* @param tz The time zone.
* @param date The date.
* @param name Receives the display name.
* @param timeType the output argument for receiving the time type (standard/daylight/unknown)
* used for the display name, or NULL if the information is not necessary.
* @return A reference to the result
* @see #UTimeZoneFormatStyle
* @see #UTimeZoneFormatTimeType
* @internal ICU 49 technology preview
*/
virtual UnicodeString& format(UTimeZoneFormatStyle style, const TimeZone& tz, UDate date,
UnicodeString& name, UTimeZoneFormatTimeType* timeType = NULL) const;
/**
* Returns offset from GMT(UTC) in milliseconds for the given RFC822
* style time zone string. When the given string is not an RFC822 time zone
* string, this method sets the current position as the error index
* to <code>ParsePosition pos</code> and returns 0.
* @param text The text contains RFC822 style time zone string (e.g. "-0800")
* at the position.
* @param pos The ParsePosition object.
* @return The offset from GMT(UTC) in milliseconds for the given RFC822 style
* time zone string.
* @see #formatOffsetRFC822
* @internal ICU 49 technology preview
*/
int32_t parseOffsetRFC822(const UnicodeString& text, ParsePosition& pos) const;
/**
* Returns offset from GMT(UTC) in milliseconds for the given ISO 8601
* style time zone string. When the given string is not an ISO 8601 time zone
* string, this method sets the current position as the error index
* to <code>ParsePosition pos</code> and returns 0.
* @param text The text contains RFC822 style time zone string (e.g. "-08:00", "Z")
* at the position.
* @param pos The ParsePosition object.
* @return The offset from GMT(UTC) in milliseconds for the given ISO 8601 style
* time zone string.
* @see #formatOffsetISO8601
* @internal ICU 49 technology preview
*/
int32_t parseOffsetISO8601(const UnicodeString& text, ParsePosition& pos) const;
/**
* Returns offset from GMT(UTC) in milliseconds for the given localized GMT
* offset format string. When the given string cannot be parsed, this method
* sets the current position as the error index to <code>ParsePosition pos</code>
* and returns 0.
* @param text The text contains a localized GMT offset string at the position.
* @param pos The ParsePosition object.
* @return The offset from GMT(UTC) in milliseconds for the given localized GMT
* offset format string.
* @see #formatOffsetLocalizedGMT
* @internal ICU 49 technology preview
*/
int32_t parseOffsetLocalizedGMT(const UnicodeString& text, ParsePosition& pos) const;
/**
* Returns a <code>TimeZone</code> by parsing the time zone string according to
* the given parse position, the specified format style and parse options.
*
* @param text The text contains a time zone string at the position.
* @param style The format style
* @param pos The position.
* @param parseOptions The parse options repesented by bitwise flags of UTimeZoneFormatParseOption.
* @param timeType The output argument for receiving the time type (standard/daylight/unknown),
* or NULL if the information is not necessary.
* @return A <code>TimeZone</code>, or null if the input could not be parsed.
* @see UTimeZoneFormatStyle
* @see UTimeZoneFormatParseOption
* @see UTimeZoneFormatTimeType
* @internal ICU 49 technology preview
*/
virtual TimeZone* parse(UTimeZoneFormatStyle style, const UnicodeString& text, ParsePosition& pos,
int32_t parseOptions, UTimeZoneFormatTimeType* timeType = NULL) const;
/**
* Returns a <code>TimeZone</code> by parsing the time zone string according to
* the given parse position, the specified format style and the default parse options.
*
* @param text The text contains a time zone string at the position.
* @param style The format style
* @param pos The position.
* @param timeType The output argument for receiving the time type (standard/daylight/unknown),
* or NULL if the information is not necessary.
* @return A <code>TimeZone</code>, or null if the input could not be parsed.
* @see UTimeZoneFormatStyle
* @see UTimeZoneFormatParseOption
* @see UTimeZoneFormatTimeType
* @internal ICU 49 technology preview
*/
TimeZone* parse(UTimeZoneFormatStyle style, const UnicodeString& text, ParsePosition& pos,
UTimeZoneFormatTimeType* timeType = NULL) const;
/* ----------------------------------------------
* Format APIs
* ---------------------------------------------- */
/**
* Format an object to produce a time zone display string using localized GMT offset format.
* This method handles Formattable objects with a <code>TimeZone</code>. If a the Formattable
* object type is not a <code>TimeZone</code>, then it returns a failing UErrorCode.
* @param obj The object to format. Must be a <code>TimeZone</code>.
* @param appendTo Output parameter to receive result. Result is appended to existing contents.
* @param pos On input: an alignment field, if desired. On output: the offsets of the alignment field.
* @param status Output param filled with success/failure status.
* @return Reference to 'appendTo' parameter.
* @internal ICU 49 technology preview
*/
virtual UnicodeString& format(const Formattable& obj, UnicodeString& appendTo,
FieldPosition& pos, UErrorCode& status) const;
/**
* Parse a string to produce an object. This methods handles parsing of
* time zone display strings into Formattable objects with <code>TimeZone</code>.
* @param source The string to be parsed into an object.
* @param result Formattable to be set to the parse result. If parse fails, return contents are undefined.
* @param parse_pos The position to start parsing at. Upon return this param is set to the position after the
* last character successfully parsed. If the source is not parsed successfully, this param
* will remain unchanged.
* @return A newly created Formattable* object, or NULL on failure. The caller owns this and should
* delete it when done.
* @internal ICU 49 technology preview
*/
virtual void parseObject(const UnicodeString& source, Formattable& result, ParsePosition& parse_pos) const;
/**
* ICU "poor man's RTTI", returns a UClassID for this class.
* @internal ICU 49 technology preview
*/
static UClassID U_EXPORT2 getStaticClassID(void);
/**
* ICU "poor man's RTTI", returns a UClassID for the actual class.
* @internal ICU 49 technology preview
*/
virtual UClassID getDynamicClassID() const;
protected:
/**
* Constructs a TimeZoneFormat object for the specified locale.
* @param locale the locale
* @param status receives the status.
* @internal ICU 49 technology preview
*/
TimeZoneFormat(const Locale& locale, UErrorCode& status);
private:
/* mutex */
UMTX fLock;
/* Locale of this object */
Locale fLocale;
/* Stores the region (could be implicit default) */
char fTargetRegion[ULOC_COUNTRY_CAPACITY];
/* TimeZoneNames object used by this formatter */
TimeZoneNames* fTimeZoneNames;
/* TimeZoneGenericNames object used by this formatter - lazily instantiated */
TimeZoneGenericNames* fTimeZoneGenericNames;
/* Localized GMT format pattern - e.g. "GMT{0}" */
UnicodeString fGMTPattern;
/* Array of offset patterns used by Localized GMT format - e.g. "+HH:mm" */
UnicodeString fGMTOffsetPatterns[UTZFMT_PAT_NEGATIVE_HMS + 1];
/* Localized decimal digits used by Localized GMT format */
UChar32 fGMTOffsetDigits[10];
/* Localized GMT zero format - e.g. "GMT" */
UnicodeString fGMTZeroFormat;
/* Bit flags representing parse options */
int32_t fDefParseOptionFlags;
/* Constant parts of GMT format pattern, populated from localized GMT format pattern*/
UnicodeString fGMTPatternPrefix; /* Substring before {0} */
UnicodeString fGMTPatternSuffix; /* Substring after {0} */
/* Compiled offset patterns generated from fGMTOffsetPatterns[] */
UVector* fGMTOffsetPatternItems[UTZFMT_PAT_NEGATIVE_HMS + 1];
/**
* Returns the time zone's specific format string.
* @param tz the time zone
* @param stdType the name type used for standard time
* @param dstType the name type used for daylight time
* @param date the date
* @param name receives the time zone's specific format name string
* @param timeType when null, actual time type is set
* @return a reference to name.
*/
UnicodeString& formatSpecific(const TimeZone& tz, UTimeZoneNameType stdType, UTimeZoneNameType dstType,
UDate date, UnicodeString& name, UTimeZoneFormatTimeType *timeType) const;
/**
* Returns the time zone's generic format string.
* @param tz the time zone
* @param genType the generic name type
* @param date the date
* @param name receives the time zone's generic format name string
* @return a reference to name.
*/
UnicodeString& formatGeneric(const TimeZone& tz, int32_t genType, UDate date, UnicodeString& name) const;
/**
* Lazily create a TimeZoneGenericNames instance
* @param status receives the status
* @return the cached TimeZoneGenericNames.
*/
const TimeZoneGenericNames* getTimeZoneGenericNames(UErrorCode& status) const;
/**
* Private enum specifying a combination of offset fields
*/
enum OffsetFields {
FIELDS_H,
FIELDS_HM,
FIELDS_HMS
};
/**
* Parses the localized GMT pattern string and initialize
* localized gmt pattern fields.
* @param gmtPattern the localized GMT pattern string such as "GMT {0}"
* @param status U_ILLEGAL_ARGUMENT_ERROR is set when the specified pattern does not
* contain an argument "{0}".
*/
void initGMTPattern(const UnicodeString& gmtPattern, UErrorCode& status);
/**
* Parse the GMT offset pattern into runtime optimized format.
* @param pattern the offset pattern string
* @param required the required set of fields, such as FIELDS_HM
* @param status U_ILLEGAL_ARGUMENT is set when the specified pattern does not contain
* pattern letters for the required fields.
* @return A list of GMTOffsetField objects, or NULL on error.
*/
static UVector* parseOffsetPattern(const UnicodeString& pattern, OffsetFields required, UErrorCode& status);
/**
* Appends second field to the offset pattern with hour/minute
* Note: This code will be obsoleted once we add hour-minute-second pattern data in CLDR.
* @param offsetHM the offset pattern including hour and minute fields
* @param result the output offset pattern including hour, minute and second fields
* @return a reference to result
*/
static UnicodeString& expandOffsetPattern(const UnicodeString& offsetHM, UnicodeString& result);
/**
* Break input string into UChar32[]. Each array element represents
* a code point. This method is used for parsing localized digit
* characters and support characters in Unicode supplemental planes.
* @param str the string
* @param codeArray receives the result
* @param capacity the capacity of codeArray
* @return TRUE when the specified code array is fully filled with code points
* (no under/overflow).
*/
static UBool toCodePoints(const UnicodeString& str, UChar32* codeArray, int32_t capacity);
/**
* Returns offset from GMT(UTC) in milliseconds for the given ISO 8601 style
* (extended format) time zone string. When the given string is not an ISO 8601 time
* zone string, this method sets the current position as the error index
* to <code>ParsePosition pos</code> and returns 0.
* @param text the text contains ISO 8601 style time zone string (e.g. "-08:00", "Z")
* at the position.
* @param pos the position, non-negative error index will be set on failure.
* @param extendedOnly TRUE if parsing the text as ISO 8601 extended offset format (e.g. "-08:00"),
* or FALSE to evaluate the text as basic format.
* @param hasDigitOffset receiving if the parsed zone string contains offset digits.
* @return the offset from GMT(UTC) in milliseconds for the given ISO 8601 style
* time zone string.
*/
int32_t parseOffsetISO8601(const UnicodeString& text, ParsePosition& pos, UBool extendedOnly,
UBool* hasDigitOffset = NULL) const;
/**
* Appends localized digits to the buffer.
* This code assumes that the input number is 0 - 59
* @param buf the target buffer
* @param n the integer number
* @param minDigits the minimum digits width
*/
void appendOffsetDigits(UnicodeString& buf, int32_t n, uint8_t minDigits) const;
/**
* Returns offset from GMT(UTC) in milliseconds for the given localized GMT
* offset format string. When the given string cannot be parsed, this method
* sets the current position as the error index to <code>ParsePosition pos</code>
* and returns 0.
* @param text the text contains a localized GMT offset string at the position.
* @param pos the position, non-negative error index will be set on failure.
* @param hasDigitOffset receiving if the parsed zone string contains offset digits.
* @return the offset from GMT(UTC) in milliseconds for the given localized GMT
* offset format string.
*/
int32_t parseOffsetLocalizedGMT(const UnicodeString& text, ParsePosition& pos,
UBool* hasDigitOffset) const;
/**
* Parses localized GMT offset fields into offset.
* @param text the input text
* @param start the start index
* @param minimumHourWidth true if the parser allows hour field width to be 1
* @param parsedLen the parsed length, or 0 on failure.
* @return the parsed offset in milliseconds.
*/
int32_t parseOffsetFields(const UnicodeString& text, int32_t start, UBool minimumHourWidth,
int32_t& parsedLen) const;
/**
* Parses abutting localized GMT offset fields (such as 0800) into offset.
* @param text the input text
* @param start the start index
* @param parsedLen the parsed length, or 0 on failure
* @return the parsed offset in milliseconds.
*/
int32_t parseAbuttingOffsetFields(const UnicodeString& text, int32_t start, int32_t& parsedLen) const;
/**
* Parses the input text using the default format patterns (e.g. "UTC{0}").
* @param text the input text
* @param start the start index
* @param parsedLen the parsed length, or 0 on failure
* @return the parsed offset in milliseconds.
*/
int32_t parseOffsetDefaultLocalizedGMT(const UnicodeString& text, int start, int32_t& parsedLen) const;
/**
* Parses the input GMT offset fields with the default offset pattern.
* @param text the input text
* @param start the start index
* @param separator the separator character, e.g. ':'
* @param parsedLen the parsed length, or 0 on failure.
* @return the parsed offset in milliseconds.
*/
int32_t parseDefaultOffsetFields(const UnicodeString& text, int32_t start, UChar separator,
int32_t& parsedLen) const;
/**
* Reads an offset field value. This method will stop parsing when
* 1) number of digits reaches <code>maxDigits</code>
* 2) just before already parsed number exceeds <code>maxVal</code>
*
* @param text the text
* @param start the start offset
* @param minDigits the minimum number of required digits
* @param maxDigits the maximum number of digits
* @param minVal the minimum value
* @param maxVal the maximum value
* @param parsedLen the actual parsed length.
* @return the integer value parsed
*/
int32_t parseOffsetFieldWithLocalizedDigits(const UnicodeString& text, int32_t start,
uint8_t minDigits, uint8_t maxDigits, uint16_t minVal, uint16_t maxVal, int32_t& parsedLen) const;
/**
* Reads a single decimal digit, either localized digits used by this object
* or any Unicode numeric character.
* @param text the text
* @param start the start index
* @param len the actual length read from the text
* the start index is not a decimal number.
* @return the integer value of the parsed digit, or -1 on failure.
*/
int32_t parseSingleLocalizedDigit(const UnicodeString& text, int32_t start, int32_t& len) const;
/**
* Formats offset using ASCII digits. The input offset range must be
* within +/-24 hours (exclusive).
* @param offset The offset
* @param sep The field separator character or 0 if not required
* @param minFields The minimum fields
* @param maxFields The maximum fields
* @return The offset string
*/
static UnicodeString& formatOffsetWithAsciiDigits(int32_t offset, UChar sep,
OffsetFields minFields, OffsetFields maxFields, UnicodeString& result);
/**
* Parses offset represented by contiguous ASCII digits.
* <p>
* Note: This method expects the input position is already at the start of
* ASCII digits and does not parse sign (+/-).
* @param text The text contains a sequence of ASCII digits
* @param pos The parse position
* @param minFields The minimum Fields to be parsed
* @param maxFields The maximum Fields to be parsed
* @param fixedHourWidth true if hour field must be width of 2
* @return Parsed offset, 0 or positive number.
*/
static int32_t parseAbuttingAsciiOffsetFields(const UnicodeString& text, ParsePosition& pos,
OffsetFields minFields, OffsetFields maxFields, UBool fixedHourWidth);
/**
* Parses offset represented by ASCII digits and separators.
* <p>
* Note: This method expects the input position is already at the start of
* ASCII digits and does not parse sign (+/-).
* @param text The text
* @param pos The parse position
* @param sep The separator character
* @param minFields The minimum Fields to be parsed
* @param maxFields The maximum Fields to be parsed
* @param fixedHourWidth true if hour field must be width of 2
* @return Parsed offset, 0 or positive number.
*/
static int32_t parseAsciiOffsetFields(const UnicodeString& text, ParsePosition& pos, UChar sep,
OffsetFields minFields, OffsetFields maxFields, UBool fixedHourWidth);
/**
* Unquotes the message format style pattern.
* @param pattern the pattern
* @param result receive the unquoted pattern.
* @return A reference to result.
*/
static UnicodeString& unquote(const UnicodeString& pattern, UnicodeString& result);
/**
* Initialize localized GMT format offset hour/min/sec patterns.
* This method parses patterns into optimized run-time format.
* @param status receives the status.
*/
void initGMTOffsetPatterns(UErrorCode& status);
/**
* Creates an instance of TimeZone for the given offset
* @param offset the offset
* @return A TimeZone with the given offset
*/
TimeZone* createTimeZoneForOffset(int32_t offset) const;
/**
* Returns the time type for the given name type
* @param nameType the name type
* @return the time type (unknown/standard/daylight)
*/
static UTimeZoneFormatTimeType getTimeType(UTimeZoneNameType nameType);
/*
* Returns the time zone ID of a match at the specified index within
* the MatchInfoCollection.
* @param matches the collection of matches
* @param idx the index withing matches
* @param tzID receives the resolved time zone ID
* @return a reference to tzID.
*/
UnicodeString& getTimeZoneID(const TimeZoneNames::MatchInfoCollection* matches, int32_t idx, UnicodeString& tzID) const;
};
U_NAMESPACE_END
#endif /* U_HIDE_INTERNAL_API */
#endif
#endif

View file

@ -0,0 +1,378 @@
/*
*******************************************************************************
* Copyright (C) 2011-2012, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*/
#ifndef __TZNAMES_H
#define __TZNAMES_H
/**
* \file
* \brief C++ API: TimeZoneNames
*/
#include "unicode/utypes.h"
#if !UCONFIG_NO_FORMATTING
#ifndef U_HIDE_INTERNAL_API
#include "unicode/uloc.h"
#include "unicode/unistr.h"
U_CDECL_BEGIN
/**
* Constants for time zone display name types.
* @internal ICU 49 technology preview
*/
typedef enum UTimeZoneNameType {
/**
* Unknown display name type.
* @internal ICU 49 technology preview
*/
UTZNM_UNKNOWN = 0x00,
/**
* Long display name, such as "Eastern Time".
* @internal ICU 49 technology preview
*/
UTZNM_LONG_GENERIC = 0x01,
/**
* Long display name for standard time, such as "Eastern Standard Time".
* @internal ICU 49 technology preview
*/
UTZNM_LONG_STANDARD = 0x02,
/**
* Long display name for daylight saving time, such as "Eastern Daylight Time".
* @internal ICU 49 technology preview
*/
UTZNM_LONG_DAYLIGHT = 0x04,
/**
* Short display name, such as "ET".
* @internal ICU 49 technology preview
*/
UTZNM_SHORT_GENERIC = 0x08,
/**
* Short display name for standard time, such as "EST".
* @internal ICU 49 technology preview
*/
UTZNM_SHORT_STANDARD = 0x10,
/**
* Short display name for daylight saving time, such as "EDT".
* @internal ICU 49 technology preview
*/
UTZNM_SHORT_DAYLIGHT = 0x20
} UTimeZoneNameType;
U_CDECL_END
U_NAMESPACE_BEGIN
class UVector;
struct MatchInfo;
/**
* <code>TimeZoneNames</code> is an abstract class representing the time zone display name data model defined
* by <a href="http://www.unicode.org/reports/tr35/">UTS#35 Unicode Locale Data Markup Language (LDML)</a>.
* The model defines meta zone, which is used for storing a set of display names. A meta zone can be shared
* by multiple time zones. Also a time zone may have multiple meta zone historic mappings.
* <p>
* For example, people in the United States refer the zone used by the east part of North America as "Eastern Time".
* The tz database contains multiple time zones "America/New_York", "America/Detroit", "America/Montreal" and some
* others that belong to "Eastern Time". However, assigning different display names to these time zones does not make
* much sense for most of people.
* <p>
* In <a href="http://cldr.unicode.org/">CLDR</a> (which uses LDML for representing locale data), the display name
* "Eastern Time" is stored as long generic display name of a meta zone identified by the ID "America_Eastern".
* Then, there is another table maintaining the historic mapping to meta zones for each time zone. The time zones in
* the above example ("America/New_York", "America/Detroit"...) are mapped to the meta zone "America_Eastern".
* <p>
* Sometimes, a time zone is mapped to a different time zone in the past. For example, "America/Indiana/Knox"
* had been moving "Eastern Time" and "Central Time" back and forth. Therefore, it is necessary that time zone
* to meta zones mapping data are stored by date range.
*
* <p><b>Note:</b>
* The methods in this class assume that time zone IDs are already canonicalized. For example, you may not get proper
* result returned by a method with time zone ID "America/Indiana/Indianapolis", because it's not a canonical time zone
* ID (the canonical time zone ID for the time zone is "America/Indianapolis". See
* {@link TimeZone#getCanonicalID(const UnicodeString& id, UnicodeString& canonicalID, UErrorCode& status)} about ICU
* canonical time zone IDs.
*
* <p>
* In CLDR, most of time zone display names except location names are provided through meta zones. But a time zone may
* have a specific name that is not shared with other time zones.
*
* For example, time zone "Europe/London" has English long name for standard time "Greenwich Mean Time", which is also
* shared with other time zones. However, the long name for daylight saving time is "British Summer Time", which is only
* used for "Europe/London".
*
* <p>
* {@link #getTimeZoneDisplayName} is designed for accessing a name only used by a single time zone.
* But is not necessarily mean that a subclass implementation use the same model with CLDR. A subclass implementation
* may provide time zone names only through {@link #getTimeZoneDisplayName}, or only through {@link #getMetaZoneDisplayName},
* or both.
*
* @internal ICU 49 technology preview
*/
class U_I18N_API TimeZoneNames : public UObject {
public:
/**
* Destructor.
* @internal ICU 49 technology preview
*/
virtual ~TimeZoneNames();
/**
* Return true if the given TimeZoneNames objects are emantically equal.
* @param other the object to be compared with.
* @return Return TRUE if the given Format objects are semantically equal.
* @internal ICU 49 technology preview
*/
virtual UBool operator==(const TimeZoneNames& other) const = 0;
/**
* Return true if the given TimeZoneNames objects are not semantically
* equal.
* @param other the object to be compared with.
* @return Return TRUE if the given Format objects are not semantically equal.
* @internal ICU 49 technology preview
*/
UBool operator!=(const TimeZoneNames& other) const { return !operator==(other); }
/**
* Clone this object polymorphically. The caller is responsible
* for deleting the result when done.
* @return A copy of the object
* @internal ICU 49 technology preview
*/
virtual TimeZoneNames* clone() const = 0;
/**
* Returns an instance of <code>TimeZoneDisplayNames</code> for the specified locale.
*
* @param locale The locale.
* @param status Recevies the status.
* @return An instance of <code>TimeZoneDisplayNames</code>
* @internal ICU 49 technology preview
*/
static TimeZoneNames* U_EXPORT2 createInstance(const Locale& locale, UErrorCode& status);
/**
* Returns an enumeration of all available meta zone IDs.
* @param status Recevies the status.
* @return an enumeration object, owned by the caller.
* @internal ICU 49 technology preview
*/
virtual StringEnumeration* getAvailableMetaZoneIDs(UErrorCode& status) const = 0;
/**
* Returns an enumeration of all available meta zone IDs used by the given time zone.
* @param tzID The canoical tiem zone ID.
* @param status Recevies the status.
* @return an enumeration object, owned by the caller.
* @internal ICU 49 technology preview
*/
virtual StringEnumeration* getAvailableMetaZoneIDs(const UnicodeString& tzID, UErrorCode& status) const = 0;
/**
* Returns the meta zone ID for the given canonical time zone ID at the given date.
* @param tzID The canonical time zone ID.
* @param date The date.
* @param mzID Receives the meta zone ID for the given time zone ID at the given date. If the time zone does not have a
* corresponding meta zone at the given date or the implementation does not support meta zones, "bogus" state
* is set.
* @return A reference to the result.
* @internal ICU 49 technology preview
*/
virtual UnicodeString& getMetaZoneID(const UnicodeString& tzID, UDate date, UnicodeString& mzID) const = 0;
/**
* Returns the reference zone ID for the given meta zone ID for the region.
* @param mzID The meta zone ID.
* @param region The region.
* @param tzID Receives the reference zone ID ("golden zone" in the LDML specification) for the given time zone ID for the
* region. If the meta zone is unknown or the implementation does not support meta zones, "bogus" state
* is set.
* @return A reference to the result.
* @internal ICU 49 technology preview
*/
virtual UnicodeString& getReferenceZoneID(const UnicodeString& mzID, const char* region, UnicodeString& tzID) const = 0;
/**
* Returns the display name of the meta zone.
* @param mzID The meta zone ID.
* @param type The display name type. See {@link #UTimeZoneNameType}.
* @param name Receives the display name of the meta zone. When this object does not have a localized display name for the given
* meta zone with the specified type or the implementation does not provide any display names associated
* with meta zones, "bogus" state is set.
* @return A reference to the result.
* @internal ICU 49 technology preview
*/
virtual UnicodeString& getMetaZoneDisplayName(const UnicodeString& mzID, UTimeZoneNameType type, UnicodeString& name) const = 0;
/**
* Returns the display name of the time zone. Unlike {@link #getDisplayName},
* this method does not get a name from a meta zone used by the time zone.
* @param tzID The canonical time zone ID.
* @param type The display name type. See {@link #UTimeZoneNameType}.
* @param name Receives the display name for the time zone. When this object does not have a localized display name for the given
* time zone with the specified type, "bogus" state is set.
* @return A reference to the result.
* @internal ICU 49 technology preview
*/
virtual UnicodeString& getTimeZoneDisplayName(const UnicodeString& tzID, UTimeZoneNameType type, UnicodeString& name) const = 0;
/**
* Returns the exemplar location name for the given time zone. When this object does not have a localized location
* name, the default implementation may still returns a programmatically generated name with the logic described
* below.
* <ol>
* <li>Check if the ID contains "/". If not, return null.
* <li>Check if the ID does not start with "Etc/" or "SystemV/". If it does, return null.
* <li>Extract a substring after the last occurrence of "/".
* <li>Replace "_" with " ".
* </ol>
* For example, "New York" is returned for the time zone ID "America/New_York" when this object does not have the
* localized location name.
*
* @param tzID The canonical time zone ID
* @param name Receives the exemplar location name for the given time zone, or "bogus" state is set when a localized
* location name is not available and the fallback logic described above cannot extract location from the ID.
* @return A reference to the result.
* @internal ICU 49 technology preview
*/
virtual UnicodeString& getExemplarLocationName(const UnicodeString& tzID, UnicodeString& name) const;
/**
* Returns the display name of the time zone at the given date.
* <p>
* <b>Note:</b> This method calls the subclass's {@link #getTimeZoneDisplayName} first. When the
* result is bogus, this method calls {@link #getMetaZoneID} to get the meta zone ID mapped from the
* time zone, then calls {@link #getMetaZoneDisplayName}.
*
* @param tzID The canonical time zone ID.
* @param type The display name type. See {@link #UTimeZoneNameType}.
* @param date The date.
* @param name Receives the display name for the time zone at the given date. When this object does not have a localized display
* name for the time zone with the specified type and date, "bogus" state is set.
* @return A reference to the result.
* @internal ICU 49 technology preview
*/
virtual UnicodeString& getDisplayName(const UnicodeString& tzID, UTimeZoneNameType type, UDate date, UnicodeString& name) const;
/**
* <code>MatchInfoCollection</code> represents a collection of time zone name matches used by
* {@link TimeZoneNames#find}.
* @internal ICU 49 technology preview
*/
class U_I18N_API MatchInfoCollection : public UMemory {
public:
/**
* Constructor.
* @internal ICU 49 technology preview
*/
MatchInfoCollection();
/**
* Destructor.
* @internal ICU 49 technology preview
*/
virtual ~MatchInfoCollection();
/**
* Adds a zone match.
* @param nameType The name type.
* @param matchLength The match length.
* @param tzID The time zone ID.
* @param status Receives the status
* @internal ICU 49 technology preview
*/
void addZone(UTimeZoneNameType nameType, int32_t matchLength,
const UnicodeString& tzID, UErrorCode& status);
/**
* Adds a meata zone match.
* @param nameType The name type.
* @param matchLength The match length.
* @param mzID The metazone ID.
* @param status Receives the status
* @internal ICU 49 technology preview
*/
void addMetaZone(UTimeZoneNameType nameType, int32_t matchLength,
const UnicodeString& mzID, UErrorCode& status);
/**
* Returns the number of entries available in this object.
* @return The number of entries.
* @internal ICU 49 technology preview
*/
int32_t size() const;
/**
* Returns the time zone name type of a match at the specified index.
* @param idx The index
* @return The time zone name type. If the specified idx is out of range,
* it returns UTZNM_UNKNOWN.
* @see UTimeZoneNameType
* @internal ICU 49 technology preview
*/
UTimeZoneNameType getNameTypeAt(int32_t idx) const;
/**
* Returns the match length of a match at the specified index.
* @param idx The index
* @param status Receives the status
* @return The match length. If the specified idx is out of range,
* it returns 0.
* @internal ICU 49 technology preview
*/
int32_t getMatchLengthAt(int32_t idx) const;
/**
* Gets the zone ID of a match at the specified index.
* @param idx The index
* @param tzID Receives the zone ID.
* @return TRUE if the zone ID was set to tzID.
* @internal ICU 49 technology preview
*/
UBool getTimeZoneIDAt(int32_t idx, UnicodeString& tzID) const;
/**
* Gets the metazone ID of a match at the specified index.
* @param idx The index
* @param mzID Receives the metazone ID
* @param status Receives the status.
* @return TRUE if the meta zone ID was set to mzID.
* @internal ICU 49 technology preview
*/
UBool getMetaZoneIDAt(int32_t idx, UnicodeString& mzID) const;
private:
UVector* fMatches; // vector of MatchEntry
UVector* matches(UErrorCode& status);
};
/**
* Finds time zone name prefix matches for the input text at the
* given offset and returns a collection of the matches.
* @param text The text.
* @param start The starting offset within the text.
* @param types The set of name types represented by bitwise flags of UTimeZoneNameType enums,
* or UTZNM_UNKNOWN for all name types.
* @param status Receives the status.
* @return A collection of matches (owned by the caller), or NULL if no matches are found.
* @see UTimeZoneNameType
* @see MatchInfoCollection
* @internal ICU 49 technology preview
*/
virtual MatchInfoCollection* find(const UnicodeString& text, int32_t start, uint32_t types, UErrorCode& status) const = 0;
private:
// No ICU "poor man's RTTI" for this class nor its subclasses.
virtual UClassID getDynamicClassID() const;
};
U_NAMESPACE_END
#endif /* U_HIDE_INTERNAL_API */
#endif
#endif

View file

@ -1,6 +1,6 @@
/*
*******************************************************************************
* Copyright (C) 2007-2011, International Business Machines Corporation and *
* Copyright (C) 2007-2012, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*/
@ -14,6 +14,7 @@
#include "unicode/timezone.h"
#include "unicode/ustring.h"
#include "unicode/putil.h"
#include "unicode/simpletz.h"
#include "umutex.h"
#include "uvector.h"
@ -132,6 +133,8 @@ static const UChar gDefaultFrom[] = {0x31, 0x39, 0x37, 0x30, 0x2D, 0x30, 0x31, 0
static const UChar gDefaultTo[] = {0x39, 0x39, 0x39, 0x39, 0x2D, 0x31, 0x32, 0x2D, 0x33, 0x31,
0x20, 0x32, 0x33, 0x3A, 0x35, 0x39, 0x00}; // "9999-12-31 23:59"
static const UChar gCustomTzPrefix[] = {0x47, 0x4D, 0x54, 0}; // "GMT"
#define ASCII_DIGIT(c) (((c)>=0x30 && (c)<=0x39) ? (c)-0x30 : -1)
/*
@ -842,6 +845,54 @@ ZoneMeta::findTimeZoneID(const UnicodeString& tzid) {
return TimeZone::findID(tzid);
}
TimeZone*
ZoneMeta::createCustomTimeZone(int32_t offset) {
UBool negative = FALSE;
int32_t tmp = offset;
if (offset < 0) {
negative = TRUE;
tmp = -offset;
}
int32_t hour, min, sec;
tmp /= 1000;
sec = tmp % 60;
tmp /= 60;
min = tmp % 60;
hour = tmp / 60;
UnicodeString zid;
formatCustomID(hour, min, sec, negative, zid);
return new SimpleTimeZone(offset, zid);
}
UnicodeString&
ZoneMeta::formatCustomID(uint8_t hour, uint8_t min, uint8_t sec, UBool negative, UnicodeString& id) {
// Create normalized time zone ID - GMT[+|-]HH:mm[:ss]
id.setTo(gCustomTzPrefix, -1);
if (hour != 0 || min != 0) {
if (negative) {
id.append(0x2D); // '-'
} else {
id.append(0x2B); // '+'
}
// Always use US-ASCII digits
id.append(0x30 + (hour%100)/10);
id.append(0x30 + (hour%10));
id.append(0x3A); // ':'
id.append(0x30 + (min%100)/10);
id.append(0x30 + (min%10));
if (sec != 0) {
id.append(0x3A); // ':'
id.append(0x30 + (sec%100)/10);
id.append(0x30 + (sec%10));
}
}
return id;
}
U_NAMESPACE_END
#endif /* #if !UCONFIG_NO_FORMATTING */

View file

@ -1,6 +1,6 @@
/*
*******************************************************************************
* Copyright (C) 2007-2011, International Business Machines Corporation and *
* Copyright (C) 2007-2012, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*/
@ -87,10 +87,18 @@ public:
*/
static const UChar* U_EXPORT2 findMetaZoneID(const UnicodeString& mzid);
/**
* Creates a custom zone for the offset
* @param offset GMT offset in milliseconds
* @return A custom TimeZone for the offset with normalized time zone id
*/
static TimeZone* createCustomTimeZone(int32_t offset);
private:
ZoneMeta(); // Prevent construction.
static UVector* createMetazoneMappings(const UnicodeString &tzid);
static void initAvailableMetaZoneIDs();
static UnicodeString& formatCustomID(uint8_t hour, uint8_t min, uint8_t sec, UBool negative, UnicodeString& id);
};
U_NAMESPACE_END

View file

@ -2291,6 +2291,7 @@ void DateFormatTest::TestTimeZoneDisplayName()
const char *fallbackTests[][6] = {
{ "en", "America/Los_Angeles", "2004-01-15T00:00:00Z", "Z", "-0800", "-8:00" },
{ "en", "America/Los_Angeles", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-08:00", "-8:00" },
{ "en", "America/Los_Angeles", "2004-01-15T00:00:00Z", "ZZZZZ", "-08:00", "-8:00" },
{ "en", "America/Los_Angeles", "2004-01-15T00:00:00Z", "z", "PST", "America/Los_Angeles" },
{ "en", "America/Los_Angeles", "2004-01-15T00:00:00Z", "V", "PST", "America/Los_Angeles" },
{ "en", "America/Los_Angeles", "2004-01-15T00:00:00Z", "zzzz", "Pacific Standard Time", "America/Los_Angeles" },
@ -3423,8 +3424,10 @@ void DateFormatTest::TestGMTParsing() {
"HH:mm:ss zzzz", "10:20:30 UTC", "10:20:30 +0000", // standalone "UTC"
"ZZZZ HH:mm:ss", "UT 10:20:30", "10:20:30 +0000",
"V HH:mm:ss", "UT+0130 10:20:30", "10:20:30 +0130",
"V HH:mm:ss", "UTC+0130 10:20:30", NULL, // UTC+0130 is not a supported pattern
"V HH:mm:ss", "UTC+0130 10:20:30", "10:20:30 +0130",
"HH mm Z ss", "10 20 GMT-1100 30", "10:20:30 -1100",
"HH:mm:ssZZZZZ", "14:25:45Z", "14:25:45 +0000",
"HH:mm:ssZZZZZ", "15:00:00-08:00", "15:00:00 -0800",
};
const int32_t DATA_len = sizeof(DATA)/sizeof(DATA[0]);
expectParse(DATA, DATA_len, Locale("en"));

View file

@ -1,6 +1,6 @@
/*
*******************************************************************************
* Copyright (C) 2007-2011, International Business Machines Corporation and *
* Copyright (C) 2007-2012, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*/
@ -20,7 +20,7 @@
#include "unicode/basictz.h"
#include "cstring.h"
static const char* PATTERNS[] = {"z", "zzzz", "Z", "ZZZZ", "v", "vvvv", "V", "VVVV"};
static const char* PATTERNS[] = {"z", "zzzz", "Z", "ZZZZ", "ZZZZZ", "v", "vvvv", "V", "VVVV"};
static const int NUM_PATTERNS = sizeof(PATTERNS)/sizeof(const char*);
void
@ -202,13 +202,18 @@ TimeZoneFormatTest::TestTimeZoneRoundTrip(void) {
} else {
// Check if localized GMT format or RFC format is used.
int32_t numDigits = 0;
for (int n = 0; n < tzstr.length(); n++) {
if (u_isdigit(tzstr.charAt(n))) {
numDigits++;
UBool isOffsetFormat = (*PATTERNS[patidx] == 'Z');
if (!isOffsetFormat) {
// Check if localized GMT format is used as a fallback of name styles
int32_t numDigits = 0;
for (int n = 0; n < tzstr.length(); n++) {
if (u_isdigit(tzstr.charAt(n))) {
numDigits++;
}
}
isOffsetFormat = (numDigits >= 3);
}
if (tzstr == localGMTString || numDigits >= 3) {
if (isOffsetFormat || tzstr == localGMTString) {
// Localized GMT or RFC: total offset (raw + dst) must be preserved.
int32_t inOffset = inRaw + inDst;
int32_t outOffset = outRaw + outDst;
@ -260,9 +265,9 @@ public:
UBool REALLY_VERBOSE = FALSE;
// Whether each pattern is ambiguous at DST->STD local time overlap
UBool AMBIGUOUS_DST_DECESSION[] = { FALSE, FALSE, FALSE, FALSE, TRUE, TRUE, FALSE, TRUE };
UBool AMBIGUOUS_DST_DECESSION[] = { FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, TRUE, FALSE, TRUE };
// Whether each pattern is ambiguous at STD->STD/DST->DST local time overlap
UBool AMBIGUOUS_NEGATIVE_SHIFT[] = { TRUE, TRUE, FALSE, FALSE, TRUE, TRUE, TRUE, TRUE };
UBool AMBIGUOUS_NEGATIVE_SHIFT[] = { TRUE, TRUE, FALSE, FALSE, FALSE, TRUE, TRUE, TRUE, TRUE };
// Workaround for #6338
//UnicodeString BASEPATTERN("yyyy-MM-dd'T'HH:mm:ss.SSS");