ICU-449 TimeZone equivalency support
X-SVN-Rev: 2523
This commit is contained in:
parent
741b94d474
commit
0f626e9c1e
@ -565,6 +565,34 @@ DateFormatSymbols::initializeData(const Locale& locale, UErrorCode& status, UBoo
|
|||||||
* @see java.util.SimpleTimeZone
|
* @see java.util.SimpleTimeZone
|
||||||
*/
|
*/
|
||||||
int32_t DateFormatSymbols::getZoneIndex(const UnicodeString& ID) const
|
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
|
// {sfb} kludge to support case-insensitive comparison
|
||||||
UnicodeString lcaseID(ID);
|
UnicodeString lcaseID(ID);
|
||||||
@ -573,8 +601,9 @@ int32_t DateFormatSymbols::getZoneIndex(const UnicodeString& ID) const
|
|||||||
for(int32_t index = 0; index < fZoneStringsRowCount; index++) {
|
for(int32_t index = 0; index < fZoneStringsRowCount; index++) {
|
||||||
UnicodeString lcase(fZoneStrings[index][0]);
|
UnicodeString lcase(fZoneStrings[index][0]);
|
||||||
lcase.toLower();
|
lcase.toLower();
|
||||||
if (lcaseID == lcase)
|
if (lcaseID == lcase) {
|
||||||
return index;
|
return index;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -218,6 +218,22 @@ TimeZone::createSystemTimeZone(const UnicodeString& name) {
|
|||||||
return 0;
|
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
|
// Perform a binary search. Possible optimization: Unroll the
|
||||||
// search. Not worth it given the small number of zones (416 in
|
// search. Not worth it given the small number of zones (416 in
|
||||||
// 1999j).
|
// 1999j).
|
||||||
@ -227,22 +243,15 @@ TimeZone::createSystemTimeZone(const UnicodeString& name) {
|
|||||||
// Invariant: match, if present, must be in the range [low,
|
// Invariant: match, if present, must be in the range [low,
|
||||||
// high).
|
// high).
|
||||||
uint32_t i = (low + high) / 2;
|
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) {
|
if (c == 0) {
|
||||||
const TZEquivalencyGroup *eg = (TZEquivalencyGroup*)
|
return (TZEquivalencyGroup*) ((int8_t*)DATA + INDEX_BY_ID[i]);
|
||||||
((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);
|
|
||||||
} else if (c < 0) {
|
} else if (c < 0) {
|
||||||
high = i;
|
high = i;
|
||||||
} else {
|
} else {
|
||||||
low = i + 1;
|
low = i + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
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&
|
UnicodeString&
|
||||||
TimeZone::getDisplayName(UnicodeString& result) const
|
TimeZone::getDisplayName(UnicodeString& result) const
|
||||||
|
@ -344,6 +344,9 @@ private:
|
|||||||
*/
|
*/
|
||||||
int32_t getZoneIndex(const UnicodeString& ID) const;
|
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
|
* Delete all the storage owned by this object and reset the fIsOwned flag
|
||||||
* to indicate that arrays have been deleted.
|
* to indicate that arrays have been deleted.
|
||||||
|
@ -34,6 +34,7 @@
|
|||||||
class SimpleTimeZone;
|
class SimpleTimeZone;
|
||||||
struct TZHeader;
|
struct TZHeader;
|
||||||
struct OffsetIndex;
|
struct OffsetIndex;
|
||||||
|
struct TZEquivalencyGroup;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <code>TimeZone</code> represents a time zone offset, and also figures out daylight
|
* <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);
|
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
|
* 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
|
* zone has already been set using adoptDefault() or setDefault(), the default is
|
||||||
@ -544,6 +583,9 @@ private:
|
|||||||
// See source file for documentation
|
// See source file for documentation
|
||||||
static TimeZone* createSystemTimeZone(const UnicodeString& name);
|
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
|
UnicodeString fID; // this time zone's ID
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
// class TimeZoneRegressionTest
|
// 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
|
void
|
||||||
TimeZoneRegressionTest::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ )
|
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");
|
// if (exec) logln((UnicodeString)"TestSuite NumberFormatRegressionTest");
|
||||||
switch (index) {
|
switch (index) {
|
||||||
|
|
||||||
CASE(0, Test4052967)
|
CASE(0, Test4052967);
|
||||||
CASE(1, Test4073209)
|
CASE(1, Test4073209);
|
||||||
CASE(2, Test4073215)
|
CASE(2, Test4073215);
|
||||||
CASE(3, Test4084933)
|
CASE(3, Test4084933);
|
||||||
CASE(4, Test4096952)
|
CASE(4, Test4096952);
|
||||||
CASE(5, Test4109314)
|
CASE(5, Test4109314);
|
||||||
CASE(6, Test4126678)
|
CASE(6, Test4126678);
|
||||||
CASE(7, Test4151406)
|
CASE(7, Test4151406);
|
||||||
CASE(8, Test4151429)
|
CASE(8, Test4151429);
|
||||||
CASE(9, Test4154537)
|
CASE(9, Test4154537);
|
||||||
CASE(10, Test4154542)
|
CASE(10, Test4154542);
|
||||||
CASE(11, Test4154650)
|
CASE(11, Test4154650);
|
||||||
CASE(12, Test4154525)
|
CASE(12, Test4154525);
|
||||||
CASE(13, Test4162593)
|
CASE(13, Test4162593);
|
||||||
CASE(14, TestJ186)
|
CASE(14, TestJ186);
|
||||||
CASE(15, TestJDK12API)
|
CASE(15, TestJ449);
|
||||||
|
CASE(16, TestJDK12API);
|
||||||
|
|
||||||
default: name = ""; break;
|
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
|
// test new API for JDK 1.2 8/31 putback
|
||||||
void
|
void
|
||||||
TimeZoneRegressionTest::TestJDK12API()
|
TimeZoneRegressionTest::TestJDK12API()
|
||||||
|
@ -40,6 +40,7 @@ public:
|
|||||||
void Test4154525(void);
|
void Test4154525(void);
|
||||||
void Test4162593(void);
|
void Test4162593(void);
|
||||||
void TestJ186(void);
|
void TestJ186(void);
|
||||||
|
void TestJ449(void);
|
||||||
void TestJDK12API(void);
|
void TestJDK12API(void);
|
||||||
|
|
||||||
UBool checkCalendar314(GregorianCalendar *testCal, TimeZone *testTZ);
|
UBool checkCalendar314(GregorianCalendar *testCal, TimeZone *testTZ);
|
||||||
|
Loading…
Reference in New Issue
Block a user