ICU-449 TimeZone equivalency support

X-SVN-Rev: 2523
This commit is contained in:
Alan Liu 2000-09-27 19:16:54 +00:00
parent 741b94d474
commit 0f626e9c1e
6 changed files with 202 additions and 27 deletions

View File

@ -565,6 +565,34 @@ DateFormatSymbols::initializeData(const Locale& locale, UErrorCode& status, UBoo
* @see java.util.SimpleTimeZone
*/
int32_t DateFormatSymbols::getZoneIndex(const UnicodeString& ID) const
{
int32_t result = _getZoneIndex(ID);
if (result >= 0) {
return result;
}
// Do a search through the equivalency group for the given ID
int32_t n = TimeZone::countEquivalentIDs(ID);
if (n > 1) {
int32_t i;
for (i=0; i<n; ++i) {
UnicodeString equivID = TimeZone::getEquivalentID(ID, i);
if (equivID != ID) {
int32_t equivResult = _getZoneIndex(equivID);
if (equivResult >= 0) {
return equivResult;
}
}
}
}
return -1;
}
/**
* Lookup the given ID. Do NOT do an equivalency search.
*/
int32_t DateFormatSymbols::_getZoneIndex(const UnicodeString& ID) const
{
// {sfb} kludge to support case-insensitive comparison
UnicodeString lcaseID(ID);
@ -573,8 +601,9 @@ int32_t DateFormatSymbols::getZoneIndex(const UnicodeString& ID) const
for(int32_t index = 0; index < fZoneStringsRowCount; index++) {
UnicodeString lcase(fZoneStrings[index][0]);
lcase.toLower();
if (lcaseID == lcase)
if (lcaseID == lcase) {
return index;
}
}
return -1;

View File

@ -218,6 +218,22 @@ TimeZone::createSystemTimeZone(const UnicodeString& name) {
return 0;
}
const TZEquivalencyGroup *eg = lookupEquivalencyGroup(name);
if (eg != 0) {
return eg->isDST ?
new SimpleTimeZone(eg->u.d.zone, name) :
new SimpleTimeZone(eg->u.s.zone, name);
}
return 0;
}
/**
* Lookup the given ID in the system time zone equivalency group table.
* Return a pointer to the equivalency group, or NULL if not found.
* DATA MUST BE INITIALIZED AND NON-NULL.
*/
const TZEquivalencyGroup*
TimeZone::lookupEquivalencyGroup(const UnicodeString& id) {
// Perform a binary search. Possible optimization: Unroll the
// search. Not worth it given the small number of zones (416 in
// 1999j).
@ -227,22 +243,15 @@ TimeZone::createSystemTimeZone(const UnicodeString& name) {
// Invariant: match, if present, must be in the range [low,
// high).
uint32_t i = (low + high) / 2;
int8_t c = name.compare(ZONE_IDS[i]);
int8_t c = id.compare(ZONE_IDS[i]);
if (c == 0) {
const TZEquivalencyGroup *eg = (TZEquivalencyGroup*)
((int8_t*)DATA + INDEX_BY_ID[i]);
// NOTE: standard zones must be before DST zones. We test
// for this when loading up the data; see loadZoneData().
return eg->isDST ?
new SimpleTimeZone(eg->u.d.zone, name) :
new SimpleTimeZone(eg->u.s.zone, name);
return (TZEquivalencyGroup*) ((int8_t*)DATA + INDEX_BY_ID[i]);
} else if (c < 0) {
high = i;
} else {
low = i + 1;
}
}
return 0;
}
@ -473,6 +482,39 @@ TimeZone::createAvailableIDs(int32_t& numIDs)
// ---------------------------------------
int32_t
TimeZone::countEquivalentIDs(const UnicodeString& id) {
if (!DATA_LOADED) {
loadZoneData();
}
if (0 == DATA) {
return 0;
}
const TZEquivalencyGroup *eg = lookupEquivalencyGroup(id);
return (eg != 0) ? (eg->isDST ? eg->u.d.count : eg->u.s.count) : 0;
}
// ---------------------------------------
const UnicodeString
TimeZone::getEquivalentID(const UnicodeString& id, int32_t index) {
if (!DATA_LOADED) {
loadZoneData();
}
if (0 != DATA) {
const TZEquivalencyGroup *eg = lookupEquivalencyGroup(id);
if (eg != 0) {
const uint16_t *p = eg->isDST ? &eg->u.d.count : &eg->u.s.count;
if (index >= 0 && index < *p) {
return ZONE_IDS[p[index+1]];
}
}
}
return UnicodeString();
}
// ---------------------------------------
UnicodeString&
TimeZone::getDisplayName(UnicodeString& result) const

View File

@ -344,6 +344,9 @@ private:
*/
int32_t getZoneIndex(const UnicodeString& ID) const;
// Internal method; see source for documentation
int32_t _getZoneIndex(const UnicodeString& id) const;
/**
* Delete all the storage owned by this object and reset the fIsOwned flag
* to indicate that arrays have been deleted.

View File

@ -34,6 +34,7 @@
class SimpleTimeZone;
struct TZHeader;
struct OffsetIndex;
struct TZEquivalencyGroup;
/**
* <code>TimeZone</code> represents a time zone offset, and also figures out daylight
@ -171,6 +172,44 @@ public:
*/
static const UnicodeString** const createAvailableIDs(int32_t& numIDs);
/**
* Returns the number of IDs in the equivalency group that
* includes the given ID. An equivalency group contains zones
* that have the same GMT offset and rules.
*
* <p>The returned count includes the given ID; it is always >= 1.
* The given ID must be a system time zone. If it is not, returns
* zero.
* @param id a system time zone ID
* @return the number of zones in the equivalency group containing
* 'id', or zero if 'id' is not a valid system ID
* @see #getEquivalentID
* @draft
*/
static int32_t countEquivalentIDs(const UnicodeString& id);
/**
* Returns an ID in the equivalency group that
* includes the given ID. An equivalency group contains zones
* that have the same GMT offset and rules.
*
* <p>The given index must be in the range 0..n-1, where n is the
* value returned by <code>countEquivalentIDs(id)</code>. For
* some value of 'index', the returned value will be equal to the
* given id. If the given id is not a valid system time zone, or
* if 'index' is out of range, then returns an empty string.
* @param id a system time zone ID
* @param index a value from 0 to n-1, where n is the value
* returned by <code>countEquivalentIDs(id)</code>
* @return the ID of the index-th zone in the equivalency group
* containing 'id', or an empty string if 'id' is not a valid
* system ID or 'index' is out of range
* @see #countEquivalentIDs
* @draft
*/
static const UnicodeString getEquivalentID(const UnicodeString& id,
int32_t index);
/**
* Creates a new copy of the default TimeZone for this host. Unless the default time
* zone has already been set using adoptDefault() or setDefault(), the default is
@ -544,6 +583,9 @@ private:
// See source file for documentation
static TimeZone* createSystemTimeZone(const UnicodeString& name);
// See source file for documentation
static const TZEquivalencyGroup* lookupEquivalencyGroup(const UnicodeString& id);
UnicodeString fID; // this time zone's ID
};

View File

@ -17,7 +17,7 @@
// class TimeZoneRegressionTest
// *****************************************************************************
#define CASE(id,test) case id: name = #test; if (exec) { logln(#test "---"); logln((UnicodeString)""); test(); } break;
#define CASE(id,test) case id: name = #test; if (exec) { logln(#test "---"); logln((UnicodeString)""); test(); } break
void
TimeZoneRegressionTest::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ )
@ -25,22 +25,23 @@ TimeZoneRegressionTest::runIndexedTest( int32_t index, UBool exec, const char* &
// if (exec) logln((UnicodeString)"TestSuite NumberFormatRegressionTest");
switch (index) {
CASE(0, Test4052967)
CASE(1, Test4073209)
CASE(2, Test4073215)
CASE(3, Test4084933)
CASE(4, Test4096952)
CASE(5, Test4109314)
CASE(6, Test4126678)
CASE(7, Test4151406)
CASE(8, Test4151429)
CASE(9, Test4154537)
CASE(10, Test4154542)
CASE(11, Test4154650)
CASE(12, Test4154525)
CASE(13, Test4162593)
CASE(14, TestJ186)
CASE(15, TestJDK12API)
CASE(0, Test4052967);
CASE(1, Test4073209);
CASE(2, Test4073215);
CASE(3, Test4084933);
CASE(4, Test4096952);
CASE(5, Test4109314);
CASE(6, Test4126678);
CASE(7, Test4151406);
CASE(8, Test4151429);
CASE(9, Test4154537);
CASE(10, Test4154542);
CASE(11, Test4154650);
CASE(12, Test4154525);
CASE(13, Test4162593);
CASE(14, TestJ186);
CASE(15, TestJ449);
CASE(16, TestJDK12API);
default: name = ""; break;
}
@ -877,6 +878,63 @@ void TimeZoneRegressionTest::TestJ186() {
}
}
/**
* Test to see if DateFormat understands zone equivalency groups. It
* might seem that this should be a DateFormat test, but it's really a
* TimeZone test -- the changes to DateFormat are minor.
*
* We use two known, stable zones that shouldn't change much over time
* -- America/Vancouver and America/Los_Angeles. However, they MAY
* change at some point -- if that happens, replace them with any two
* zones in an equivalency group where one zone has localized name
* data, and the other doesn't, in some locale.
*/
void TimeZoneRegressionTest::TestJ449() {
UErrorCode status = U_ZERO_ERROR;
UnicodeString str;
// Modify the following three as necessary. The two IDs must
// specify two zones in the same equivalency group. One must have
// locale data in 'loc'; the other must not.
const char* idWithLocaleData = "America/Los_Angeles";
const char* idWithoutLocaleData = "America/Vancouver";
const Locale loc("en", "", "");
TimeZone *zoneWith = TimeZone::createTimeZone(idWithLocaleData);
TimeZone *zoneWithout = TimeZone::createTimeZone(idWithoutLocaleData);
// Make sure we got valid zones
if (zoneWith->getID(str) != UnicodeString(idWithLocaleData) ||
zoneWithout->getID(str) != UnicodeString(idWithoutLocaleData)) {
errln("Fail: Unable to create zones");
} else {
GregorianCalendar calWith(*zoneWith, status);
GregorianCalendar calWithout(*zoneWithout, status);
SimpleDateFormat fmt("MMM d yyyy hh:mm a zzz", loc, status);
if (U_FAILURE(status)) {
errln("Fail: Unable to create GregorianCalendar/SimpleDateFormat");
} else {
UDate date = 0;
UnicodeString strWith, strWithout;
fmt.setCalendar(calWith);
fmt.format(date, strWith);
fmt.setCalendar(calWithout);
fmt.format(date, strWithout);
if (strWith == strWithout) {
logln((UnicodeString)"Ok: " + idWithLocaleData + " -> " +
strWith + "; " + idWithoutLocaleData + " -> " +
strWithout);
} else {
errln((UnicodeString)"FAIL: " + idWithLocaleData + " -> " +
strWith + "; " + idWithoutLocaleData + " -> " +
strWithout);
}
}
}
delete zoneWith;
delete zoneWithout;
}
// test new API for JDK 1.2 8/31 putback
void
TimeZoneRegressionTest::TestJDK12API()

View File

@ -40,6 +40,7 @@ public:
void Test4154525(void);
void Test4162593(void);
void TestJ186(void);
void TestJ449(void);
void TestJDK12API(void);
UBool checkCalendar314(GregorianCalendar *testCal, TimeZone *testTZ);