mirror of
https://github.com/openjdk/jdk.git
synced 2026-04-26 14:50:34 +00:00
8239836: ZoneRules.of() doesn't check transitionList/standardOffsetTL arguments validity
Reviewed-by: rriggs, joehw, scolebourne
This commit is contained in:
parent
5c8f935641
commit
123ac07064
@ -470,7 +470,10 @@ public final class ZoneRules implements Serializable {
|
||||
* @return true if the time-zone is fixed and the offset never changes
|
||||
*/
|
||||
public boolean isFixedOffset() {
|
||||
return savingsInstantTransitions.length == 0;
|
||||
return standardOffsets[0].equals(wallOffsets[0]) &&
|
||||
standardTransitions.length == 0 &&
|
||||
savingsInstantTransitions.length == 0 &&
|
||||
lastRules.length == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -486,7 +489,7 @@ public final class ZoneRules implements Serializable {
|
||||
*/
|
||||
public ZoneOffset getOffset(Instant instant) {
|
||||
if (savingsInstantTransitions.length == 0) {
|
||||
return standardOffsets[0];
|
||||
return wallOffsets[0];
|
||||
}
|
||||
long epochSec = instant.getEpochSecond();
|
||||
// check if using last rules
|
||||
@ -572,7 +575,7 @@ public final class ZoneRules implements Serializable {
|
||||
* There are various ways to handle the conversion from a {@code LocalDateTime}.
|
||||
* One technique, using this method, would be:
|
||||
* <pre>
|
||||
* List<ZoneOffset> validOffsets = rules.getOffset(localDT);
|
||||
* List<ZoneOffset> validOffsets = rules.getValidOffsets(localDT);
|
||||
* if (validOffsets.size() == 1) {
|
||||
* // Normal case: only one valid offset
|
||||
* zoneOffset = validOffsets.get(0);
|
||||
@ -640,8 +643,8 @@ public final class ZoneRules implements Serializable {
|
||||
}
|
||||
|
||||
private Object getOffsetInfo(LocalDateTime dt) {
|
||||
if (savingsInstantTransitions.length == 0) {
|
||||
return standardOffsets[0];
|
||||
if (savingsLocalTransitions.length == 0) {
|
||||
return wallOffsets[0];
|
||||
}
|
||||
// check if using last rules
|
||||
if (lastRules.length > 0 &&
|
||||
@ -756,7 +759,7 @@ public final class ZoneRules implements Serializable {
|
||||
* @return the standard offset, not null
|
||||
*/
|
||||
public ZoneOffset getStandardOffset(Instant instant) {
|
||||
if (savingsInstantTransitions.length == 0) {
|
||||
if (standardTransitions.length == 0) {
|
||||
return standardOffsets[0];
|
||||
}
|
||||
long epochSec = instant.getEpochSecond();
|
||||
@ -786,7 +789,7 @@ public final class ZoneRules implements Serializable {
|
||||
* @return the difference between the standard and actual offset, not null
|
||||
*/
|
||||
public Duration getDaylightSavings(Instant instant) {
|
||||
if (savingsInstantTransitions.length == 0) {
|
||||
if (isFixedOffset()) {
|
||||
return Duration.ZERO;
|
||||
}
|
||||
ZoneOffset standardOffset = getStandardOffset(instant);
|
||||
|
||||
@ -24,6 +24,7 @@
|
||||
package test.java.time.zone;
|
||||
|
||||
import java.time.DayOfWeek;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
@ -37,16 +38,17 @@ import java.time.zone.ZoneOffsetTransition;
|
||||
import java.time.zone.ZoneOffsetTransitionRule;
|
||||
import java.time.zone.ZoneRules;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.testng.annotations.Test;
|
||||
import org.testng.annotations.DataProvider;
|
||||
import org.testng.annotations.Test;
|
||||
import static org.testng.Assert.assertEquals;
|
||||
import static org.testng.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* @summary Tests for ZoneRules class.
|
||||
*
|
||||
* @bug 8212970 8236903
|
||||
* @bug 8212970 8236903 8239836
|
||||
*/
|
||||
@Test
|
||||
public class TestZoneRules {
|
||||
@ -59,37 +61,44 @@ public class TestZoneRules {
|
||||
private static final ZoneId TOKYO = ZoneId.of("Asia/Tokyo");
|
||||
private static final LocalTime ONE_AM = LocalTime.of(1, 0);
|
||||
|
||||
private static final ZoneOffset OFF_0 = ZoneOffset.ofHours(0);
|
||||
private static final ZoneOffset OFF_1 = ZoneOffset.ofHours(1);
|
||||
private static final ZoneOffset OFF_2 = ZoneOffset.ofHours(2);
|
||||
private static final List EL = Collections.emptyList();
|
||||
private static final ZoneOffsetTransition ZOT = ZoneId.of("America/Los_Angeles").getRules().getTransitions().get(0);
|
||||
private static final ZoneOffsetTransitionRule ZOTR = ZoneId.of("America/Los_Angeles").getRules().getTransitionRules().get(0);
|
||||
|
||||
@DataProvider
|
||||
private Object[][] negativeDST () {
|
||||
return new Object[][] {
|
||||
// ZoneId, localDate, offset, standard offset, isDaylightSavings
|
||||
// Europe/Dublin for the Rule "Eire"
|
||||
{DUBLIN, LocalDate.of(1970, 6, 23), ZoneOffset.ofHours(1), ZoneOffset.ofHours(0), true},
|
||||
{DUBLIN, LocalDate.of(1971, 6, 23), ZoneOffset.ofHours(1), ZoneOffset.ofHours(0), true},
|
||||
{DUBLIN, LocalDate.of(1971, 11, 1), ZoneOffset.ofHours(0), ZoneOffset.ofHours(0), false},
|
||||
{DUBLIN, LocalDate.of(2019, 6, 23), ZoneOffset.ofHours(1), ZoneOffset.ofHours(0), true},
|
||||
{DUBLIN, LocalDate.of(2019, 12, 23), ZoneOffset.ofHours(0), ZoneOffset.ofHours(0), false},
|
||||
{DUBLIN, LocalDate.of(1970, 6, 23), OFF_1, OFF_0, true},
|
||||
{DUBLIN, LocalDate.of(1971, 6, 23), OFF_1, OFF_0, true},
|
||||
{DUBLIN, LocalDate.of(1971, 11, 1), OFF_0, OFF_0, false},
|
||||
{DUBLIN, LocalDate.of(2019, 6, 23), OFF_1, OFF_0, true},
|
||||
{DUBLIN, LocalDate.of(2019, 12, 23), OFF_0, OFF_0, false},
|
||||
|
||||
// Europe/Prague which contains fixed negative savings (not a named Rule)
|
||||
{PRAGUE, LocalDate.of(1946, 9, 30), ZoneOffset.ofHours(2), ZoneOffset.ofHours(1), true},
|
||||
{PRAGUE, LocalDate.of(1946, 10, 10), ZoneOffset.ofHours(1), ZoneOffset.ofHours(1), false},
|
||||
{PRAGUE, LocalDate.of(1946, 12, 3), ZoneOffset.ofHours(0), ZoneOffset.ofHours(0), false},
|
||||
{PRAGUE, LocalDate.of(1947, 2, 25), ZoneOffset.ofHours(1), ZoneOffset.ofHours(1), false},
|
||||
{PRAGUE, LocalDate.of(1947, 4, 30), ZoneOffset.ofHours(2), ZoneOffset.ofHours(1), true},
|
||||
{PRAGUE, LocalDate.of(1946, 9, 30), OFF_2, OFF_1, true},
|
||||
{PRAGUE, LocalDate.of(1946, 10, 10), OFF_1, OFF_1, false},
|
||||
{PRAGUE, LocalDate.of(1946, 12, 3), OFF_0, OFF_0, false},
|
||||
{PRAGUE, LocalDate.of(1947, 2, 25), OFF_1, OFF_1, false},
|
||||
{PRAGUE, LocalDate.of(1947, 4, 30), OFF_2, OFF_1, true},
|
||||
|
||||
// Africa/Windhoek for the Rule "Namibia"
|
||||
{WINDHOEK, LocalDate.of(1994, 3, 23), ZoneOffset.ofHours(1), ZoneOffset.ofHours(1), false},
|
||||
{WINDHOEK, LocalDate.of(2016, 9, 23), ZoneOffset.ofHours(2), ZoneOffset.ofHours(1), true},
|
||||
{WINDHOEK, LocalDate.of(1994, 3, 23), OFF_1, OFF_1, false},
|
||||
{WINDHOEK, LocalDate.of(2016, 9, 23), OFF_2, OFF_1, true},
|
||||
|
||||
// Africa/Casablanca for the Rule "Morocco" Defines negative DST till 2037 as of 2019a.
|
||||
{CASABLANCA, LocalDate.of(1939, 9, 13), ZoneOffset.ofHours(1), ZoneOffset.ofHours(0), true},
|
||||
{CASABLANCA, LocalDate.of(1939, 11, 20), ZoneOffset.ofHours(0), ZoneOffset.ofHours(0), false},
|
||||
{CASABLANCA, LocalDate.of(2018, 6, 18), ZoneOffset.ofHours(1), ZoneOffset.ofHours(0), true},
|
||||
{CASABLANCA, LocalDate.of(2019, 1, 1), ZoneOffset.ofHours(1), ZoneOffset.ofHours(0), true},
|
||||
{CASABLANCA, LocalDate.of(2019, 5, 6), ZoneOffset.ofHours(0), ZoneOffset.ofHours(0), false},
|
||||
{CASABLANCA, LocalDate.of(2037, 10, 5), ZoneOffset.ofHours(0), ZoneOffset.ofHours(0), false},
|
||||
{CASABLANCA, LocalDate.of(2037, 11, 16), ZoneOffset.ofHours(1), ZoneOffset.ofHours(0), true},
|
||||
{CASABLANCA, LocalDate.of(2038, 11, 1), ZoneOffset.ofHours(1), ZoneOffset.ofHours(0), true},
|
||||
{CASABLANCA, LocalDate.of(1939, 9, 13), OFF_1, OFF_0, true},
|
||||
{CASABLANCA, LocalDate.of(1939, 11, 20), OFF_0, OFF_0, false},
|
||||
{CASABLANCA, LocalDate.of(2018, 6, 18), OFF_1, OFF_0, true},
|
||||
{CASABLANCA, LocalDate.of(2019, 1, 1), OFF_1, OFF_0, true},
|
||||
{CASABLANCA, LocalDate.of(2019, 5, 6), OFF_0, OFF_0, false},
|
||||
{CASABLANCA, LocalDate.of(2037, 10, 5), OFF_0, OFF_0, false},
|
||||
{CASABLANCA, LocalDate.of(2037, 11, 16), OFF_1, OFF_0, true},
|
||||
{CASABLANCA, LocalDate.of(2038, 11, 1), OFF_1, OFF_0, true},
|
||||
};
|
||||
}
|
||||
|
||||
@ -108,6 +117,28 @@ public class TestZoneRules {
|
||||
};
|
||||
}
|
||||
|
||||
@DataProvider
|
||||
private Object[][] emptyTransitionList() {
|
||||
return new Object[][] {
|
||||
// days, offset, std offset, savings, isDST
|
||||
{7, 1, 2, -1, true},
|
||||
{-7, 1, 1, 0, false},
|
||||
};
|
||||
}
|
||||
|
||||
@DataProvider
|
||||
private Object[][] isFixedOffset() {
|
||||
return new Object[][] {
|
||||
// ZoneRules, expected
|
||||
{ZoneRules.of(OFF_0), true},
|
||||
{ZoneRules.of(OFF_0, OFF_0, EL, EL, EL), true},
|
||||
{ZoneRules.of(OFF_0, OFF_1, EL, EL, EL), false},
|
||||
{ZoneRules.of(OFF_0, OFF_0, Collections.singletonList(ZOT), EL, EL), false},
|
||||
{ZoneRules.of(OFF_0, OFF_0, EL, Collections.singletonList(ZOT), EL), false},
|
||||
{ZoneRules.of(OFF_0, OFF_0, EL, EL, Collections.singletonList(ZOTR)), false},
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Test ZoneRules whether the savings are positive in time zones that have
|
||||
* negative savings in the source TZ files.
|
||||
@ -147,23 +178,21 @@ public class TestZoneRules {
|
||||
59,
|
||||
59,
|
||||
999999999).toInstant(ZoneOffset.UTC);
|
||||
ZoneOffset offsetZero = ZoneOffset.ofHours(0);
|
||||
ZoneOffset offsetPlusOneHour = ZoneOffset.ofHours(1);
|
||||
ZoneRules zoneRulesA = ZoneRules.of(offsetPlusOneHour);
|
||||
ZoneOffsetTransition transition = ZoneOffsetTransition.of(LocalDateTime.ofEpochSecond(0, 0, offsetZero),
|
||||
offsetZero,
|
||||
offsetPlusOneHour);
|
||||
ZoneRules zoneRulesA = ZoneRules.of(OFF_1);
|
||||
ZoneOffsetTransition transition = ZoneOffsetTransition.of(LocalDateTime.ofEpochSecond(0, 0, OFF_0),
|
||||
OFF_0,
|
||||
OFF_1);
|
||||
ZoneOffsetTransitionRule transitionRule = ZoneOffsetTransitionRule.of(Month.JANUARY,
|
||||
1,
|
||||
DayOfWeek.SUNDAY,
|
||||
LocalTime.MIDNIGHT,
|
||||
true,
|
||||
ZoneOffsetTransitionRule.TimeDefinition.STANDARD,
|
||||
offsetZero,
|
||||
offsetZero,
|
||||
offsetPlusOneHour);
|
||||
ZoneRules zoneRulesB = ZoneRules.of(offsetZero,
|
||||
offsetZero,
|
||||
OFF_0,
|
||||
OFF_0,
|
||||
OFF_1);
|
||||
ZoneRules zoneRulesB = ZoneRules.of(OFF_0,
|
||||
OFF_0,
|
||||
Collections.singletonList(transition),
|
||||
Collections.singletonList(transition),
|
||||
Collections.singletonList(transitionRule));
|
||||
@ -171,4 +200,35 @@ public class TestZoneRules {
|
||||
ZoneOffset offsetB = zoneRulesB.getOffset(maxLocalDateTime);
|
||||
assertEquals(offsetA, offsetB);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests whether empty "transitionList" is correctly interpreted.
|
||||
* @bug 8239836
|
||||
*/
|
||||
@Test(dataProvider="emptyTransitionList")
|
||||
public void test_EmptyTransitionList(int days, int offset, int stdOffset, int savings, boolean isDST) {
|
||||
LocalDateTime transitionDay = LocalDateTime.of(2020, 1, 1, 2, 0);
|
||||
Instant testDay = transitionDay.plusDays(days).toInstant(ZoneOffset.UTC);
|
||||
ZoneOffsetTransition trans = ZoneOffsetTransition.of(
|
||||
transitionDay,
|
||||
OFF_1,
|
||||
OFF_2);
|
||||
ZoneRules rules = ZoneRules.of(OFF_1, OFF_1,
|
||||
Collections.singletonList(trans),
|
||||
Collections.emptyList(), Collections.emptyList());
|
||||
|
||||
assertEquals(rules.getOffset(testDay), ZoneOffset.ofHours(offset));
|
||||
assertEquals(rules.getStandardOffset(testDay), ZoneOffset.ofHours(stdOffset));
|
||||
assertEquals(rules.getDaylightSavings(testDay), Duration.ofHours(savings));
|
||||
assertEquals(rules.isDaylightSavings(testDay), isDST);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests whether isFixedOffset() is working correctly
|
||||
* @bug 8239836
|
||||
*/
|
||||
@Test(dataProvider="isFixedOffset")
|
||||
public void test_IsFixedOffset(ZoneRules zr, boolean expected) {
|
||||
assertEquals(zr.isFixedOffset(), expected);
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user