ICU-8279 TimeZone API - getRegion in ICU4C

X-SVN-Rev: 29459
This commit is contained in:
Yoshito Umaoka 2011-02-18 23:03:47 +00:00
parent 48f462c307
commit 7c93a6eeac
5 changed files with 146 additions and 10 deletions
icu4c/source

View file

@ -1,6 +1,6 @@
/*
*******************************************************************************
* Copyright (C) 1997-2010, International Business Machines Corporation and *
* Copyright (C) 1997-2011, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*
@ -39,6 +39,7 @@
#include "unicode/utypes.h"
#include "unicode/ustring.h"
#include "ustr_imp.h"
#ifdef U_DEBUG_TZ
# include <stdio.h>
@ -103,6 +104,7 @@ static char gStrBuf[256];
static const UChar WORLD[] = {0x30, 0x30, 0x31, 0x00}; /* "001" */
static const UChar GMT_ID[] = {0x47, 0x4D, 0x54, 0x00}; /* "GMT" */
static const UChar UNKNOWN_ZONE_ID[] = {0x45, 0x74, 0x63, 0x2F, 0x55, 0x6E, 0x6B, 0x6E, 0x6F, 0x77, 0x6E, 0x00}; /* "Etc/Unknown" */
static const UChar Z_STR[] = {0x7A, 0x00}; /* "z" */
static const UChar ZZZZ_STR[] = {0x7A, 0x7A, 0x7A, 0x7A, 0x00}; /* "zzzz" */
static const UChar Z_UC_STR[] = {0x5A, 0x00}; /* "Z" */
@ -112,6 +114,7 @@ static const UChar VVVV_STR[] = {0x76, 0x76, 0x76, 0x76, 0x00}; /* "vvvv
static const UChar V_UC_STR[] = {0x56, 0x00}; /* "V" */
static const UChar VVVV_UC_STR[] = {0x56, 0x56, 0x56, 0x56, 0x00}; /* "VVVV" */
static const int32_t GMT_ID_LENGTH = 3;
static const int32_t UNKNOWN_ZONE_ID_LENGTH = 11;
static UMTX LOCK;
static UMTX TZSET_LOCK;
@ -942,7 +945,7 @@ TimeZone::dereferOlsonLink(const UnicodeString& id) {
const UChar*
TimeZone::getRegion(const UnicodeString& id) {
const UChar *result = WORLD;
const UChar *result = NULL;
UErrorCode ec = U_ZERO_ERROR;
UResourceBundle *rb = ures_openDirect(NULL, kZONEINFO, &ec);
@ -963,6 +966,38 @@ TimeZone::getRegion(const UnicodeString& id) {
return result;
}
// ---------------------------------------
int32_t
TimeZone::getRegion(const UnicodeString& id, char *region, int32_t capacity, UErrorCode& status)
{
int32_t resultLen = 0;
*region = 0;
if (U_FAILURE(status)) {
return 0;
}
const UChar *uregion = NULL;
// "Etc/Unknown" is not a system zone ID,
// but in the zone data
if (id.compare(UNKNOWN_ZONE_ID, UNKNOWN_ZONE_ID_LENGTH) != 0) {
uregion = getRegion(id);
}
if (uregion == NULL) {
status = U_ILLEGAL_ARGUMENT_ERROR;
return 0;
}
resultLen = u_strlen(uregion);
// A region code is represented by invariant characters
u_UCharsToChars(uregion, region, uprv_min(resultLen, capacity));
if (capacity < resultLen) {
status = U_BUFFER_OVERFLOW_ERROR;
return resultLen;
}
return u_terminateChars(region, capacity, resultLen, &status);
}
// ---------------------------------------

View file

@ -640,6 +640,26 @@ public:
*/
virtual int32_t getDSTSavings() const;
/**
* Gets the region code associated with the given
* system time zone ID. The region code is either ISO 3166
* 2-letter country code or UN M.49 3-digit area code.
* When the time zone is not associated with a specific location,
* for example - "Etc/UTC", "EST5EDT", then this method returns
* "001" (UN M.49 area code for World).
*
* @param id The system time zone ID.
* @param region Output buffer for receiving the region code.
* @param capacity The size of the output buffer.
* @param status Receives the status. When the given time zone ID
* is not a known system time zone ID,
* U_ILLEGAL_ARGUMENT_ERROR is set.
* @return The length of the output region code.
* @draft ICU 4.8
*/
static int32_t U_EXPORT2 getRegion(const UnicodeString& id,
char *region, int32_t capacity, UErrorCode& status);
protected:
/**
@ -680,6 +700,7 @@ protected:
*/
static UResourceBundle* loadRule(const UResourceBundle* top, const UnicodeString& ruleid, UResourceBundle* oldbundle, UErrorCode&status);
private:
friend class ZoneMeta;
@ -697,7 +718,8 @@ private:
static const UChar* dereferOlsonLink(const UnicodeString& id);
/**
* Returns the region code associated with the given zone.
* Returns the region code associated with the given zone,
* or NULL if the zone is not known.
* @param id zone id string
* @return the region associated with the given zone
*/

View file

@ -1,6 +1,6 @@
/*
*******************************************************************************
* Copyright (C) 2007-2010, International Business Machines Corporation and *
* Copyright (C) 2007-2011, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*/
@ -274,7 +274,7 @@ ZoneMeta::getCanonicalSystemID(const UnicodeString &tzid, UnicodeString &systemI
UnicodeString& U_EXPORT2
ZoneMeta::getCanonicalCountry(const UnicodeString &tzid, UnicodeString &canonicalCountry) {
const UChar *region = TimeZone::getRegion(tzid);
if (u_strcmp(gWorld, region) != 0) {
if (region != NULL && u_strcmp(gWorld, region) != 0) {
canonicalCountry.setTo(region, -1);
} else {
canonicalCountry.remove();
@ -286,8 +286,8 @@ UnicodeString& U_EXPORT2
ZoneMeta::getSingleCountry(const UnicodeString &tzid, UnicodeString &country) {
// Get canonical country for the zone
const UChar *region = TimeZone::getRegion(tzid);
if (u_strcmp(gWorld, region) == 0) {
// special case - "001"
if (region == NULL || u_strcmp(gWorld, region) == 0) {
// special case - unknown or "001"
country.remove();
return country;
}

View file

@ -1,6 +1,6 @@
/***********************************************************************
* COPYRIGHT:
* Copyright (c) 1997-2010, International Business Machines Corporation
* Copyright (c) 1997-2011, International Business Machines Corporation
* and others. All Rights Reserved.
***********************************************************************/
@ -61,6 +61,7 @@ void TimeZoneTest::runIndexedTest( int32_t index, UBool exec, const char* &name,
CASE(15, TestFebruary);
CASE(16, TestCanonicalID);
CASE(17, TestDisplayNamesMeta);
CASE(18, TestGetRegion);
default: name = ""; break;
}
}
@ -1976,4 +1977,80 @@ void TimeZoneTest::TestDisplayNamesMeta() {
}
}
void TimeZoneTest::TestGetRegion()
{
static const struct {
const char *id;
const char *region;
} data[] = {
{"America/Los_Angeles", "US"},
{"America/Indianapolis", "US"}, // CLDR canonical, Olson backward
{"America/Indiana/Indianapolis", "US"}, // CLDR alias
{"Mexico/General", "MX"}, // Link America/Mexico_City, Olson backward
{"Etc/UTC", "001"},
{"EST5EDT", "001"},
{"PST", "US"}, // Link America/Los_Angeles
{"Europe/Helsinki", "FI"},
{"Europe/Mariehamn", "AX"}, // Link Europe/Helsinki, but in zone.tab
{"Asia/Riyadh", "SA"},
{"Asia/Riyadh87", "001"}, // this should be "SA" actually, but not in zone.tab
{"Etc/Unknown", 0}, // CLDR canonical, but not a sysmte zone ID
{"bogus", 0}, // bogus
{"GMT+08:00", 0}, // a custom ID, not a system zone ID
{0, 0}
};
int32_t i;
char region[4];
UErrorCode sts;
for (i = 0; data[i].id; i++) {
sts = U_ZERO_ERROR;
TimeZone::getRegion(data[i].id, region, sizeof(region), sts);
if (U_SUCCESS(sts)) {
if (data[i].region == 0) {
errln((UnicodeString)"Fail: getRegion(\"" + data[i].id + "\") returns "
+ region + " [expected: U_ILLEGAL_ARGUMENT_ERROR]");
} else if (uprv_strcmp(region, data[i].region) != 0) {
errln((UnicodeString)"Fail: getRegion(\"" + data[i].id + "\") returns "
+ region + " [expected: " + data[i].region + "]");
}
} else if (sts == U_ILLEGAL_ARGUMENT_ERROR) {
if (data[i].region != 0) {
errln((UnicodeString)"Fail: getRegion(\"" + data[i].id
+ "\") returns error status U_ILLEGAL_ARGUMENT_ERROR [expected: "
+ data[i].region + "]");
}
} else {
errln((UnicodeString)"Fail: getRegion(\"" + data[i].id
+ "\") returns an unexpected error status");
}
}
// Extra test cases for short buffer
int32_t len;
char region2[2];
sts = U_ZERO_ERROR;
len = TimeZone::getRegion("America/New_York", region2, sizeof(region2), sts);
if (sts != U_STRING_NOT_TERMINATED_WARNING) {
errln("Expected U_STRING_NOT_TERMINATED_WARNING");
}
if (len != 2) { // length of "US"
errln("Incorrect result length");
}
if (uprv_strncmp(region2, "US", 2) != 0) {
errln("Incorrect result");
}
char region1[1];
sts = U_ZERO_ERROR;
len = TimeZone::getRegion("America/Chicago", region1, sizeof(region1), sts);
if (sts != U_BUFFER_OVERFLOW_ERROR) {
errln("Expected U_BUFFER_OVERFLOW_ERROR");
}
if (len != 2) { // length of "US"
errln("Incorrect result length");
}
}
#endif /* #if !UCONFIG_NO_FORMATTING */

View file

@ -1,6 +1,6 @@
/********************************************************************
* Copyright (c) 1997-2010, International Business Machines
* Copyright (c) 1997-2011, International Business Machines
* Corporation and others. All Rights Reserved.
********************************************************************/
@ -89,9 +89,11 @@ public:
void TestFebruary(void);
void TestCanonicalID(void);
virtual void TestDisplayNamesMeta();
void TestGetRegion(void);
static const UDate INTERVAL;
private: