mirror of
https://github.com/unicode-org/icu.git
synced 2025-04-07 22:44:49 +00:00
ICU-10544 Fixed some implementation problems in Calendar#add. When adding day or lager field results wall time falls into non-existing time slot created by DST transition, the new implementaion honors the current skipped wall time option.
X-SVN-Rev: 35232
This commit is contained in:
parent
f7f73fe88d
commit
25d898f0b4
2 changed files with 277 additions and 58 deletions
|
@ -3064,10 +3064,10 @@ public abstract class Calendar implements Serializable, Cloneable, Comparable<Ca
|
|||
// 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
|
||||
|
@ -3082,7 +3082,7 @@ public abstract class Calendar implements Serializable, Cloneable, Comparable<Ca
|
|||
// <April 30>, rather than <April 31> => <May 1>.
|
||||
|
||||
long delta = amount; // delta in ms
|
||||
boolean keepHourInvariant = true;
|
||||
boolean keepWallTimeInvariant = true;
|
||||
|
||||
switch (field) {
|
||||
case ERA:
|
||||
|
@ -3144,22 +3144,22 @@ public abstract class Calendar implements Serializable, Cloneable, Comparable<Ca
|
|||
case HOUR_OF_DAY:
|
||||
case HOUR:
|
||||
delta *= ONE_HOUR;
|
||||
keepHourInvariant = false;
|
||||
keepWallTimeInvariant = false;
|
||||
break;
|
||||
|
||||
case MINUTE:
|
||||
delta *= ONE_MINUTE;
|
||||
keepHourInvariant = false;
|
||||
keepWallTimeInvariant = false;
|
||||
break;
|
||||
|
||||
case SECOND:
|
||||
delta *= ONE_SECOND;
|
||||
keepHourInvariant = false;
|
||||
keepWallTimeInvariant = false;
|
||||
break;
|
||||
|
||||
case MILLISECOND:
|
||||
case MILLISECONDS_IN_DAY:
|
||||
keepHourInvariant = false;
|
||||
keepWallTimeInvariant = false;
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -3167,40 +3167,61 @@ public abstract class Calendar implements Serializable, Cloneable, Comparable<Ca
|
|||
") 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.
|
||||
int prevOffset = 0;
|
||||
int hour = 0;
|
||||
if (keepHourInvariant) {
|
||||
int prevWallTime = 0;
|
||||
if (keepWallTimeInvariant) {
|
||||
prevOffset = get(DST_OFFSET) + get(ZONE_OFFSET);
|
||||
hour = internalGet(HOUR_OF_DAY);
|
||||
prevWallTime = get(MILLISECONDS_IN_DAY);
|
||||
}
|
||||
|
||||
setTimeInMillis(getTimeInMillis() + delta);
|
||||
|
||||
if (keepHourInvariant) {
|
||||
int newOffset = get(DST_OFFSET) + get(ZONE_OFFSET);
|
||||
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.
|
||||
long adjAmount = (prevOffset - newOffset) % ONE_DAY;
|
||||
if (adjAmount != 0) {
|
||||
long t = time;
|
||||
setTimeInMillis(time + adjAmount);
|
||||
if (get(HOUR_OF_DAY) != hour) {
|
||||
setTimeInMillis(t);
|
||||
if (keepWallTimeInvariant) {
|
||||
int newWallTime = get(MILLISECONDS_IN_DAY);
|
||||
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.
|
||||
long t = internalGetTimeInMillis();
|
||||
int newOffset = get(DST_OFFSET) + get(ZONE_OFFSET);
|
||||
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.
|
||||
long adjAmount = (prevOffset - newOffset) % ONE_DAY;
|
||||
if (adjAmount != 0) {
|
||||
setTimeInMillis(t + adjAmount);
|
||||
newWallTime = get(MILLISECONDS_IN_DAY);
|
||||
}
|
||||
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 (skippedWallTime) {
|
||||
case WALLTIME_FIRST:
|
||||
if (adjAmount > 0) {
|
||||
setTimeInMillis(t);
|
||||
}
|
||||
break;
|
||||
case WALLTIME_LAST:
|
||||
if (adjAmount < 0) {
|
||||
setTimeInMillis(t);
|
||||
}
|
||||
break;
|
||||
case WALLTIME_NEXT_VALID:
|
||||
long tmpT = adjAmount > 0 ? internalGetTimeInMillis() : t;
|
||||
Long immediatePrevTrans = getImmediatePreviousZoneTransition(tmpT);
|
||||
if (immediatePrevTrans != null) {
|
||||
setTimeInMillis(immediatePrevTrans);
|
||||
} else {
|
||||
throw new RuntimeException("Could not locate a time zone transition before " + tmpT);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5047,7 +5068,7 @@ public abstract class Calendar implements Serializable, Cloneable, Comparable<Ca
|
|||
* millisecond time value <code>time</code>.
|
||||
* @stable ICU 2.0
|
||||
*/
|
||||
protected void computeTime() {
|
||||
protected void computeTime() {
|
||||
if (!isLenient()) {
|
||||
validateFields();
|
||||
}
|
||||
|
@ -5126,26 +5147,11 @@ public abstract class Calendar implements Serializable, Cloneable, Comparable<Ca
|
|||
// 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.
|
||||
if (zone instanceof BasicTimeZone) {
|
||||
TimeZoneTransition transition = ((BasicTimeZone)zone).getPreviousTransition(tmpTime, true);
|
||||
if (transition == null) {
|
||||
// Could not find any transitions
|
||||
throw new RuntimeException("Could not locate previous zone transition");
|
||||
}
|
||||
time = transition.getTime();
|
||||
} else {
|
||||
// Usually, it is enough to check past one hour because such transition is most
|
||||
// likely +1 hour shift. However, there is an example jumped +24 hour in the tz database.
|
||||
Long transitionT = getPreviousZoneTransitionTime(zone, tmpTime, 2*60*60*1000); // check last 2 hours
|
||||
if (transitionT == null) {
|
||||
transitionT = getPreviousZoneTransitionTime(zone, tmpTime, 30*60*60*1000); // try last 30 hours
|
||||
if (transitionT == null) {
|
||||
// Could not find any transitions in last 30 hours...
|
||||
throw new RuntimeException("Could not locate previous zone transition within 30 hours from " + tmpTime);
|
||||
}
|
||||
}
|
||||
time = transitionT.longValue();
|
||||
Long immediatePrevTransition = getImmediatePreviousZoneTransition(tmpTime);
|
||||
if (immediatePrevTransition == null) {
|
||||
throw new RuntimeException("Could not locate a time zone transition before " + tmpTime);
|
||||
}
|
||||
time = immediatePrevTransition;
|
||||
} else {
|
||||
time = tmpTime;
|
||||
}
|
||||
|
@ -5155,16 +5161,40 @@ public abstract class Calendar implements Serializable, Cloneable, Comparable<Ca
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the previous zone transtion near the given time.
|
||||
*
|
||||
* @param base The base time, inclusive.
|
||||
* @return The time of the previous transition, or null if not found.
|
||||
*/
|
||||
private Long getImmediatePreviousZoneTransition(long base) {
|
||||
Long transitionTime = null;
|
||||
|
||||
if (zone instanceof BasicTimeZone) {
|
||||
TimeZoneTransition transition = ((BasicTimeZone) zone).getPreviousTransition(base, true);
|
||||
if (transition != null) {
|
||||
transitionTime = transition.getTime();
|
||||
}
|
||||
} else {
|
||||
// Usually, it is enough to check past one hour because such transition is most
|
||||
// likely +1 hour shift. However, there is an example jumped +24 hour in the tz database.
|
||||
transitionTime = getPreviousZoneTransitionTime(zone, base, 2 * 60 * 60 * 1000); // check last 2 hours
|
||||
if (transitionTime == null) {
|
||||
transitionTime = getPreviousZoneTransitionTime(zone, base, 30 * 60 * 60 * 1000); // try last 30 hours
|
||||
}
|
||||
}
|
||||
return transitionTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the previous zone transition within the specified duration.
|
||||
* Note: This method should not be used when TimeZone is a BasicTimeZone.
|
||||
* {@link BasicTimeZone#getPreviousTransition(long, boolean)} is much more efficient.
|
||||
* Note: This method is only used when TimeZone is NOT a BasicTimeZone.
|
||||
* @param tz The time zone.
|
||||
* @param base The base time, inclusive.
|
||||
* @param duration The range of time evaluated.
|
||||
* @return The time of the previous zone transition, or null if not available.
|
||||
*/
|
||||
private Long getPreviousZoneTransitionTime(TimeZone tz, long base, long duration) {
|
||||
private static Long getPreviousZoneTransitionTime(TimeZone tz, long base, long duration) {
|
||||
assert duration > 0;
|
||||
|
||||
long upper = base;
|
||||
|
@ -5196,7 +5226,7 @@ public abstract class Calendar implements Serializable, Cloneable, Comparable<Ca
|
|||
* @param lower The lower bound, exclusive.
|
||||
* @return The time of the previous zone transition, or null if not available.
|
||||
*/
|
||||
private Long findPreviousZoneTransitionTime(TimeZone tz, int upperOffset, long upper, long lower) {
|
||||
private static Long findPreviousZoneTransitionTime(TimeZone tz, int upperOffset, long upper, long lower) {
|
||||
boolean onUnitTime = false;
|
||||
long mid = 0;
|
||||
|
||||
|
|
|
@ -1097,23 +1097,30 @@ public class IBMCalendarTest extends CalendarTest {
|
|||
private int hour;
|
||||
private int min;
|
||||
private int sec;
|
||||
private int ms;
|
||||
|
||||
CalFields(int year, int month, int day, int hour, int min, int sec) {
|
||||
this(year, month, day, hour, min, sec, 0);
|
||||
}
|
||||
|
||||
CalFields(int year, int month, int day, int hour, int min, int sec, int ms) {
|
||||
this.year = year;
|
||||
this.month = month;
|
||||
this.day = day;
|
||||
this.hour = hour;
|
||||
this.min = min;
|
||||
this.sec = sec;
|
||||
this.ms = ms;
|
||||
}
|
||||
|
||||
void setTo(Calendar cal) {
|
||||
cal.clear();
|
||||
cal.set(year, month - 1, day, hour, min, sec);
|
||||
cal.set(Calendar.MILLISECOND, ms);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return String.format("%04d-%02d-%02d %02d:%02d:%02d", year, month, day, hour, min, sec);
|
||||
return String.format("%04d-%02d-%02d %02d:%02d:%02d.%03d", year, month, day, hour, min, sec, ms);
|
||||
}
|
||||
|
||||
public boolean equals(Object other) {
|
||||
|
@ -1124,11 +1131,22 @@ public class IBMCalendarTest extends CalendarTest {
|
|||
&& day == otr.day
|
||||
&& hour == otr.hour
|
||||
&& min == otr.min
|
||||
&& sec == otr.sec);
|
||||
&& sec == otr.sec
|
||||
&& ms == otr.ms);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean isEquivalentTo(Calendar cal) {
|
||||
return year == cal.get(Calendar.YEAR)
|
||||
&& month == cal.get(Calendar.MONTH) + 1
|
||||
&& day == cal.get(Calendar.DAY_OF_MONTH)
|
||||
&& hour == cal.get(Calendar.HOUR_OF_DAY)
|
||||
&& min == cal.get(Calendar.MINUTE)
|
||||
&& sec == cal.get(Calendar.SECOND)
|
||||
&& ms == cal.get(Calendar.MILLISECOND);
|
||||
}
|
||||
|
||||
static CalFields createFrom(Calendar cal) {
|
||||
int year = cal.get(Calendar.YEAR);
|
||||
int month = cal.get(Calendar.MONTH) + 1;
|
||||
|
@ -1681,4 +1699,175 @@ public class IBMCalendarTest extends CalendarTest {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void TestAddAcrossZoneTransition() {
|
||||
class TestData {
|
||||
String zone;
|
||||
CalFields base;
|
||||
int deltaDays;
|
||||
int skippedWTOpt;
|
||||
CalFields expected;
|
||||
|
||||
TestData(String zone, CalFields base, int deltaDays, int skippedWTOpt, CalFields expected) {
|
||||
this.zone = zone;
|
||||
this.base = base;
|
||||
this.deltaDays = deltaDays;
|
||||
this.skippedWTOpt = skippedWTOpt;
|
||||
this.expected = expected;
|
||||
}
|
||||
}
|
||||
|
||||
TestData[] data = new TestData[] {
|
||||
// Add 1 day, from the date before DST transition
|
||||
new TestData("America/Los_Angeles", new CalFields(2014, 3, 8, 1, 59, 59, 999), 1, Calendar.WALLTIME_FIRST,
|
||||
new CalFields(2014, 3, 9, 1, 59, 59, 999)),
|
||||
|
||||
new TestData("America/Los_Angeles", new CalFields(2014, 3, 8, 1, 59, 59, 999), 1, Calendar.WALLTIME_LAST,
|
||||
new CalFields(2014, 3, 9, 1, 59, 59, 999)),
|
||||
|
||||
new TestData("America/Los_Angeles", new CalFields(2014, 3, 8, 1, 59, 59, 999), 1, Calendar.WALLTIME_NEXT_VALID,
|
||||
new CalFields(2014, 3, 9, 1, 59, 59, 999)),
|
||||
|
||||
|
||||
new TestData("America/Los_Angeles", new CalFields(2014, 3, 8, 2, 0, 0, 0), 1, Calendar.WALLTIME_FIRST,
|
||||
new CalFields(2014, 3, 9, 1, 0, 0, 0)),
|
||||
|
||||
new TestData("America/Los_Angeles", new CalFields(2014, 3, 8, 2, 0, 0, 0), 1, Calendar.WALLTIME_LAST,
|
||||
new CalFields(2014, 3, 9, 3, 0, 0, 0)),
|
||||
|
||||
new TestData("America/Los_Angeles", new CalFields(2014, 3, 8, 2, 0, 0, 0), 1, Calendar.WALLTIME_NEXT_VALID,
|
||||
new CalFields(2014, 3, 9, 3, 0, 0, 0)),
|
||||
|
||||
|
||||
new TestData("America/Los_Angeles", new CalFields(2014, 3, 8, 2, 30, 0, 0), 1, Calendar.WALLTIME_FIRST,
|
||||
new CalFields(2014, 3, 9, 1, 30, 0, 0)),
|
||||
|
||||
new TestData("America/Los_Angeles", new CalFields(2014, 3, 8, 2, 30, 0, 0), 1, Calendar.WALLTIME_LAST,
|
||||
new CalFields(2014, 3, 9, 3, 30, 0, 0)),
|
||||
|
||||
new TestData("America/Los_Angeles", new CalFields(2014, 3, 8, 2, 30, 0, 0), 1, Calendar.WALLTIME_NEXT_VALID,
|
||||
new CalFields(2014, 3, 9, 3, 0, 0, 0)),
|
||||
|
||||
|
||||
new TestData("America/Los_Angeles", new CalFields(2014, 3, 8, 3, 0, 0, 0), 1, Calendar.WALLTIME_FIRST,
|
||||
new CalFields(2014, 3, 9, 3, 0, 0, 0)),
|
||||
|
||||
new TestData("America/Los_Angeles", new CalFields(2014, 3, 8, 3, 0, 0, 0), 1, Calendar.WALLTIME_LAST,
|
||||
new CalFields(2014, 3, 9, 3, 0, 0, 0)),
|
||||
|
||||
new TestData("America/Los_Angeles", new CalFields(2014, 3, 8, 3, 0, 0, 0), 1, Calendar.WALLTIME_NEXT_VALID,
|
||||
new CalFields(2014, 3, 9, 3, 0, 0, 0)),
|
||||
|
||||
|
||||
// Subtract 1 day, from one day after DST transition
|
||||
new TestData("America/Los_Angeles", new CalFields(2014, 3, 10, 1, 59, 59, 999), -1, Calendar.WALLTIME_FIRST,
|
||||
new CalFields(2014, 3, 9, 1, 59, 59, 999)),
|
||||
|
||||
new TestData("America/Los_Angeles", new CalFields(2014, 3, 10, 1, 59, 59, 999), -1, Calendar.WALLTIME_LAST,
|
||||
new CalFields(2014, 3, 9, 1, 59, 59, 999)),
|
||||
|
||||
new TestData("America/Los_Angeles", new CalFields(2014, 3, 10, 1, 59, 59, 999), -1, Calendar.WALLTIME_NEXT_VALID,
|
||||
new CalFields(2014, 3, 9, 1, 59, 59, 999)),
|
||||
|
||||
|
||||
new TestData("America/Los_Angeles", new CalFields(2014, 3, 10, 2, 0, 0, 0), -1, Calendar.WALLTIME_FIRST,
|
||||
new CalFields(2014, 3, 9, 1, 0, 0, 0)),
|
||||
|
||||
new TestData("America/Los_Angeles", new CalFields(2014, 3, 10, 2, 0, 0, 0), -1, Calendar.WALLTIME_LAST,
|
||||
new CalFields(2014, 3, 9, 3, 0, 0, 0)),
|
||||
|
||||
new TestData("America/Los_Angeles", new CalFields(2014, 3, 10, 2, 0, 0, 0), -1, Calendar.WALLTIME_NEXT_VALID,
|
||||
new CalFields(2014, 3, 9, 3, 0, 0, 0)),
|
||||
|
||||
|
||||
new TestData("America/Los_Angeles", new CalFields(2014, 3, 10, 2, 30, 0, 0), -1, Calendar.WALLTIME_FIRST,
|
||||
new CalFields(2014, 3, 9, 1, 30, 0, 0)),
|
||||
|
||||
new TestData("America/Los_Angeles", new CalFields(2014, 3, 10, 2, 30, 0, 0), -1, Calendar.WALLTIME_LAST,
|
||||
new CalFields(2014, 3, 9, 3, 30, 0, 0)),
|
||||
|
||||
new TestData("America/Los_Angeles", new CalFields(2014, 3, 10, 2, 30, 0, 0), -1, Calendar.WALLTIME_NEXT_VALID,
|
||||
new CalFields(2014, 3, 9, 3, 0, 0, 0)),
|
||||
|
||||
|
||||
new TestData("America/Los_Angeles", new CalFields(2014, 3, 10, 3, 0, 0, 0), -1, Calendar.WALLTIME_FIRST,
|
||||
new CalFields(2014, 3, 9, 3, 0, 0, 0)),
|
||||
|
||||
new TestData("America/Los_Angeles", new CalFields(2014, 3, 10, 3, 0, 0, 0), -1, Calendar.WALLTIME_LAST,
|
||||
new CalFields(2014, 3, 9, 3, 0, 0, 0)),
|
||||
|
||||
new TestData("America/Los_Angeles", new CalFields(2014, 3, 10, 3, 0, 0, 0), -1, Calendar.WALLTIME_NEXT_VALID,
|
||||
new CalFields(2014, 3, 9, 3, 0, 0, 0)),
|
||||
|
||||
|
||||
// Test case for ticket#10544
|
||||
new TestData("America/Santiago", new CalFields(2013, 4, 27, 0, 0, 0, 0), 134, Calendar.WALLTIME_FIRST,
|
||||
new CalFields(2013, 9, 7, 23, 0, 0, 0)),
|
||||
|
||||
new TestData("America/Santiago", new CalFields(2013, 4, 27, 0, 0, 0, 0), 134, Calendar.WALLTIME_LAST,
|
||||
new CalFields(2013, 9, 8, 1, 0, 0, 0)),
|
||||
|
||||
new TestData("America/Santiago", new CalFields(2013, 4, 27, 0, 0, 0, 0), 134, Calendar.WALLTIME_NEXT_VALID,
|
||||
new CalFields(2013, 9, 8, 1, 0, 0, 0)),
|
||||
|
||||
|
||||
new TestData("America/Santiago", new CalFields(2013, 4, 27, 0, 30, 0, 0), 134, Calendar.WALLTIME_FIRST,
|
||||
new CalFields(2013, 9, 7, 23, 30, 0, 0)),
|
||||
|
||||
new TestData("America/Santiago", new CalFields(2013, 4, 27, 0, 30, 0, 0), 134, Calendar.WALLTIME_LAST,
|
||||
new CalFields(2013, 9, 8, 1, 30, 0, 0)),
|
||||
|
||||
new TestData("America/Santiago", new CalFields(2013, 4, 27, 0, 30, 0, 0), 134, Calendar.WALLTIME_NEXT_VALID,
|
||||
new CalFields(2013, 9, 8, 1, 0, 0, 0)),
|
||||
|
||||
|
||||
// Extreme transition - Pacific/Apia completely skips 2011-12-30
|
||||
new TestData("Pacific/Apia", new CalFields(2011, 12, 29, 0, 0, 0, 0), 1, Calendar.WALLTIME_FIRST,
|
||||
new CalFields(2011, 12, 31, 0, 0, 0, 0)),
|
||||
|
||||
new TestData("Pacific/Apia", new CalFields(2011, 12, 29, 0, 0, 0, 0), 1, Calendar.WALLTIME_LAST,
|
||||
new CalFields(2011, 12, 31, 0, 0, 0, 0)),
|
||||
|
||||
new TestData("Pacific/Apia", new CalFields(2011, 12, 29, 0, 0, 0, 0), 1, Calendar.WALLTIME_NEXT_VALID,
|
||||
new CalFields(2011, 12, 31, 0, 0, 0, 0)),
|
||||
|
||||
|
||||
new TestData("Pacific/Apia", new CalFields(2011, 12, 31, 12, 0, 0, 0), -1, Calendar.WALLTIME_FIRST,
|
||||
new CalFields(2011, 12, 29, 12, 0, 0, 0)),
|
||||
|
||||
new TestData("Pacific/Apia", new CalFields(2011, 12, 31, 12, 0, 0, 0), -1, Calendar.WALLTIME_LAST,
|
||||
new CalFields(2011, 12, 29, 12, 0, 0, 0)),
|
||||
|
||||
new TestData("Pacific/Apia", new CalFields(2011, 12, 31, 12, 0, 0, 0), -1, Calendar.WALLTIME_NEXT_VALID,
|
||||
new CalFields(2011, 12, 29, 12, 0, 0, 0)),
|
||||
|
||||
|
||||
// 30 minutes DST - Australia/Lord_Howe
|
||||
new TestData("Australia/Lord_Howe", new CalFields(2013, 10, 5, 2, 15, 0, 0), 1, Calendar.WALLTIME_FIRST,
|
||||
new CalFields(2013, 10, 6, 1, 45, 0, 0)),
|
||||
|
||||
new TestData("Australia/Lord_Howe", new CalFields(2013, 10, 5, 2, 15, 0, 0), 1, Calendar.WALLTIME_LAST,
|
||||
new CalFields(2013, 10, 6, 2, 45, 0, 0)),
|
||||
|
||||
new TestData("Australia/Lord_Howe", new CalFields(2013, 10, 5, 2, 15, 0, 0), 1, Calendar.WALLTIME_NEXT_VALID,
|
||||
new CalFields(2013, 10, 6, 2, 30, 0, 0)),
|
||||
};
|
||||
|
||||
Calendar cal = Calendar.getInstance();
|
||||
for (TestData d : data) {
|
||||
cal.setTimeZone(TimeZone.getTimeZone(d.zone));
|
||||
cal.setSkippedWallTimeOption(d.skippedWTOpt);
|
||||
d.base.setTo(cal);
|
||||
cal.add(Calendar.DATE, d.deltaDays);
|
||||
|
||||
if (!d.expected.isEquivalentTo(cal)) {
|
||||
CalFields res = CalFields.createFrom(cal);
|
||||
String optDisp = d.skippedWTOpt == Calendar.WALLTIME_FIRST ? "FIRST" :
|
||||
d.skippedWTOpt == Calendar.WALLTIME_LAST ? "LAST" : "NEXT_VALID";
|
||||
errln("Error: base:" + d.base.toString() + ", tz:" + d.zone
|
||||
+ ", delta:" + d.deltaDays + " day(s), opt:" + optDisp
|
||||
+ ", result:" + res.toString() + " - expected:" + d.expected.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue