FULL PRODUCT VERSION :
java version "1.8.0_102"
Java(TM) SE Runtime Environment (build 1.8.0_102-b14)
Java HotSpot(TM) 64-Bit Server VM (build 25.102-b14, mixed mode)
ADDITIONAL OS VERSION INFORMATION :
Window 7/64-bit
A DESCRIPTION OF THE PROBLEM :
The java.time.zone.ZoneRules have inconsistent previous / next transition handling at a transition instant time. Even the transition instant time correcly represents the new transition offset the previous transition has not been changed.
This breaks following invariants
previousTransition.OffsetAfter == nextTransition.OffsetBefore
previousTransition.OffsetAfter == Offset
The previousTransition method should be rather specified as
"Gets the previous transition before or at the specified instant"
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
import java.time.Instant;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.zone.ZoneOffsetTransition;
import java.time.zone.ZoneRules;
import org.junit.Assert;
import org.junit.Test;
public final class ZoneRulesPreviousTest {
@Test
public void testPreviousEuropeBerlinZone() {
final Instant now = Instant.now();
final ZoneRules zoneRules = ZoneId.of("Europe/Berlin").getRules();
final Instant transitionInstant = zoneRules.nextTransition(now).getInstant();
// BEFORE TRANSITION
{
final Instant beforeTransitionInstant = transitionInstant.minusMillis(1);
final ZoneOffset offset = zoneRules.getOffset(beforeTransitionInstant);
final ZoneOffsetTransition prevTransition = zoneRules.previousTransition(beforeTransitionInstant);
final ZoneOffsetTransition nextTransition = zoneRules.nextTransition(beforeTransitionInstant);
Assert.assertEquals(prevTransition.getOffsetAfter(), nextTransition.getOffsetBefore());
Assert.assertEquals(prevTransition.getOffsetAfter(), offset);
Assert.assertEquals(nextTransition.getOffsetBefore(), offset);
}
// AFTER TRANSITION
{
final Instant afterTransitionInstant = transitionInstant.plusMillis(1);
final ZoneOffset offset = zoneRules.getOffset(afterTransitionInstant);
final ZoneOffsetTransition prevTransition = zoneRules.previousTransition(afterTransitionInstant);
final ZoneOffsetTransition nextTransition = zoneRules.nextTransition(afterTransitionInstant);
Assert.assertEquals(prevTransition.getOffsetAfter(), nextTransition.getOffsetBefore());
Assert.assertEquals(prevTransition.getOffsetAfter(), offset);
Assert.assertEquals(nextTransition.getOffsetBefore(), offset);
}
// AT TRANSITION
{
final Instant atTransitionInstant = transitionInstant;
final ZoneOffset offset = zoneRules.getOffset(atTransitionInstant);
final ZoneOffsetTransition prevTransition = zoneRules.previousTransition(atTransitionInstant);
final ZoneOffsetTransition nextTransition = zoneRules.nextTransition(atTransitionInstant);
Assert.assertEquals(prevTransition.getOffsetAfter(), nextTransition.getOffsetBefore());
Assert.assertEquals(prevTransition.getOffsetAfter(), offset);
Assert.assertEquals(nextTransition.getOffsetBefore(), offset);
}
}
}
REPRODUCIBILITY :
This bug can be reproduced always.
java version "1.8.0_102"
Java(TM) SE Runtime Environment (build 1.8.0_102-b14)
Java HotSpot(TM) 64-Bit Server VM (build 25.102-b14, mixed mode)
ADDITIONAL OS VERSION INFORMATION :
Window 7/64-bit
A DESCRIPTION OF THE PROBLEM :
The java.time.zone.ZoneRules have inconsistent previous / next transition handling at a transition instant time. Even the transition instant time correcly represents the new transition offset the previous transition has not been changed.
This breaks following invariants
previousTransition.OffsetAfter == nextTransition.OffsetBefore
previousTransition.OffsetAfter == Offset
The previousTransition method should be rather specified as
"Gets the previous transition before or at the specified instant"
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
import java.time.Instant;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.zone.ZoneOffsetTransition;
import java.time.zone.ZoneRules;
import org.junit.Assert;
import org.junit.Test;
public final class ZoneRulesPreviousTest {
@Test
public void testPreviousEuropeBerlinZone() {
final Instant now = Instant.now();
final ZoneRules zoneRules = ZoneId.of("Europe/Berlin").getRules();
final Instant transitionInstant = zoneRules.nextTransition(now).getInstant();
// BEFORE TRANSITION
{
final Instant beforeTransitionInstant = transitionInstant.minusMillis(1);
final ZoneOffset offset = zoneRules.getOffset(beforeTransitionInstant);
final ZoneOffsetTransition prevTransition = zoneRules.previousTransition(beforeTransitionInstant);
final ZoneOffsetTransition nextTransition = zoneRules.nextTransition(beforeTransitionInstant);
Assert.assertEquals(prevTransition.getOffsetAfter(), nextTransition.getOffsetBefore());
Assert.assertEquals(prevTransition.getOffsetAfter(), offset);
Assert.assertEquals(nextTransition.getOffsetBefore(), offset);
}
// AFTER TRANSITION
{
final Instant afterTransitionInstant = transitionInstant.plusMillis(1);
final ZoneOffset offset = zoneRules.getOffset(afterTransitionInstant);
final ZoneOffsetTransition prevTransition = zoneRules.previousTransition(afterTransitionInstant);
final ZoneOffsetTransition nextTransition = zoneRules.nextTransition(afterTransitionInstant);
Assert.assertEquals(prevTransition.getOffsetAfter(), nextTransition.getOffsetBefore());
Assert.assertEquals(prevTransition.getOffsetAfter(), offset);
Assert.assertEquals(nextTransition.getOffsetBefore(), offset);
}
// AT TRANSITION
{
final Instant atTransitionInstant = transitionInstant;
final ZoneOffset offset = zoneRules.getOffset(atTransitionInstant);
final ZoneOffsetTransition prevTransition = zoneRules.previousTransition(atTransitionInstant);
final ZoneOffsetTransition nextTransition = zoneRules.nextTransition(atTransitionInstant);
Assert.assertEquals(prevTransition.getOffsetAfter(), nextTransition.getOffsetBefore());
Assert.assertEquals(prevTransition.getOffsetAfter(), offset);
Assert.assertEquals(nextTransition.getOffsetBefore(), offset);
}
}
}
REPRODUCIBILITY :
This bug can be reproduced always.