ICU-7518 Workaround for 24:00 on a transition day problem. Use 23:59:59.999 as the transition time. iCal VTIMEZONE is not capable to handle such rule. Also a minor bug fix in BasicTimeZone.hasEquivalentTransitions which was found while updating the test case.
X-SVN-Rev: 28879
This commit is contained in:
parent
a1f9c9d8f7
commit
faca047508
@ -136,17 +136,27 @@ public abstract class BasicTimeZone extends TimeZone {
|
||||
|
||||
if (ignoreDstAmount) {
|
||||
// Skip a transition which only differ the amount of DST savings
|
||||
if (tr1 != null
|
||||
&& (tr1.getFrom().getRawOffset() + tr1.getFrom().getDSTSavings()
|
||||
== tr1.getTo().getRawOffset() + tr1.getTo().getDSTSavings())
|
||||
&& (tr1.getFrom().getDSTSavings() != 0 && tr1.getTo().getDSTSavings() != 0)) {
|
||||
tr1 = getNextTransition(tr1.getTime(), false);
|
||||
while (true) {
|
||||
if (tr1 != null
|
||||
&& tr1.getTime() <= end
|
||||
&& (tr1.getFrom().getRawOffset() + tr1.getFrom().getDSTSavings()
|
||||
== tr1.getTo().getRawOffset() + tr1.getTo().getDSTSavings())
|
||||
&& (tr1.getFrom().getDSTSavings() != 0 && tr1.getTo().getDSTSavings() != 0)) {
|
||||
tr1 = getNextTransition(tr1.getTime(), false);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (tr2 != null
|
||||
&& (tr2.getFrom().getRawOffset() + tr2.getFrom().getDSTSavings()
|
||||
== tr2.getTo().getRawOffset() + tr2.getTo().getDSTSavings())
|
||||
&& (tr2.getFrom().getDSTSavings() != 0 && tr2.getTo().getDSTSavings() != 0)) {
|
||||
tr2 = getNextTransition(tr2.getTime(), false);
|
||||
while (true) {
|
||||
if (tr2 != null
|
||||
&& tr2.getTime() <= end
|
||||
&& (tr2.getFrom().getRawOffset() + tr2.getFrom().getDSTSavings()
|
||||
== tr2.getTo().getRawOffset() + tr2.getTo().getDSTSavings())
|
||||
&& (tr2.getFrom().getDSTSavings() != 0 && tr2.getTo().getDSTSavings() != 0)) {
|
||||
tr2 = ((BasicTimeZone)tz).getNextTransition(tr2.getTime(), false);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1624,6 +1624,18 @@ public class VTimeZone extends BasicTimeZone {
|
||||
private static void writeFinalRule(Writer writer, boolean isDst, AnnualTimeZoneRule rule,
|
||||
int fromRawOffset, int fromDSTSavings, long startTime) throws IOException{
|
||||
DateTimeRule dtrule = toWallTimeRule(rule.getRule(), fromRawOffset, fromDSTSavings);
|
||||
|
||||
// If the rule's mills in a day is out of range, adjust start time.
|
||||
// Olson tzdata supports 24:00 of a day, but VTIMEZONE does not.
|
||||
// See ticket#7008/#7518
|
||||
|
||||
int timeInDay = dtrule.getRuleMillisInDay();
|
||||
if (timeInDay < 0) {
|
||||
startTime = startTime + (0 - timeInDay);
|
||||
} else if (timeInDay >= Grego.MILLIS_PER_DAY) {
|
||||
startTime = startTime - (timeInDay - (Grego.MILLIS_PER_DAY - 1));
|
||||
}
|
||||
|
||||
int toOffset = rule.getRawOffset() + rule.getDSTSavings();
|
||||
switch (dtrule.getDateRuleType()) {
|
||||
case DateTimeRule.DOM:
|
||||
|
@ -436,9 +436,6 @@ public class TimeZoneRuleTest extends TestFmwk {
|
||||
|
||||
String[] tzids = getTestZIDs();
|
||||
for (int i = 0; i < tzids.length; i++) {
|
||||
if (skipIfBeforeICU(4,5,2) && tzids[i].equals("Asia/Amman")) { // ticket#7008
|
||||
continue;
|
||||
}
|
||||
BasicTimeZone olsontz = (BasicTimeZone)TimeZone.getTimeZone(tzids[i], TimeZone.TIMEZONE_ICU);
|
||||
VTimeZone vtz_org = VTimeZone.create(tzids[i]);
|
||||
vtz_org.setTZURL("http://source.icu-project.org/timezone");
|
||||
@ -488,7 +485,12 @@ public class TimeZoneRuleTest extends TestFmwk {
|
||||
TimeZoneTransition tzt = olsontz.getNextTransition(startTime, false);
|
||||
if (tzt != null) {
|
||||
if (!vtz_new.hasEquivalentTransitions(olsontz, tzt.getTime(), endTime, true)) {
|
||||
errln("FAIL: VTimeZone for " + tzids[i] + " is not equivalent to its OlsonTimeZone corresponding.");
|
||||
int maxDelta = 1000;
|
||||
if (!hasEquivalentTransitions(vtz_new, olsontz, tzt.getTime() + maxDelta, endTime, true, maxDelta)) {
|
||||
errln("FAIL: VTimeZone for " + tzids[i] + " is not equivalent to its OlsonTimeZone corresponding.");
|
||||
} else {
|
||||
logln("VTimeZone for " + tzids[i] + " differs from its OlsonTimeZone corresponding with maximum transition time delta - " + maxDelta);
|
||||
}
|
||||
}
|
||||
if (!vtz_new.hasEquivalentTransitions(olsontz, tzt.getTime(), endTime, false)) {
|
||||
logln("VTimeZone for " + tzids[i] + " is not equivalent to its OlsonTimeZone corresponding in strict comparison mode.");
|
||||
@ -513,9 +515,6 @@ public class TimeZoneRuleTest extends TestFmwk {
|
||||
for (int n = 0; n < startTimes.length; n++) {
|
||||
long startTime = startTimes[n];
|
||||
for (int i = 0; i < tzids.length; i++) {
|
||||
if (skipIfBeforeICU(4,5,2) && tzids[i].equals("Asia/Amman")) { // ticket#7008
|
||||
continue;
|
||||
}
|
||||
BasicTimeZone olsontz = (BasicTimeZone)TimeZone.getTimeZone(tzids[i], TimeZone.TIMEZONE_ICU);
|
||||
VTimeZone vtz_org = VTimeZone.create(tzids[i]);
|
||||
VTimeZone vtz_new = null;
|
||||
@ -546,10 +545,15 @@ public class TimeZoneRuleTest extends TestFmwk {
|
||||
TimeZoneTransition tzt = olsontz.getNextTransition(startTime, false);
|
||||
if (tzt != null) {
|
||||
if (!vtz_new.hasEquivalentTransitions(olsontz, tzt.getTime(), endTime, true)) {
|
||||
errln("FAIL: VTimeZone for " + tzids[i] + "(>=" + startTime + ") is not equivalent to its OlsonTimeZone corresponding.");
|
||||
int maxDelta = 1000;
|
||||
if (!hasEquivalentTransitions(vtz_new, olsontz, tzt.getTime() + maxDelta, endTime, true, maxDelta)) {
|
||||
errln("FAIL: VTimeZone for " + tzids[i] + "(>=" + startTime + ") is not equivalent to its OlsonTimeZone corresponding.");
|
||||
} else {
|
||||
logln("VTimeZone for " + tzids[i] + "(>=" + startTime + ") differs from its OlsonTimeZone corresponding with maximum transition time delta - " + maxDelta);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1677,4 +1681,106 @@ public class TimeZoneRuleTest extends TestFmwk {
|
||||
utcCal.set(year, month, dayOfMonth);
|
||||
return utcCal.getTimeInMillis();
|
||||
}
|
||||
|
||||
/*
|
||||
* Slightly modified version of BasicTimeZone#hasEquivalentTransitions.
|
||||
* This version returns true if transition time delta is within the given
|
||||
* delta range.
|
||||
*/
|
||||
private static boolean hasEquivalentTransitions(BasicTimeZone tz1, BasicTimeZone tz2,
|
||||
long start, long end,
|
||||
boolean ignoreDstAmount, int maxTransitionTimeDelta) {
|
||||
if (tz1.hasSameRules(tz2)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check the offsets at the start time
|
||||
int[] offsets1 = new int[2];
|
||||
int[] offsets2 = new int[2];
|
||||
|
||||
tz1.getOffset(start, false, offsets1);
|
||||
tz2.getOffset(start, false, offsets2);
|
||||
|
||||
if (ignoreDstAmount) {
|
||||
if ((offsets1[0] + offsets1[1] != offsets2[0] + offsets2[1])
|
||||
|| (offsets1[1] != 0 && offsets2[1] == 0)
|
||||
|| (offsets1[1] == 0 && offsets2[1] != 0)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (offsets1[0] != offsets2[0] || offsets1[1] != offsets2[1]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Check transitions in the range
|
||||
long time = start;
|
||||
while (true) {
|
||||
TimeZoneTransition tr1 = tz1.getNextTransition(time, false);
|
||||
TimeZoneTransition tr2 = tz2.getNextTransition(time, false);
|
||||
|
||||
if (ignoreDstAmount) {
|
||||
// Skip a transition which only differ the amount of DST savings
|
||||
while (true) {
|
||||
if (tr1 != null
|
||||
&& tr1.getTime() <= end
|
||||
&& (tr1.getFrom().getRawOffset() + tr1.getFrom().getDSTSavings()
|
||||
== tr1.getTo().getRawOffset() + tr1.getTo().getDSTSavings())
|
||||
&& (tr1.getFrom().getDSTSavings() != 0 && tr1.getTo().getDSTSavings() != 0)) {
|
||||
tr1 = tz1.getNextTransition(tr1.getTime(), false);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (true) {
|
||||
if (tr2 != null
|
||||
&& tr2.getTime() <= end
|
||||
&& (tr2.getFrom().getRawOffset() + tr2.getFrom().getDSTSavings()
|
||||
== tr2.getTo().getRawOffset() + tr2.getTo().getDSTSavings())
|
||||
&& (tr2.getFrom().getDSTSavings() != 0 && tr2.getTo().getDSTSavings() != 0)) {
|
||||
tr2 = tz2.getNextTransition(tr2.getTime(), false);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} }
|
||||
|
||||
boolean inRange1 = false;
|
||||
boolean inRange2 = false;
|
||||
if (tr1 != null) {
|
||||
if (tr1.getTime() <= end) {
|
||||
inRange1 = true;
|
||||
}
|
||||
}
|
||||
if (tr2 != null) {
|
||||
if (tr2.getTime() <= end) {
|
||||
inRange2 = true;
|
||||
}
|
||||
}
|
||||
if (!inRange1 && !inRange2) {
|
||||
// No more transition in the range
|
||||
break;
|
||||
}
|
||||
if (!inRange1 || !inRange2) {
|
||||
return false;
|
||||
}
|
||||
if (Math.abs(tr1.getTime() - tr2.getTime()) > maxTransitionTimeDelta) {
|
||||
return false;
|
||||
}
|
||||
if (ignoreDstAmount) {
|
||||
if (tr1.getTo().getRawOffset() + tr1.getTo().getDSTSavings()
|
||||
!= tr2.getTo().getRawOffset() + tr2.getTo().getDSTSavings()
|
||||
|| tr1.getTo().getDSTSavings() != 0 && tr2.getTo().getDSTSavings() == 0
|
||||
|| tr1.getTo().getDSTSavings() == 0 && tr2.getTo().getDSTSavings() != 0) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (tr1.getTo().getRawOffset() != tr2.getTo().getRawOffset() ||
|
||||
tr1.getTo().getDSTSavings() != tr2.getTo().getDSTSavings()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
time = tr1.getTime() > tr2.getTime() ? tr1.getTime() : tr2.getTime();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user