mirror of
https://github.com/unicode-org/icu.git
synced 2025-04-20 20:19:32 +00:00
ICU-9606 Add ucal_getTimeZoneTransitionDate, UTimeZoneTransitionType and tests
X-SVN-Rev: 32545
This commit is contained in:
parent
6a81ec8327
commit
3e36b67cf7
3 changed files with 166 additions and 0 deletions
|
@ -727,4 +727,32 @@ ucal_getKeywordValuesForLocale(const char * /* key */, const char* locale, UBool
|
|||
return en;
|
||||
}
|
||||
|
||||
U_CAPI UBool U_EXPORT2
|
||||
ucal_getTimeZoneTransitionDate(const UCalendar* cal, UTimeZoneTransitionType type,
|
||||
UDate* transition, UErrorCode* status)
|
||||
{
|
||||
if (U_FAILURE(*status)) {
|
||||
return FALSE;
|
||||
}
|
||||
UDate base = ((Calendar*)cal)->getTime(*status);
|
||||
const TimeZone& tz = ((Calendar*)cal)->getTimeZone();
|
||||
// The reference returned from Calendar::getTimeZone() "is only valid until clients
|
||||
// make another call to adoptTimeZone or setTimeZone, or this Calendar is destroyed."
|
||||
// Add a mutex lock until after we clone (or fail)?
|
||||
const BasicTimeZone * btz = dynamic_cast<const BasicTimeZone *>(&tz);
|
||||
if (btz != NULL && U_SUCCESS(*status)) {
|
||||
TimeZoneTransition tzt;
|
||||
BasicTimeZone * btzClone = static_cast<BasicTimeZone *>(btz->clone()); // getNext/PreviousTransition are non-const
|
||||
UBool inclusive = (type == UCAL_TZ_TRANSITION_NEXT_INCLUSIVE || type == UCAL_TZ_TRANSITION_PREVIOUS_INCLUSIVE);
|
||||
UBool result = (type == UCAL_TZ_TRANSITION_NEXT || type == UCAL_TZ_TRANSITION_NEXT_INCLUSIVE)?
|
||||
btzClone->getNextTransition(base, inclusive, tzt):
|
||||
btzClone->getPreviousTransition(base, inclusive, tzt);
|
||||
if (result) {
|
||||
*transition = tzt.getTime();
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
#endif /* #if !UCONFIG_NO_FORMATTING */
|
||||
|
|
|
@ -1432,6 +1432,62 @@ ucal_getFieldDifference(UCalendar* cal,
|
|||
UCalendarDateFields field,
|
||||
UErrorCode* status);
|
||||
|
||||
#ifndef U_HIDE_DRAFT_API
|
||||
/**
|
||||
* Time zone transition types for ucal_getTimeZoneTransitionDate
|
||||
* @draft ICU 50
|
||||
*/
|
||||
enum UTimeZoneTransitionType {
|
||||
/**
|
||||
* Get the next transition after the current date,
|
||||
* i.e. excludes the current date
|
||||
* @draft ICU 50
|
||||
*/
|
||||
UCAL_TZ_TRANSITION_NEXT,
|
||||
/**
|
||||
* Get the next transition on or after the current date,
|
||||
* i.e. may include the current date
|
||||
* @draft ICU 50
|
||||
*/
|
||||
UCAL_TZ_TRANSITION_NEXT_INCLUSIVE,
|
||||
/**
|
||||
* Get the previous transition before the current date,
|
||||
* i.e. excludes the current date
|
||||
* @draft ICU 50
|
||||
*/
|
||||
UCAL_TZ_TRANSITION_PREVIOUS,
|
||||
/**
|
||||
* Get the previous transition on or before the current date,
|
||||
* i.e. may include the current date
|
||||
* @draft ICU 50
|
||||
*/
|
||||
UCAL_TZ_TRANSITION_PREVIOUS_INCLUSIVE
|
||||
};
|
||||
|
||||
/** @draft ICU 50 */
|
||||
typedef enum UTimeZoneTransitionType UTimeZoneTransitionType;
|
||||
|
||||
/**
|
||||
* Get the UDate for the next/previous time zone transition relative to
|
||||
* the calendar's current date, in the time zone to which the calendar
|
||||
* is currently set. If there is no known time zone transition of the
|
||||
* requested type relative to the calendar's date, the function returns
|
||||
* FALSE.
|
||||
* @param cal The UCalendar to query.
|
||||
* @param type The type of transition desired.
|
||||
* @param transition A pointer to a UDate to be set to the transition time.
|
||||
* If the function returns FALSE, the value set is unspecified.
|
||||
* @param status A pointer to a UErrorCode to receive any errors.
|
||||
* @return TRUE if a valid transition time is set in *transition, FALSE
|
||||
* otherwise.
|
||||
* @draft ICU 50
|
||||
*/
|
||||
U_DRAFT UBool U_EXPORT2
|
||||
ucal_getTimeZoneTransitionDate(const UCalendar* cal, UTimeZoneTransitionType type,
|
||||
UDate* transition, UErrorCode* status);
|
||||
|
||||
#endif /* U_HIDE_DRAFT_API */
|
||||
|
||||
#endif /* #if !UCONFIG_NO_FORMATTING */
|
||||
|
||||
#endif
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
void TestGregorianChange(void);
|
||||
void TestFieldDifference(void);
|
||||
void TestAddRollEra0AndEraBounds(void);
|
||||
void TestGetTZTransition(void);
|
||||
|
||||
void addCalTest(TestNode** root);
|
||||
|
||||
|
@ -52,6 +53,7 @@ void addCalTest(TestNode** root)
|
|||
addTest(root, &TestFieldDifference, "tsformat/ccaltst/TestFieldDifference");
|
||||
addTest(root, &TestAmbiguousWallTime, "tsformat/ccaltst/TestAmbiguousWallTime");
|
||||
addTest(root, &TestAddRollEra0AndEraBounds, "tsformat/ccaltst/TestAddRollEra0AndEraBounds");
|
||||
addTest(root, &TestGetTZTransition, "tsformat/ccaltst/TestGetTZTransition");
|
||||
}
|
||||
|
||||
/* "GMT" */
|
||||
|
@ -2186,4 +2188,84 @@ void TestAddRollEra0AndEraBounds() {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* TestGetTZTransition, for #9606
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
const char *descrip; /* test description */
|
||||
const UChar * zoneName; /* pointer to zero-terminated zone name */
|
||||
int32_t year; /* starting point for test is gregorian calendar noon on day specified by y,M,d here */
|
||||
int32_t month;
|
||||
int32_t day;
|
||||
UBool hasPrev; /* does it have a previous transition from starting point? If so we test inclusive from that */
|
||||
UBool hasNext; /* does it have a next transition from starting point? If so we test inclusive from that */
|
||||
} TZTransitionItem;
|
||||
|
||||
/* have zoneGMT above */
|
||||
static const UChar zoneUSPacific[] = { 0x55,0x53,0x2F,0x50,0x61,0x63,0x69,0x66,0x69,0x63,0 }; /* "US/Pacific" */
|
||||
static const UChar zoneCairo[] = { 0x41,0x66,0x72,0x69,0x63,0x61,0x2F,0x43,0x61,0x69,0x72,0x6F,0 }; /* "Africa/Cairo", DST cancelled since 2011 */
|
||||
static const UChar zoneIceland[] = { 0x41,0x74,0x6C,0x61,0x6E,0x74,0x69,0x63,0x2F,0x52,0x65,0x79,0x6B,0x6A,0x61,0x76,0x69,0x6B,0 }; /* "Atlantic/Reykjavik", always on DST (since when?) */
|
||||
|
||||
static const TZTransitionItem tzTransitionItems[] = {
|
||||
{ "USPacific mid 2012", zoneUSPacific, 2012, UCAL_JULY, 1, TRUE , TRUE },
|
||||
{ "USPacific mid 100", zoneUSPacific, 100, UCAL_JULY, 1, FALSE, TRUE }, /* no transitions before 100 CE... */
|
||||
{ "Cairo mid 2012", zoneCairo, 2012, UCAL_JULY, 1, TRUE , FALSE }, /* DST cancelled since 2011 */
|
||||
{ "Iceland mid 2012", zoneIceland, 2012, UCAL_JULY, 1, TRUE , FALSE }, /* always on DST */
|
||||
{ NULL, NULL, 0, 0, 0, FALSE, FALSE } /* terminator */
|
||||
};
|
||||
|
||||
void TestGetTZTransition() {
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
UCalendar * ucal = ucal_open(zoneGMT, -1, "en", UCAL_GREGORIAN, &status);
|
||||
if ( U_SUCCESS(status) ) {
|
||||
const TZTransitionItem * itemPtr;
|
||||
for (itemPtr = tzTransitionItems; itemPtr->descrip != NULL; itemPtr++) {
|
||||
UDate curMillis;
|
||||
ucal_setTimeZone(ucal, itemPtr->zoneName, -1, &status);
|
||||
ucal_setDateTime(ucal, itemPtr->year, itemPtr->month, itemPtr->day, 12, 0, 0, &status);
|
||||
curMillis = ucal_getMillis(ucal, &status);
|
||||
if ( U_SUCCESS(status) ) {
|
||||
UDate transition1, transition2;
|
||||
UBool result;
|
||||
|
||||
result = ucal_getTimeZoneTransitionDate(ucal, UCAL_TZ_TRANSITION_PREVIOUS, &transition1, &status);
|
||||
if (U_FAILURE(status) || result != itemPtr->hasPrev) {
|
||||
log_err("FAIL: %s ucal_getTimeZoneTransitionDate prev status %s, expected result %d but got %d\n",
|
||||
itemPtr->descrip, u_errorName(status), itemPtr->hasPrev, result);
|
||||
} else if (result) {
|
||||
ucal_setMillis(ucal, transition1, &status);
|
||||
result = ucal_getTimeZoneTransitionDate(ucal, UCAL_TZ_TRANSITION_PREVIOUS_INCLUSIVE, &transition2, &status);
|
||||
if (U_FAILURE(status) || !result || transition2 != transition1) {
|
||||
log_err("FAIL: %s ucal_getTimeZoneTransitionDate prev_inc status %s, result %d, expected date %.1f but got %.1f\n",
|
||||
itemPtr->descrip, u_errorName(status), result, transition1, transition2);
|
||||
}
|
||||
}
|
||||
status = U_ZERO_ERROR;
|
||||
|
||||
result = ucal_getTimeZoneTransitionDate(ucal, UCAL_TZ_TRANSITION_NEXT, &transition1, &status);
|
||||
if (U_FAILURE(status) || result != itemPtr->hasNext) {
|
||||
log_err("FAIL: %s ucal_getTimeZoneTransitionDate next status %s, expected result %d but got %d\n",
|
||||
itemPtr->descrip, u_errorName(status), itemPtr->hasNext, result);
|
||||
} else if (result) {
|
||||
ucal_setMillis(ucal, transition1, &status);
|
||||
result = ucal_getTimeZoneTransitionDate(ucal, UCAL_TZ_TRANSITION_NEXT_INCLUSIVE, &transition2, &status);
|
||||
if (U_FAILURE(status) || !result || transition2 != transition1) {
|
||||
log_err("FAIL: %s ucal_getTimeZoneTransitionDate next_inc status %s, result %d, expected date %.1f but got %.1f\n",
|
||||
itemPtr->descrip, u_errorName(status), result, transition1, transition2);
|
||||
}
|
||||
}
|
||||
status = U_ZERO_ERROR;
|
||||
} else {
|
||||
log_data_err("FAIL setup: can't setup calendar for %s, status %s\n",
|
||||
itemPtr->descrip, u_errorName(status));
|
||||
status = U_ZERO_ERROR;
|
||||
}
|
||||
}
|
||||
ucal_close(ucal);
|
||||
} else {
|
||||
log_data_err("FAIL setup: ucal_open status %s\n", u_errorName(status));
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* #if !UCONFIG_NO_FORMATTING */
|
||||
|
|
Loading…
Add table
Reference in a new issue