RFR: JDK-8079063 ZoneOffsetTransition constructor should ignore nanoseconds

Peter Levart peter.levart at gmail.com
Mon May 4 10:22:30 UTC 2015


Hi,

Now that JDK-8074003 is in, I'd like to discuss how to tackle JDK-8079063.

Package-private ZoneOffsetTransition constructor that takes 
LocalDateTime transition is invoked from the following 4 places:

1 - the public static factory method:

     /**
      * Obtains an instance defining a transition between two offsets.
      * <p>
      * Applications should normally obtain an instance from {@link 
ZoneRules}.
      * This factory is only intended for use when creating {@link 
ZoneRules}.
      *
      * @param transition  the transition date-time at the transition, 
which never
      *  actually occurs, expressed local to the before offset, not null
      * @param offsetBefore  the offset before the transition, not null
      * @param offsetAfter  the offset at and after the transition, not null
      * @return the transition, not null
      * @throws IllegalArgumentException if {@code offsetBefore} and 
{@code offsetAfter}
      *         are equal, or {@code transition.getNano()} returns 
non-zero value
      */
     public static ZoneOffsetTransition of(LocalDateTime transition, 
ZoneOffset offsetBefore, ZoneOffset offsetAfter) {

...this one already disallows transition parameters that have 
transition.getNano() != 0.


2 - Lines 498..500 of ZoneOffsetTransitionRule:

         LocalDateTime localDT = LocalDateTime.of(date, time);
         LocalDateTime transition = 
timeDefinition.createDateTime(localDT, standardOffset, offsetBefore);
         return new ZoneOffsetTransition(transition, offsetBefore, 
offsetAfter);

...where 'time' is an instance field of ZoneOffsetTransitionRule. The 
ZoneOffsetTransitionRule public static factory method has the following 
definition:

     /**
      * Obtains an instance defining the yearly rule to create 
transitions between two offsets.
      * <p>
      * Applications should normally obtain an instance from {@link 
ZoneRules}.
      * This factory is only intended for use when creating {@link 
ZoneRules}.
      *
      * @param month  the month of the month-day of the first day of the 
cutover week, not null
      * @param dayOfMonthIndicator  the day of the month-day of the 
cutover week, positive if the week is that
      *  day or later, negative if the week is that day or earlier, 
counting from the last day of the month,
      *  from -28 to 31 excluding 0
      * @param dayOfWeek  the required day-of-week, null if the 
month-day should not be changed
      * @param time  the cutover time in the 'before' offset, not null
      * @param timeEndOfDay  whether the time is midnight at the end of day
      * @param timeDefnition  how to interpret the cutover
      * @param standardOffset  the standard offset in force at the 
cutover, not null
      * @param offsetBefore  the offset before the cutover, not null
      * @param offsetAfter  the offset after the cutover, not null
      * @return the rule, not null
      * @throws IllegalArgumentException if the day of month indicator 
is invalid
      * @throws IllegalArgumentException if the end of day flag is true 
when the time is not midnight
      */
     public static ZoneOffsetTransitionRule of(
             Month month,
             int dayOfMonthIndicator,
             DayOfWeek dayOfWeek,
             LocalTime time,
             boolean timeEndOfDay,
             TimeDefinition timeDefnition,
             ZoneOffset standardOffset,
             ZoneOffset offsetBefore,
             ZoneOffset offsetAfter) {
         Objects.requireNonNull(month, "month");
         Objects.requireNonNull(time, "time");
         Objects.requireNonNull(timeDefnition, "timeDefnition");
         Objects.requireNonNull(standardOffset, "standardOffset");
         Objects.requireNonNull(offsetBefore, "offsetBefore");
         Objects.requireNonNull(offsetAfter, "offsetAfter");
         if (dayOfMonthIndicator < -28 || dayOfMonthIndicator > 31 || 
dayOfMonthIndicator == 0) {
             throw new IllegalArgumentException("Day of month indicator 
must be between -28 and 31 inclusive excluding zero");
         }
         if (timeEndOfDay && time.equals(LocalTime.MIDNIGHT) == false) {
             throw new IllegalArgumentException("Time must be midnight 
when end of day flag is true");
         }
         return new ZoneOffsetTransitionRule(month, dayOfMonthIndicator, 
dayOfWeek, time, timeEndOfDay, timeDefnition, standardOffset, 
offsetBefore, offsetAfter);
     }

...which allows 'time' parameter (that becomes 
ZoneOffsetTransitionRule's 'time' field) with no restriction as to 
whether it can contain nanos != 0 or not.


3, 4 - Lines 668..678 of ZoneRules private getOffsetInfo method:

             LocalDateTime dtBefore = savingsLocalTransitions[index];
             LocalDateTime dtAfter = savingsLocalTransitions[index + 1];
             ZoneOffset offsetBefore = wallOffsets[index / 2];
             ZoneOffset offsetAfter = wallOffsets[index / 2 + 1];
             if (offsetAfter.getTotalSeconds() > 
offsetBefore.getTotalSeconds()) {
                 // gap
                 return new ZoneOffsetTransition(dtBefore, offsetBefore, 
offsetAfter);
             } else {
                 // overlap
                 return new ZoneOffsetTransition(dtAfter, offsetBefore, 
offsetAfter);
             }

...where dtBefore/dtAfter "transition" parameters are taken from 
savingsLocalTransitions[] array that is filled-in in ZoneRules 
constructors from passed-in ZoneOffsetTransition objects. So here no 
nanos != 0 can sneak in if ZoneOffsetTransition invariant holds.

The only place where nanos can sneak-in therefore seems to be the public 
ZoneOffsetTransitionRule.of() factory method. The question is whether 
the spec. could be changed so that ZoneOffsetTransitionRule.of() factory 
method would add another @throws definition:

      * @throws IllegalArgumentException if {@code time.getNano()} 
returns non-zero value


This, I think, would be consistent with ZoneOffsetTransition.of() 
factory method and I believe early enough in the live of the API so that 
no custom software would be affected:

http://cr.openjdk.java.net/~plevart/jdk9-dev/ZoneOffsetTransitionRule.time/webrev.01/

What do you think?

Regards, Peter




More information about the core-libs-dev mailing list