ICU-5708 Generic time zone support
X-SVN-Rev: 22283
This commit is contained in:
parent
3727ad903b
commit
a2d03cc0fb
@ -19,13 +19,13 @@
|
||||
* 10/12/05 emmons Added setters for eraNames, month/day by width/context
|
||||
*******************************************************************************
|
||||
*/
|
||||
|
||||
#include "unicode/utypes.h"
|
||||
|
||||
#if !UCONFIG_NO_FORMATTING
|
||||
#include "unicode/ustring.h"
|
||||
#include "unicode/dtfmtsym.h"
|
||||
#include "unicode/smpdtfmt.h"
|
||||
#include "unicode/msgfmt.h"
|
||||
#include "cpputils.h"
|
||||
#include "ucln_in.h"
|
||||
#include "umutex.h"
|
||||
@ -173,6 +173,12 @@ static const char gAmPmMarkersTag[]="AmPmMarkers";
|
||||
static const char gQuartersTag[]="quarters";
|
||||
static const char gMaptimezonesTag[]="mapTimezones";
|
||||
static const char gMetazonesTag[]="metazones";
|
||||
static const char gTerritoryTag[]="territory";
|
||||
static const char gCountriesTag[]="Countries";
|
||||
static const char gZoneFormattingTag[]="zoneFormatting";
|
||||
static const char gMultizoneTag[]="multizone";
|
||||
static const char gRegionFormatTag[]="zoneStrings/regionFormat";
|
||||
static const char gFallbackFormatTag[]="zoneStrings/fallbackFormat";
|
||||
|
||||
/**
|
||||
* These are the tags we expect to see in time zone data resource bundle files
|
||||
@ -1977,6 +1983,106 @@ DateFormatSymbols::getMetazoneString(const UnicodeString &zid, const TimeZoneTra
|
||||
ures_close(um);
|
||||
return result;
|
||||
}
|
||||
|
||||
UnicodeString&
|
||||
DateFormatSymbols::getFallbackString(const UnicodeString &zid, UnicodeString &result, UErrorCode &status)
|
||||
{
|
||||
UnicodeString exemplarCity;
|
||||
char zidkey[ZID_KEY_MAX];
|
||||
char zoneTerritoryChars[ULOC_COUNTRY_CAPACITY];
|
||||
UnicodeString displayCountry;
|
||||
UnicodeString solidus = UNICODE_STRING_SIMPLE("/");
|
||||
UnicodeString und = UNICODE_STRING_SIMPLE("_");
|
||||
UnicodeString spc = UNICODE_STRING_SIMPLE(" ");
|
||||
const UChar* aZone = NULL;
|
||||
UBool IsMultiZone = FALSE;
|
||||
|
||||
|
||||
int32_t len = zid.length();
|
||||
len = (len >= (ZID_KEY_MAX-1) ? ZID_KEY_MAX-1 : len);
|
||||
u_UCharsToChars(zid.getBuffer(), zidkey, len);
|
||||
zidkey[len] = 0; // NULL terminate
|
||||
|
||||
// Replace / with : for zid
|
||||
len = (int32_t)uprv_strlen(zidkey);
|
||||
for (int i = 0; i < len; i++) {
|
||||
if (zidkey[i] == '/') {
|
||||
zidkey[i] = ':';
|
||||
}
|
||||
}
|
||||
|
||||
result.remove();
|
||||
|
||||
UResourceBundle* supplementalDataBundle = ures_openDirect(NULL, kSUPPLEMENTAL, &status);
|
||||
if (U_FAILURE(status) || fResourceBundle == NULL ) {
|
||||
return result;
|
||||
}
|
||||
|
||||
UResourceBundle* zoneFormatting = ures_getByKey(supplementalDataBundle, gZoneFormattingTag, NULL, &status);
|
||||
UResourceBundle* thisZone = ures_getByKey(zoneFormatting, zidkey, NULL, &status);
|
||||
if (U_FAILURE(status)) {
|
||||
ures_close(zoneFormatting);
|
||||
ures_close(supplementalDataBundle);
|
||||
return result;
|
||||
}
|
||||
|
||||
UResourceBundle* multiZone = ures_getByKey(zoneFormatting, gMultizoneTag, NULL, &status);
|
||||
const UChar *zoneTerritory = ures_getStringByKey(thisZone,gTerritoryTag,&len,&status);
|
||||
u_UCharsToChars(zoneTerritory, zoneTerritoryChars, u_strlen(zoneTerritory));
|
||||
zoneTerritoryChars[u_strlen(zoneTerritory)] = 0; // NULL terminate
|
||||
|
||||
UResourceBundle* countries = ures_getByKey(fResourceBundle, gCountriesTag, NULL, &status);
|
||||
if ( u_strlen(zoneTerritory) > 0 && countries != NULL ) {
|
||||
displayCountry = ures_getStringByKeyWithFallback(countries,zoneTerritoryChars,&len,&status);
|
||||
}
|
||||
|
||||
if ( U_FAILURE(status) ) {
|
||||
status = U_ZERO_ERROR;
|
||||
displayCountry = UnicodeString(zoneTerritory);
|
||||
}
|
||||
|
||||
while ( ures_hasNext(multiZone) ) {
|
||||
aZone = ures_getNextString(multiZone,&len,NULL,&status);
|
||||
if ( u_strcmp(aZone,zoneTerritory) == 0 ) {
|
||||
IsMultiZone = TRUE;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if ( IsMultiZone ) {
|
||||
getZoneString(zid, TIMEZONE_EXEMPLAR_CITY, exemplarCity, status);
|
||||
if ( exemplarCity.length()==0 ) {
|
||||
exemplarCity.setTo(UnicodeString(zid,zid.lastIndexOf(solidus)+1));
|
||||
exemplarCity.findAndReplace(und,spc);
|
||||
}
|
||||
Formattable cityCountryArray[2];
|
||||
UnicodeString pattern = UnicodeString(ures_getStringByKeyWithFallback(fResourceBundle,gFallbackFormatTag,&len,&status));
|
||||
if ( U_FAILURE(status) ) {
|
||||
pattern = UNICODE_STRING_SIMPLE("{1} ({0})");
|
||||
status = U_ZERO_ERROR;
|
||||
}
|
||||
cityCountryArray[0].adoptString(new UnicodeString(exemplarCity));
|
||||
cityCountryArray[1].adoptString(new UnicodeString(displayCountry));
|
||||
MessageFormat::format(pattern,cityCountryArray, 2, result, status);
|
||||
} else {
|
||||
Formattable countryArray[1];
|
||||
UnicodeString pattern = UnicodeString(ures_getStringByKeyWithFallback(fResourceBundle,gRegionFormatTag,&len,&status));
|
||||
if ( U_FAILURE(status) ) {
|
||||
pattern = UNICODE_STRING_SIMPLE("{0}");
|
||||
status = U_ZERO_ERROR;
|
||||
}
|
||||
countryArray[0].adoptString(new UnicodeString(displayCountry));
|
||||
MessageFormat::format(pattern,countryArray, 1, result, status);
|
||||
}
|
||||
|
||||
if (thisZone) ures_close(thisZone);
|
||||
if (zoneFormatting) ures_close(zoneFormatting);
|
||||
if (supplementalDataBundle) ures_close(supplementalDataBundle);
|
||||
if (countries) ures_close(countries);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
StringEnumeration*
|
||||
DateFormatSymbols::createZoneStringIDs(UErrorCode &status){
|
||||
if(U_FAILURE(status)){
|
||||
@ -2132,13 +2238,38 @@ DateFormatSymbols::findZoneIDTypeValue( UnicodeString& zid, const UnicodeString&
|
||||
if (myKey->startsWith(UNICODE_STRING_SIMPLE("meta"))) {
|
||||
zid.setTo(resolveParsedMetazone(*myKey));
|
||||
}
|
||||
else
|
||||
else {
|
||||
zid.setTo(*myKey);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check for generic tz fallback strings if we have gone through all zone strings and haven't found
|
||||
// anything.
|
||||
|
||||
UnicodeString fbString;
|
||||
StringEnumeration *tzKeys = TimeZone::createEnumeration();
|
||||
|
||||
tzKeys->reset(status);
|
||||
while( (myKey=tzKeys->snext(status))!= NULL){
|
||||
char outpt[1000];
|
||||
status = U_ZERO_ERROR;
|
||||
this->getFallbackString(*myKey,fbString,status);
|
||||
if ( U_FAILURE(status) ) {
|
||||
status = U_ZERO_ERROR;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(fbString.length()>0 && text.compare(start, fbString.length(), fbString)==0){
|
||||
type = (TimeZoneTranslationType) TIMEZONE_LONG_GENERIC;
|
||||
value.setTo(fbString);
|
||||
zid.setTo(*myKey);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
UnicodeString
|
||||
|
@ -24,6 +24,8 @@
|
||||
********************************************************************************
|
||||
*/
|
||||
|
||||
#define ZID_KEY_MAX 128
|
||||
|
||||
#include "unicode/utypes.h"
|
||||
|
||||
#if !UCONFIG_NO_FORMATTING
|
||||
@ -81,6 +83,9 @@ static const UChar SUPPRESS_NEGATIVE_PREFIX[] = {0xAB00, 0};
|
||||
* These are the tags we expect to see in normal resource bundle files associated
|
||||
* with a locale.
|
||||
*/
|
||||
static const char kSUPPLEMENTAL[]="supplementalData";
|
||||
static const char gZoneFormattingTag[]="zoneFormatting";
|
||||
static const char gAliases[]="aliases";
|
||||
static const char gDateTimePatternsTag[]="DateTimePatterns";
|
||||
|
||||
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(SimpleDateFormat)
|
||||
@ -780,16 +785,20 @@ SimpleDateFormat::subFormat(UnicodeString &appendTo,
|
||||
appendGMT(appendTo, cal, status);
|
||||
}
|
||||
else {
|
||||
|
||||
zoneIDCanonicalize(zid);
|
||||
if (patternCharIndex == UDAT_TIMEZONE_GENERIC_FIELD) {
|
||||
if(count < 4){
|
||||
fSymbols->getZoneString(zid, DateFormatSymbols::TIMEZONE_SHORT_GENERIC, displayString, status);
|
||||
if(displayString.length()==0)
|
||||
fSymbols->getMetazoneString(zid, DateFormatSymbols::TIMEZONE_SHORT_GENERIC, cal, displayString, status);
|
||||
if(displayString.length()==0)
|
||||
fSymbols->getFallbackString(zid, displayString, status);
|
||||
}else{
|
||||
fSymbols->getZoneString(zid, DateFormatSymbols::TIMEZONE_LONG_GENERIC, displayString, status);
|
||||
if(displayString.length()==0)
|
||||
fSymbols->getMetazoneString(zid, DateFormatSymbols::TIMEZONE_LONG_GENERIC, cal, displayString, status);
|
||||
if(displayString.length()==0)
|
||||
fSymbols->getFallbackString(zid, displayString, status);
|
||||
}
|
||||
} else {
|
||||
if (cal.get(UCAL_DST_OFFSET, status) != 0) {
|
||||
@ -876,7 +885,86 @@ SimpleDateFormat::subFormat(UnicodeString &appendTo,
|
||||
pos.setEndIndex(appendTo.length());
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
void
|
||||
SimpleDateFormat::zoneIDCanonicalize(UnicodeString &zid) const
|
||||
{
|
||||
UnicodeString colon = UNICODE_STRING_SIMPLE(":");
|
||||
UnicodeString solidus = UNICODE_STRING_SIMPLE("/");
|
||||
char zidkey[ZID_KEY_MAX];
|
||||
int32_t len;
|
||||
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
UResourceBundle* supplementalDataBundle = ures_openDirect(NULL, kSUPPLEMENTAL, &status);
|
||||
if (U_FAILURE(status)) {
|
||||
return;
|
||||
}
|
||||
|
||||
UResourceBundle* zoneFormatting = ures_getByKey(supplementalDataBundle, gZoneFormattingTag, NULL, &status);
|
||||
|
||||
// First try to lookup the zone itself, since most of the time the canonical ID and the ID itself
|
||||
// will be the same. This should save us a significant amount of time.
|
||||
|
||||
len = zid.length();
|
||||
len = (len >= (ZID_KEY_MAX-1) ? ZID_KEY_MAX-1 : len);
|
||||
u_UCharsToChars(zid.getBuffer(), zidkey, len);
|
||||
zidkey[len] = 0; // NULL terminate
|
||||
|
||||
// Replace / with : for zid
|
||||
len = (int32_t)uprv_strlen(zidkey);
|
||||
for (int i = 0; i < len; i++) {
|
||||
if (zidkey[i] == '/') {
|
||||
zidkey[i] = ':';
|
||||
}
|
||||
}
|
||||
|
||||
UResourceBundle* tryThisZone = ures_getByKey(zoneFormatting,zidkey,NULL,&status);
|
||||
if (U_SUCCESS(status)) {
|
||||
ures_close(tryThisZone);
|
||||
ures_close(zoneFormatting);
|
||||
ures_close(supplementalDataBundle);
|
||||
return;
|
||||
}
|
||||
|
||||
// Didn't find it, so go searching for an alias
|
||||
|
||||
while ( ures_hasNext(zoneFormatting)) {
|
||||
UResourceBundle *currentZone = ures_getNextResource(zoneFormatting,NULL,&status);
|
||||
if (U_FAILURE(status)) {
|
||||
ures_close(supplementalDataBundle);
|
||||
return;
|
||||
}
|
||||
|
||||
const char *currentZoneString= ures_getKey(currentZone);
|
||||
|
||||
UResourceBundle *zoneAliases = ures_getByKey(currentZone,gAliases,NULL, &status);
|
||||
if (U_FAILURE(status)) {
|
||||
status = U_ZERO_ERROR;
|
||||
ures_close(currentZone);
|
||||
continue;
|
||||
}
|
||||
while ( ures_hasNext(zoneAliases)) {
|
||||
int32_t len;
|
||||
const UChar* alias = ures_getNextString(zoneAliases,&len,NULL,&status);
|
||||
if ( zid.compare(alias)==0 ) {
|
||||
zid.setTo(UnicodeString(currentZoneString,(const char *)0));
|
||||
zid.findAndReplace(colon,solidus);
|
||||
ures_close(zoneAliases);
|
||||
ures_close(currentZone);
|
||||
ures_close(zoneFormatting);
|
||||
ures_close(supplementalDataBundle);
|
||||
return;
|
||||
}
|
||||
}
|
||||
ures_close(zoneAliases);
|
||||
ures_close(currentZone);
|
||||
}
|
||||
ures_close(zoneFormatting);
|
||||
ures_close(supplementalDataBundle);
|
||||
|
||||
return;
|
||||
}
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
void
|
||||
|
@ -497,6 +497,18 @@ public:
|
||||
*/
|
||||
UnicodeString& getMetazoneString(const UnicodeString &ID, const TimeZoneTranslationType type, Calendar &cal, UnicodeString &result, UErrorCode &status);
|
||||
|
||||
/**
|
||||
* Gets fallback string given the key
|
||||
* @param ID The ID of zone strings, e.g: "America/Los_Angeles".
|
||||
* The time zone ID is for programmatic lookup.
|
||||
* @param result Output parameter to recieve the translation string
|
||||
* @param status Input/output parameter, set to success or
|
||||
* failure code upon return.
|
||||
* @return the input UnicodeString parameter for chaining
|
||||
* @internal ICU 3.8
|
||||
*/
|
||||
UnicodeString& getFallbackString(const UnicodeString &ID, UnicodeString &result, UErrorCode &status);
|
||||
|
||||
/**
|
||||
* Sets timezone string for the given the ID and translation type
|
||||
* @param ID The ID of zone strings, e.g: "America/Los_Angeles".
|
||||
|
@ -649,6 +649,13 @@ private:
|
||||
Calendar& cal,
|
||||
UErrorCode& status) const; // in case of illegal argument
|
||||
|
||||
/**
|
||||
* Used to resolve Time Zone aliases
|
||||
*
|
||||
* @param zid Time Zone ID to Canonicalize ( resolve aliases )
|
||||
*/
|
||||
void zoneIDCanonicalize( UnicodeString & ) const;
|
||||
|
||||
/**
|
||||
* Used by subFormat() to format a numeric value.
|
||||
* Appends to toAppendTo a string representation of "value"
|
||||
|
@ -914,8 +914,6 @@ void TimeZoneTest::TestCustomParse()
|
||||
}
|
||||
}
|
||||
|
||||
static const UVersionInfo ICU_39 = {3,9,0,0};
|
||||
|
||||
void
|
||||
TimeZoneTest::TestAliasedNames()
|
||||
{
|
||||
@ -1047,10 +1045,6 @@ TimeZoneTest::TestAliasedNames()
|
||||
UBool useDst[] = { FALSE, TRUE };
|
||||
int32_t noLoc = uloc_countAvailable();
|
||||
|
||||
if(isICUVersionAtLeast(ICU_39)) {
|
||||
errln("This test needs to be fixed. This test fails in exhaustive mode because we need to implement generic timezones.\n");
|
||||
}
|
||||
|
||||
int32_t i, j, k, loc;
|
||||
UnicodeString fromName, toName;
|
||||
TimeZone *from = NULL, *to = NULL;
|
||||
@ -1060,8 +1054,7 @@ TimeZoneTest::TestAliasedNames()
|
||||
if(!from->hasSameRules(*to)) {
|
||||
errln("different at %i\n", i);
|
||||
}
|
||||
if(!quick && isICUVersionAtLeast(ICU_39)) {
|
||||
errln("This test needs to be fixed. This test fails in exhaustive mode because we need to implement generic timezones.\n");
|
||||
if(!quick) {
|
||||
for(loc = 0; loc < noLoc; loc++) {
|
||||
const char* locale = uloc_getAvailable(loc);
|
||||
for(j = 0; j < (int32_t)(sizeof(styles)/sizeof(styles[0])); j++) {
|
||||
|
Loading…
Reference in New Issue
Block a user