RFR: JDK-8079063 ZoneOffsetTransition constructor should ignore nanoseconds

Roger Riggs Roger.Riggs at Oracle.com
Wed May 6 14:43:22 UTC 2015


Hi Peter,

Thanks for the analysis and followup.

Yes, I think thesimple check as you propose is the desired clarification.
I agree that the change should not affect any existing code outside the JDK
and does not raise a compatibility issue.

Roger


On 5/4/2015 6:22 AM, Peter Levart wrote:
> 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