diff --git a/src/main/java/net/logstash/logback/composite/FastISOTimestampFormatter.java b/src/main/java/net/logstash/logback/composite/FastISOTimestampFormatter.java index bcf526bb..19dcbb2e 100644 --- a/src/main/java/net/logstash/logback/composite/FastISOTimestampFormatter.java +++ b/src/main/java/net/logstash/logback/composite/FastISOTimestampFormatter.java @@ -20,6 +20,8 @@ import java.time.ZoneOffset; import java.time.format.DateTimeFormatter; import java.time.zone.ZoneOffsetTransition; +import java.time.zone.ZoneRules; +import java.util.List; /** * A fast alternative to DateTimeFormatter when formatting millis using an ISO format. @@ -167,12 +169,13 @@ private class ZoneOffsetState { Instant now = Instant.ofEpochMilli(timestampInMillis); ZoneOffset zoneOffset; - + + ZoneRules rules = zoneId.getRules(); /* * The Zone has a fixed offset that will never change. */ - if (zoneId.getRules().isFixedOffset()) { - zoneOffset = zoneId.getRules().getOffset(now); + if (rules.isFixedOffset()) { + zoneOffset = rules.getOffset(now); this.zoneTransitionStart = 0; this.zoneTransitionStop = Long.MAX_VALUE; } @@ -181,7 +184,12 @@ private class ZoneOffsetState { * and how long it is valid. */ else { - ZoneOffsetTransition zoneOffsetTransition = zoneId.getRules().nextTransition(now); + ZoneOffsetTransition zoneOffsetTransition = rules.nextTransition(now); + if (zoneOffsetTransition == null) { + List transitions = rules.getTransitions(); + zoneOffsetTransition = transitions.get(transitions.size() - 1); + } + this.zoneTransitionStart = timestampInMillis; this.zoneTransitionStop = zoneOffsetTransition.toEpochSecond() * 1_000; zoneOffset = zoneOffsetTransition.getOffsetBefore(); diff --git a/src/test/java/net/logstash/logback/composite/FastISOTimestampFormatterTest.java b/src/test/java/net/logstash/logback/composite/FastISOTimestampFormatterTest.java index c65bc202..97fd2d8b 100644 --- a/src/test/java/net/logstash/logback/composite/FastISOTimestampFormatterTest.java +++ b/src/test/java/net/logstash/logback/composite/FastISOTimestampFormatterTest.java @@ -18,6 +18,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatCode; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; +import static org.assertj.core.api.Assertions.assertThatNoException; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -267,8 +268,14 @@ protected ZoneRules provideRules(String zoneId, boolean forCaching) { assertThat(invokeTwice(fast, after.toInstant())).isEqualTo(formatter.format(after)); }); } - - + + /* + * Assert after the last transitions are not exception + */ + @Test + public void afterTheLastTransition() { + assertThatNoException().isThrownBy(() -> FastISOTimestampFormatter.isoOffsetDateTime(ZoneId.of("Asia/Bangkok"))); + } /* * Invoke same formatter from concurrent threads. Force invalidation of the cache by making