mirror of
https://github.com/unicode-org/icu.git
synced 2025-04-07 06:25:30 +00:00
ICU-10544 Fixed some implementation problems in Calendar::add. When adding day or larger field results wall time falls into non-existing time slot created by DST transition, the implementation honors the current skipped wall time option.
X-SVN-Rev: 35231
This commit is contained in:
parent
c2ba26e8ba
commit
f7f73fe88d
4 changed files with 299 additions and 56 deletions
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
*******************************************************************************
|
||||
* Copyright (C) 1997-2013, International Business Machines Corporation and *
|
||||
* Copyright (C) 1997-2014, International Business Machines Corporation and *
|
||||
* others. All Rights Reserved. *
|
||||
*******************************************************************************
|
||||
*
|
||||
|
@ -1894,10 +1894,10 @@ void Calendar::add(UCalendarDateFields field, int32_t amount, UErrorCode& status
|
|||
// a computed amount of millis to the current millis. The only
|
||||
// wrinkle is with DST (and/or a change to the zone's UTC offset, which
|
||||
// we'll include with DST) -- for some fields, like the DAY_OF_MONTH,
|
||||
// we don't want the HOUR to shift due to changes in DST. If the
|
||||
// we don't want the wall time to shift due to changes in DST. If the
|
||||
// result of the add operation is to move from DST to Standard, or
|
||||
// vice versa, we need to adjust by an hour forward or back,
|
||||
// respectively. For such fields we set keepHourInvariant to TRUE.
|
||||
// respectively. For such fields we set keepWallTimeInvariant to TRUE.
|
||||
|
||||
// We only adjust the DST for fields larger than an hour. For
|
||||
// fields smaller than an hour, we cannot adjust for DST without
|
||||
|
@ -1912,7 +1912,7 @@ void Calendar::add(UCalendarDateFields field, int32_t amount, UErrorCode& status
|
|||
// <April 30>, rather than <April 31> => <May 1>.
|
||||
|
||||
double delta = amount; // delta in ms
|
||||
UBool keepHourInvariant = TRUE;
|
||||
UBool keepWallTimeInvariant = TRUE;
|
||||
|
||||
switch (field) {
|
||||
case UCAL_ERA:
|
||||
|
@ -1974,22 +1974,22 @@ void Calendar::add(UCalendarDateFields field, int32_t amount, UErrorCode& status
|
|||
case UCAL_HOUR_OF_DAY:
|
||||
case UCAL_HOUR:
|
||||
delta *= kOneHour;
|
||||
keepHourInvariant = FALSE;
|
||||
keepWallTimeInvariant = FALSE;
|
||||
break;
|
||||
|
||||
case UCAL_MINUTE:
|
||||
delta *= kOneMinute;
|
||||
keepHourInvariant = FALSE;
|
||||
keepWallTimeInvariant = FALSE;
|
||||
break;
|
||||
|
||||
case UCAL_SECOND:
|
||||
delta *= kOneSecond;
|
||||
keepHourInvariant = FALSE;
|
||||
keepWallTimeInvariant = FALSE;
|
||||
break;
|
||||
|
||||
case UCAL_MILLISECOND:
|
||||
case UCAL_MILLISECONDS_IN_DAY:
|
||||
keepHourInvariant = FALSE;
|
||||
keepWallTimeInvariant = FALSE;
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -2003,41 +2003,61 @@ void Calendar::add(UCalendarDateFields field, int32_t amount, UErrorCode& status
|
|||
// ") not supported");
|
||||
}
|
||||
|
||||
// In order to keep the hour invariant (for fields where this is
|
||||
// In order to keep the wall time invariant (for fields where this is
|
||||
// appropriate), check the combined DST & ZONE offset before and
|
||||
// after the add() operation. If it changes, then adjust the millis
|
||||
// to compensate.
|
||||
int32_t prevOffset = 0;
|
||||
int32_t hour = 0;
|
||||
if (keepHourInvariant) {
|
||||
int32_t prevWallTime = 0;
|
||||
if (keepWallTimeInvariant) {
|
||||
prevOffset = get(UCAL_DST_OFFSET, status) + get(UCAL_ZONE_OFFSET, status);
|
||||
hour = internalGet(UCAL_HOUR_OF_DAY);
|
||||
prevWallTime = get(UCAL_MILLISECONDS_IN_DAY, status);
|
||||
}
|
||||
|
||||
setTimeInMillis(getTimeInMillis(status) + delta, status);
|
||||
|
||||
if (keepHourInvariant) {
|
||||
int32_t newOffset = get(UCAL_DST_OFFSET, status) + get(UCAL_ZONE_OFFSET, status);
|
||||
if (newOffset != prevOffset) {
|
||||
// We have done an hour-invariant adjustment but the
|
||||
// combined offset has changed. We adjust millis to keep
|
||||
// the hour constant. In cases such as midnight after
|
||||
// a DST change which occurs at midnight, there is the
|
||||
// danger of adjusting into a different day. To avoid
|
||||
// this we make the adjustment only if it actually
|
||||
// maintains the hour.
|
||||
|
||||
// When the difference of the previous UTC offset and
|
||||
// the new UTC offset exceeds 1 full day, we do not want
|
||||
// to roll over/back the date. For now, this only happens
|
||||
// in Samoa (Pacific/Apia) on Dec 30, 2011. See ticket:9452.
|
||||
int32_t adjAmount = prevOffset - newOffset;
|
||||
adjAmount = adjAmount >= 0 ? adjAmount % (int32_t)kOneDay : -(-adjAmount % (int32_t)kOneDay);
|
||||
if (adjAmount != 0) {
|
||||
double t = internalGetTime();
|
||||
setTimeInMillis(t + adjAmount, status);
|
||||
if (get(UCAL_HOUR_OF_DAY, status) != hour) {
|
||||
setTimeInMillis(t, status);
|
||||
if (keepWallTimeInvariant) {
|
||||
int32_t newWallTime = get(UCAL_MILLISECONDS_IN_DAY, status);
|
||||
if (newWallTime != prevWallTime) {
|
||||
// There is at least one zone transition between the base
|
||||
// time and the result time. As the result, wall time has
|
||||
// changed.
|
||||
UDate t = internalGetTime();
|
||||
int32_t newOffset = get(UCAL_DST_OFFSET, status) + get(UCAL_ZONE_OFFSET, status);
|
||||
if (newOffset != prevOffset) {
|
||||
// When the difference of the previous UTC offset and
|
||||
// the new UTC offset exceeds 1 full day, we do not want
|
||||
// to roll over/back the date. For now, this only happens
|
||||
// in Samoa (Pacific/Apia) on Dec 30, 2011. See ticket:9452.
|
||||
int32_t adjAmount = prevOffset - newOffset;
|
||||
adjAmount = adjAmount >= 0 ? adjAmount % (int32_t)kOneDay : -(-adjAmount % (int32_t)kOneDay);
|
||||
if (adjAmount != 0) {
|
||||
setTimeInMillis(t + adjAmount, status);
|
||||
newWallTime = get(UCAL_MILLISECONDS_IN_DAY, status);
|
||||
}
|
||||
if (newWallTime != prevWallTime) {
|
||||
// The result wall time or adjusted wall time was shifted because
|
||||
// the target wall time does not exist on the result date.
|
||||
switch (fSkippedWallTime) {
|
||||
case UCAL_WALLTIME_FIRST:
|
||||
if (adjAmount > 0) {
|
||||
setTimeInMillis(t, status);
|
||||
}
|
||||
break;
|
||||
case UCAL_WALLTIME_LAST:
|
||||
if (adjAmount < 0) {
|
||||
setTimeInMillis(t, status);
|
||||
}
|
||||
break;
|
||||
case UCAL_WALLTIME_NEXT_VALID:
|
||||
UDate tmpT = adjAmount > 0 ? internalGetTime() : t;
|
||||
UDate immediatePrevTrans;
|
||||
UBool hasTransition = getImmediatePreviousZoneTransition(tmpT, &immediatePrevTrans, status);
|
||||
if (U_SUCCESS(status) && hasTransition) {
|
||||
setTimeInMillis(immediatePrevTrans, status);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2818,22 +2838,10 @@ void Calendar::computeTime(UErrorCode& status) {
|
|||
// Adjust time to the next valid wall clock time.
|
||||
// At this point, tmpTime is on or after the zone offset transition causing
|
||||
// the skipped time range.
|
||||
|
||||
BasicTimeZone *btz = getBasicTimeZone();
|
||||
if (btz) {
|
||||
TimeZoneTransition transition;
|
||||
UBool hasTransition = btz->getPreviousTransition(tmpTime, TRUE, transition);
|
||||
if (hasTransition) {
|
||||
t = transition.getTime();
|
||||
} else {
|
||||
// Could not find any transitions.
|
||||
// Note: This should never happen.
|
||||
status = U_INTERNAL_PROGRAM_ERROR;
|
||||
}
|
||||
} else {
|
||||
// If not BasicTimeZone, return unsupported error for now.
|
||||
// TODO: We may support non-BasicTimeZone in future.
|
||||
status = U_UNSUPPORTED_ERROR;
|
||||
UDate immediatePrevTransition;
|
||||
UBool hasTransition = getImmediatePreviousZoneTransition(tmpTime, &immediatePrevTransition, status);
|
||||
if (U_SUCCESS(status) && hasTransition) {
|
||||
t = immediatePrevTransition;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -2849,6 +2857,30 @@ void Calendar::computeTime(UErrorCode& status) {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the previous zone transtion near the given time.
|
||||
*/
|
||||
UBool Calendar::getImmediatePreviousZoneTransition(UDate base, UDate *transitionTime, UErrorCode& status) const {
|
||||
BasicTimeZone *btz = getBasicTimeZone();
|
||||
if (btz) {
|
||||
TimeZoneTransition trans;
|
||||
UBool hasTransition = btz->getPreviousTransition(base, TRUE, trans);
|
||||
if (hasTransition) {
|
||||
*transitionTime = trans.getTime();
|
||||
return TRUE;
|
||||
} else {
|
||||
// Could not find any transitions.
|
||||
// Note: This should never happen.
|
||||
status = U_INTERNAL_PROGRAM_ERROR;
|
||||
}
|
||||
} else {
|
||||
// If not BasicTimeZone, return unsupported error for now.
|
||||
// TODO: We may support non-BasicTimeZone in future.
|
||||
status = U_UNSUPPORTED_ERROR;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the milliseconds in the day from the fields. This is a
|
||||
* value from 0 to 23:59:59.999 inclusive, unless fields are out of
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
********************************************************************************
|
||||
* Copyright (C) 1997-2013, International Business Machines
|
||||
* Copyright (C) 1997-2014, International Business Machines
|
||||
* Corporation and others. All Rights Reserved.
|
||||
********************************************************************************
|
||||
*
|
||||
|
@ -2428,6 +2428,15 @@ private:
|
|||
* is not an instance of BasicTimeZone.
|
||||
*/
|
||||
BasicTimeZone* getBasicTimeZone() const;
|
||||
|
||||
/**
|
||||
* Find the previous zone transtion near the given time.
|
||||
* @param base The base time, inclusive
|
||||
* @param transitionTime Receives the result time
|
||||
* @param status The error status
|
||||
* @return TRUE if a transition is found.
|
||||
*/
|
||||
UBool getImmediatePreviousZoneTransition(UDate base, UDate *transitionTime, UErrorCode& status) const;
|
||||
};
|
||||
|
||||
// -------------------------------------
|
||||
|
|
|
@ -312,6 +312,13 @@ void CalendarTest::runIndexedTest( int32_t index, UBool exec, const char* &name,
|
|||
TestWeekData();
|
||||
}
|
||||
break;
|
||||
case 35:
|
||||
name = "TestAddAcrossZoneTransition";
|
||||
if(exec) {
|
||||
logln("TestAddAcrossZoneTransition---"); logln("");
|
||||
TestAddAcrossZoneTransition();
|
||||
}
|
||||
break;
|
||||
default: name = ""; break;
|
||||
}
|
||||
}
|
||||
|
@ -2422,12 +2429,13 @@ CalendarTest::TestAmbiguousWallTimeAPIs(void) {
|
|||
|
||||
class CalFields {
|
||||
public:
|
||||
CalFields(int32_t year, int32_t month, int32_t day, int32_t hour, int32_t min, int32_t sec);
|
||||
CalFields(int32_t year, int32_t month, int32_t day, int32_t hour, int32_t min, int32_t sec, int32_t ms = 0);
|
||||
CalFields(const Calendar& cal, UErrorCode& status);
|
||||
void setTo(Calendar& cal) const;
|
||||
char* toString(char* buf, int32_t len) const;
|
||||
UBool operator==(const CalFields& rhs) const;
|
||||
UBool operator!=(const CalFields& rhs) const;
|
||||
UBool isEquivalentTo(const Calendar& cal, UErrorCode& status) const;
|
||||
|
||||
private:
|
||||
int32_t year;
|
||||
|
@ -2436,10 +2444,11 @@ private:
|
|||
int32_t hour;
|
||||
int32_t min;
|
||||
int32_t sec;
|
||||
int32_t ms;
|
||||
};
|
||||
|
||||
CalFields::CalFields(int32_t year, int32_t month, int32_t day, int32_t hour, int32_t min, int32_t sec)
|
||||
: year(year), month(month), day(day), hour(hour), min(min), sec(sec) {
|
||||
CalFields::CalFields(int32_t year, int32_t month, int32_t day, int32_t hour, int32_t min, int32_t sec, int32_t ms)
|
||||
: year(year), month(month), day(day), hour(hour), min(min), sec(sec), ms(ms) {
|
||||
}
|
||||
|
||||
CalFields::CalFields(const Calendar& cal, UErrorCode& status) {
|
||||
|
@ -2449,18 +2458,20 @@ CalFields::CalFields(const Calendar& cal, UErrorCode& status) {
|
|||
hour = cal.get(UCAL_HOUR_OF_DAY, status);
|
||||
min = cal.get(UCAL_MINUTE, status);
|
||||
sec = cal.get(UCAL_SECOND, status);
|
||||
ms = cal.get(UCAL_MILLISECOND, status);
|
||||
}
|
||||
|
||||
void
|
||||
CalFields::setTo(Calendar& cal) const {
|
||||
cal.clear();
|
||||
cal.set(year, month - 1, day, hour, min, sec);
|
||||
cal.set(UCAL_MILLISECOND, ms);
|
||||
}
|
||||
|
||||
char*
|
||||
CalFields::toString(char* buf, int32_t len) const {
|
||||
char local[32];
|
||||
sprintf(local, "%04d-%02d-%02d %02d:%02d:%02d", year, month, day, hour, min, sec);
|
||||
sprintf(local, "%04d-%02d-%02d %02d:%02d:%02d.%03d", year, month, day, hour, min, sec, ms);
|
||||
uprv_strncpy(buf, local, len - 1);
|
||||
buf[len - 1] = 0;
|
||||
return buf;
|
||||
|
@ -2473,7 +2484,8 @@ CalFields::operator==(const CalFields& rhs) const {
|
|||
&& day == rhs.day
|
||||
&& hour == rhs.hour
|
||||
&& min == rhs.min
|
||||
&& sec == rhs.sec;
|
||||
&& sec == rhs.sec
|
||||
&& ms == rhs.ms;
|
||||
}
|
||||
|
||||
UBool
|
||||
|
@ -2481,6 +2493,17 @@ CalFields::operator!=(const CalFields& rhs) const {
|
|||
return !(*this == rhs);
|
||||
}
|
||||
|
||||
UBool
|
||||
CalFields::isEquivalentTo(const Calendar& cal, UErrorCode& status) const {
|
||||
return year == cal.get(UCAL_YEAR, status)
|
||||
&& month == cal.get(UCAL_MONTH, status) + 1
|
||||
&& day == cal.get(UCAL_DAY_OF_MONTH, status)
|
||||
&& hour == cal.get(UCAL_HOUR_OF_DAY, status)
|
||||
&& min == cal.get(UCAL_MINUTE, status)
|
||||
&& sec == cal.get(UCAL_SECOND, status)
|
||||
&& ms == cal.get(UCAL_MILLISECOND, status);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
const char* tzid;
|
||||
const CalFields in;
|
||||
|
@ -2969,6 +2992,183 @@ void CalendarTest::TestWeekData() {
|
|||
}
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
const char* zone;
|
||||
const CalFields base;
|
||||
int32_t deltaDays;
|
||||
UCalendarWallTimeOption skippedWTOpt;
|
||||
const CalFields expected;
|
||||
} TestAddAcrossZoneTransitionData;
|
||||
|
||||
static const TestAddAcrossZoneTransitionData AAZTDATA[] =
|
||||
{
|
||||
// Time zone Base wall time day(s) Skipped time options
|
||||
// Expected wall time
|
||||
|
||||
// Add 1 day, from the date before DST transition
|
||||
{"America/Los_Angeles", CalFields(2014,3,8,1,59,59,999), 1, UCAL_WALLTIME_FIRST,
|
||||
CalFields(2014,3,9,1,59,59,999)},
|
||||
|
||||
{"America/Los_Angeles", CalFields(2014,3,8,1,59,59,999), 1, UCAL_WALLTIME_LAST,
|
||||
CalFields(2014,3,9,1,59,59,999)},
|
||||
|
||||
{"America/Los_Angeles", CalFields(2014,3,8,1,59,59,999), 1, UCAL_WALLTIME_NEXT_VALID,
|
||||
CalFields(2014,3,9,1,59,59,999)},
|
||||
|
||||
|
||||
{"America/Los_Angeles", CalFields(2014,3,8,2,0,0,0), 1, UCAL_WALLTIME_FIRST,
|
||||
CalFields(2014,3,9,1,0,0,0)},
|
||||
|
||||
{"America/Los_Angeles", CalFields(2014,3,8,2,0,0,0), 1, UCAL_WALLTIME_LAST,
|
||||
CalFields(2014,3,9,3,0,0,0)},
|
||||
|
||||
{"America/Los_Angeles", CalFields(2014,3,8,2,0,0,0), 1, UCAL_WALLTIME_NEXT_VALID,
|
||||
CalFields(2014,3,9,3,0,0,0)},
|
||||
|
||||
|
||||
{"America/Los_Angeles", CalFields(2014,3,8,2,30,0,0), 1, UCAL_WALLTIME_FIRST,
|
||||
CalFields(2014,3,9,1,30,0,0)},
|
||||
|
||||
{"America/Los_Angeles", CalFields(2014,3,8,2,30,0,0), 1, UCAL_WALLTIME_LAST,
|
||||
CalFields(2014,3,9,3,30,0,0)},
|
||||
|
||||
{"America/Los_Angeles", CalFields(2014,3,8,2,30,0,0), 1, UCAL_WALLTIME_NEXT_VALID,
|
||||
CalFields(2014,3,9,3,0,0,0)},
|
||||
|
||||
|
||||
{"America/Los_Angeles", CalFields(2014,3,8,3,0,0,0), 1, UCAL_WALLTIME_FIRST,
|
||||
CalFields(2014,3,9,3,0,0,0)},
|
||||
|
||||
{"America/Los_Angeles", CalFields(2014,3,8,3,0,0,0), 1, UCAL_WALLTIME_LAST,
|
||||
CalFields(2014,3,9,3,0,0,0)},
|
||||
|
||||
{"America/Los_Angeles", CalFields(2014,3,8,3,0,0,0), 1, UCAL_WALLTIME_NEXT_VALID,
|
||||
CalFields(2014,3,9,3,0,0,0)},
|
||||
|
||||
// Subtract 1 day, from one day after DST transition
|
||||
{"America/Los_Angeles", CalFields(2014,3,10,1,59,59,999), -1, UCAL_WALLTIME_FIRST,
|
||||
CalFields(2014,3,9,1,59,59,999)},
|
||||
|
||||
{"America/Los_Angeles", CalFields(2014,3,10,1,59,59,999), -1, UCAL_WALLTIME_LAST,
|
||||
CalFields(2014,3,9,1,59,59,999)},
|
||||
|
||||
{"America/Los_Angeles", CalFields(2014,3,10,1,59,59,999), -1, UCAL_WALLTIME_NEXT_VALID,
|
||||
CalFields(2014,3,9,1,59,59,999)},
|
||||
|
||||
|
||||
{"America/Los_Angeles", CalFields(2014,3,10,2,0,0,0), -1, UCAL_WALLTIME_FIRST,
|
||||
CalFields(2014,3,9,1,0,0,0)},
|
||||
|
||||
{"America/Los_Angeles", CalFields(2014,3,10,2,0,0,0), -1, UCAL_WALLTIME_LAST,
|
||||
CalFields(2014,3,9,3,0,0,0)},
|
||||
|
||||
{"America/Los_Angeles", CalFields(2014,3,10,2,0,0,0), -1, UCAL_WALLTIME_NEXT_VALID,
|
||||
CalFields(2014,3,9,3,0,0,0)},
|
||||
|
||||
|
||||
{"America/Los_Angeles", CalFields(2014,3,10,2,30,0,0), -1, UCAL_WALLTIME_FIRST,
|
||||
CalFields(2014,3,9,1,30,0,0)},
|
||||
|
||||
{"America/Los_Angeles", CalFields(2014,3,10,2,30,0,0), -1, UCAL_WALLTIME_LAST,
|
||||
CalFields(2014,3,9,3,30,0,0)},
|
||||
|
||||
{"America/Los_Angeles", CalFields(2014,3,10,2,30,0,0), -1, UCAL_WALLTIME_NEXT_VALID,
|
||||
CalFields(2014,3,9,3,0,0,0)},
|
||||
|
||||
|
||||
{"America/Los_Angeles", CalFields(2014,3,10,3,0,0,0), -1, UCAL_WALLTIME_FIRST,
|
||||
CalFields(2014,3,9,3,0,0,0)},
|
||||
|
||||
{"America/Los_Angeles", CalFields(2014,3,10,3,0,0,0), -1, UCAL_WALLTIME_LAST,
|
||||
CalFields(2014,3,9,3,0,0,0)},
|
||||
|
||||
{"America/Los_Angeles", CalFields(2014,3,10,3,0,0,0), -1, UCAL_WALLTIME_NEXT_VALID,
|
||||
CalFields(2014,3,9,3,0,0,0)},
|
||||
|
||||
|
||||
// Test case for ticket#10544
|
||||
{"America/Santiago", CalFields(2013,4,27,0,0,0,0), 134, UCAL_WALLTIME_FIRST,
|
||||
CalFields(2013,9,7,23,0,0,0)},
|
||||
|
||||
{"America/Santiago", CalFields(2013,4,27,0,0,0,0), 134, UCAL_WALLTIME_LAST,
|
||||
CalFields(2013,9,8,1,0,0,0)},
|
||||
|
||||
{"America/Santiago", CalFields(2013,4,27,0,0,0,0), 134, UCAL_WALLTIME_NEXT_VALID,
|
||||
CalFields(2013,9,8,1,0,0,0)},
|
||||
|
||||
|
||||
{"America/Santiago", CalFields(2013,4,27,0,30,0,0), 134, UCAL_WALLTIME_FIRST,
|
||||
CalFields(2013,9,7,23,30,0,0)},
|
||||
|
||||
{"America/Santiago", CalFields(2013,4,27,0,30,0,0), 134, UCAL_WALLTIME_LAST,
|
||||
CalFields(2013,9,8,1,30,0,0)},
|
||||
|
||||
{"America/Santiago", CalFields(2013,4,27,0,30,0,0), 134, UCAL_WALLTIME_NEXT_VALID,
|
||||
CalFields(2013,9,8,1,0,0,0)},
|
||||
|
||||
|
||||
// Extreme transition - Pacific/Apia completely skips 2011-12-30
|
||||
{"Pacific/Apia", CalFields(2011,12,29,0,0,0,0), 1, UCAL_WALLTIME_FIRST,
|
||||
CalFields(2011,12,31,0,0,0,0)},
|
||||
|
||||
{"Pacific/Apia", CalFields(2011,12,29,0,0,0,0), 1, UCAL_WALLTIME_LAST,
|
||||
CalFields(2011,12,31,0,0,0,0)},
|
||||
|
||||
{"Pacific/Apia", CalFields(2011,12,29,0,0,0,0), 1, UCAL_WALLTIME_NEXT_VALID,
|
||||
CalFields(2011,12,31,0,0,0,0)},
|
||||
|
||||
|
||||
{"Pacific/Apia", CalFields(2011,12,31,12,0,0,0), -1, UCAL_WALLTIME_FIRST,
|
||||
CalFields(2011,12,29,12,0,0,0)},
|
||||
|
||||
{"Pacific/Apia", CalFields(2011,12,31,12,0,0,0), -1, UCAL_WALLTIME_LAST,
|
||||
CalFields(2011,12,29,12,0,0,0)},
|
||||
|
||||
{"Pacific/Apia", CalFields(2011,12,31,12,0,0,0), -1, UCAL_WALLTIME_NEXT_VALID,
|
||||
CalFields(2011,12,29,12,0,0,0)},
|
||||
|
||||
|
||||
// 30 minutes DST - Australia/Lord_Howe
|
||||
{"Australia/Lord_Howe", CalFields(2013,10,5,2,15,0,0), 1, UCAL_WALLTIME_FIRST,
|
||||
CalFields(2013,10,6,1,45,0,0)},
|
||||
|
||||
{"Australia/Lord_Howe", CalFields(2013,10,5,2,15,0,0), 1, UCAL_WALLTIME_LAST,
|
||||
CalFields(2013,10,6,2,45,0,0)},
|
||||
|
||||
{"Australia/Lord_Howe", CalFields(2013,10,5,2,15,0,0), 1, UCAL_WALLTIME_NEXT_VALID,
|
||||
CalFields(2013,10,6,2,30,0,0)},
|
||||
|
||||
{NULL, CalFields(0,0,0,0,0,0,0), 0, UCAL_WALLTIME_LAST, CalFields(0,0,0,0,0,0,0)}
|
||||
};
|
||||
|
||||
void CalendarTest::TestAddAcrossZoneTransition() {
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
GregorianCalendar cal(status);
|
||||
TEST_CHECK_STATUS;
|
||||
|
||||
for (int32_t i = 0; AAZTDATA[i].zone; i++) {
|
||||
status = U_ZERO_ERROR;
|
||||
TimeZone *tz = TimeZone::createTimeZone(AAZTDATA[i].zone);
|
||||
cal.adoptTimeZone(tz);
|
||||
cal.setSkippedWallTimeOption(AAZTDATA[i].skippedWTOpt);
|
||||
AAZTDATA[i].base.setTo(cal);
|
||||
cal.add(UCAL_DATE, AAZTDATA[i].deltaDays, status);
|
||||
TEST_CHECK_STATUS;
|
||||
|
||||
if (!AAZTDATA[i].expected.isEquivalentTo(cal, status)) {
|
||||
CalFields res(cal, status);
|
||||
TEST_CHECK_STATUS;
|
||||
char buf[32];
|
||||
const char *optDisp = AAZTDATA[i].skippedWTOpt == UCAL_WALLTIME_FIRST ? "FIRST" :
|
||||
AAZTDATA[i].skippedWTOpt == UCAL_WALLTIME_LAST ? "LAST" : "NEXT_VALID";
|
||||
errln(UnicodeString("Error: base:") + AAZTDATA[i].base.toString(buf, sizeof(buf)) + ", tz:" + AAZTDATA[i].zone
|
||||
+ ", delta:" + AAZTDATA[i].deltaDays + " day(s), opt:" + optDisp
|
||||
+ ", result:" + res.toString(buf, sizeof(buf))
|
||||
+ " - expected:" + AAZTDATA[i].expected.toString(buf, sizeof(buf)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* #if !UCONFIG_NO_FORMATTING */
|
||||
|
||||
//eof
|
||||
|
|
|
@ -249,6 +249,8 @@ public: // package
|
|||
void setAndTestWholeYear(Calendar* cal, int32_t startYear, UErrorCode& status);
|
||||
|
||||
void TestWeekData(void);
|
||||
|
||||
void TestAddAcrossZoneTransition(void);
|
||||
};
|
||||
|
||||
#endif /* #if !UCONFIG_NO_FORMATTING */
|
||||
|
|
Loading…
Add table
Reference in a new issue