Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8236903

ZoneRules#getOffset throws DateTimeException for rules with last rules

    XMLWordPrintable

Details

    • b08
    • generic
    • generic
    • Not verified

    Description

      A DESCRIPTION OF THE PROBLEM :
      The method java.time.zone.ZoneRules#getOffset(java.time.Instant) will throw the following exception:
      Exception in thread "main" java.time.DateTimeException: Invalid value for EpochDay (valid values -365243219162 - 365241780471): 365241780472
      at java.base/java.time.temporal.ValueRange.checkValidValue(ValueRange.java:311)
      at java.base/java.time.temporal.ChronoField.checkValidValue(ChronoField.java:717)
      at java.base/java.time.LocalDate.ofEpochDay(LocalDate.java:341)
      at java.base/java.time.zone.ZoneRules.findYear(ZoneRules.java:927)
      at java.base/java.time.zone.ZoneRules.getOffset(ZoneRules.java:486)

      if the ZoneRules has a last rule and has a transition such that when added to the instant will be larger than the maximum epoch-day.

      Offsets of the same size that do not contain last rules will not throw an error for the same instants.

      The method does not declare that a DateTimeException exception may be thrown and the description implies that it should be possible to get the offset for any instant.

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      ➜ observability git:(master) jshell
      | Welcome to JShell -- Version 13.0.1
      | For an introduction type: /help intro

      jshell> import java.time.*;
         ...> import java.time.zone.ZoneOffsetTransition;
         ...> import java.time.zone.ZoneOffsetTransitionRule;
         ...> import java.time.zone.ZoneRules;
         ...> import java.util.Collections;
         ...>

      jshell> Instant maxLocalDateTime = LocalDateTime.of(Year.MAX_VALUE,
         ...> 12,
         ...> 31,
         ...> 23,
         ...> 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);
         ...> ZoneOffsetTransitionRule transitionRule = ZoneOffsetTransitionRule.of(Month.JANUARY,
         ...> 1,
         ...> DayOfWeek.SUNDAY,
         ...> LocalTime.MIDNIGHT,
         ...> true,
         ...> ZoneOffsetTransitionRule.TimeDefinition.STANDARD,
         ...> offsetZero,
         ...> offsetZero,
         ...> offsetPlusOneHour);
         ...> ZoneRules zoneRulesB = ZoneRules.of(offsetZero,
         ...> offsetZero,
         ...> Collections.singletonList(transition),
         ...> Collections.singletonList(transition),
         ...> Collections.singletonList(transitionRule));
         ...> ZoneOffset offsetA = zoneRulesA.getOffset(maxLocalDateTime);
         ...> ZoneOffset offsetB = zoneRulesB.getOffset(maxLocalDateTime);
         ...> boolean areEqual = offsetA.equals(offsetB);
         ...>

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      areEqual ==> true
      ACTUAL -
      | Exception java.time.DateTimeException: Invalid value for EpochDay (valid values -365243219162 - 365241780471): 365241780472
      | at ValueRange.checkValidValue (ValueRange.java:311)
      | at ChronoField.checkValidValue (ChronoField.java:717)
      | at LocalDate.ofEpochDay (LocalDate.java:341)
      | at ZoneRules.findYear (ZoneRules.java:927)
      | at ZoneRules.getOffset (ZoneRules.java:486)
      | at (#14:1)

      ---------- BEGIN SOURCE ----------
      import java.time.*;
      import java.time.zone.ZoneOffsetTransition;
      import java.time.zone.ZoneOffsetTransitionRule;
      import java.time.zone.ZoneRules;
      import java.util.Collections;

      public class ZoneRulesBug {

          public static void main(String[] args) {
              Instant maxLocalDateTime = LocalDateTime.of(Year.MAX_VALUE,
                      12,
                      31,
                      23,
                      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);
              ZoneOffsetTransitionRule transitionRule = ZoneOffsetTransitionRule.of(Month.JANUARY,
                      1,
                      DayOfWeek.SUNDAY,
                      LocalTime.MIDNIGHT,
                      true,
                      ZoneOffsetTransitionRule.TimeDefinition.STANDARD,
                      offsetZero,
                      offsetZero,
                      offsetPlusOneHour);
              ZoneRules zoneRulesB = ZoneRules.of(offsetZero,
                      offsetZero,
                      Collections.singletonList(transition),
                      Collections.singletonList(transition),
                      Collections.singletonList(transitionRule));
              ZoneOffset offsetA = zoneRulesA.getOffset(maxLocalDateTime);
              ZoneOffset offsetB = zoneRulesB.getOffset(maxLocalDateTime);
              boolean areEqual = offsetA.equals(offsetB);
              System.out.println(areEqual);
          }
      }

      ---------- END SOURCE ----------

      FREQUENCY : always


      Attachments

        Activity

          People

            naoto Naoto Sato
            webbuggrp Webbug Group
            Votes:
            0 Vote for this issue
            Watchers:
            4 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved: