< prev index next >

src/java.base/share/classes/java/time/zone/ZoneRules.java

Print this page
rev 58174 : 8239836: ZoneRules.of() doesn't check transitionList/standardOffsetTL arguments validity
Reviewed-by: rriggs


 453         }
 454         ZoneOffset[] savOffsets = new ZoneOffset[savSize + 1];
 455         for (int i = 0; i < savOffsets.length; i++) {
 456             savOffsets[i] = Ser.readOffset(in);
 457         }
 458         int ruleSize = in.readByte();
 459         ZoneOffsetTransitionRule[] rules = (ruleSize == 0) ?
 460             EMPTY_LASTRULES : new ZoneOffsetTransitionRule[ruleSize];
 461         for (int i = 0; i < ruleSize; i++) {
 462             rules[i] = ZoneOffsetTransitionRule.readExternal(in);
 463         }
 464         return new ZoneRules(stdTrans, stdOffsets, savTrans, savOffsets, rules);
 465     }
 466 
 467     /**
 468      * Checks of the zone rules are fixed, such that the offset never varies.
 469      *
 470      * @return true if the time-zone is fixed and the offset never changes
 471      */
 472     public boolean isFixedOffset() {
 473         return savingsInstantTransitions.length == 0;
 474     }
 475 
 476     /**
 477      * Gets the offset applicable at the specified instant in these rules.
 478      * <p>
 479      * The mapping from an instant to an offset is simple, there is only
 480      * one valid offset for each instant.
 481      * This method returns that offset.
 482      *
 483      * @param instant  the instant to find the offset for, not null, but null
 484      *  may be ignored if the rules have a single offset for all instants
 485      * @return the offset, not null
 486      */
 487     public ZoneOffset getOffset(Instant instant) {
 488         if (savingsInstantTransitions.length == 0) {
 489             return standardOffsets[0];
 490         }
 491         long epochSec = instant.getEpochSecond();
 492         // check if using last rules
 493         if (lastRules.length > 0 &&

 494                 epochSec > savingsInstantTransitions[savingsInstantTransitions.length - 1]) {
 495             int year = findYear(epochSec, wallOffsets[wallOffsets.length - 1]);
 496             ZoneOffsetTransition[] transArray = findTransitionArray(year);
 497             ZoneOffsetTransition trans = null;
 498             for (int i = 0; i < transArray.length; i++) {
 499                 trans = transArray[i];
 500                 if (epochSec < trans.toEpochSecond()) {
 501                     return trans.getOffsetBefore();
 502                 }
 503             }
 504             return trans.getOffsetAfter();
 505         }
 506 
 507         // using historic rules
 508         int index  = Arrays.binarySearch(savingsInstantTransitions, epochSec);
 509         if (index < 0) {
 510             // switch negative insert position to start of matched range
 511             index = -index - 2;
 512         }
 513         return wallOffsets[index + 1];


 623      * <pre>
 624      *  ZoneOffsetTransition trans = rules.getTransition(localDT);
 625      *  if (trans != null) {
 626      *    // Gap or Overlap: determine what to do from transition
 627      *  } else {
 628      *    // Normal case: only one valid offset
 629      *    zoneOffset = rule.getOffset(localDT);
 630      *  }
 631      * </pre>
 632      *
 633      * @param localDateTime  the local date-time to query for offset transition, not null, but null
 634      *  may be ignored if the rules have a single offset for all instants
 635      * @return the offset transition, null if the local date-time is not in transition
 636      */
 637     public ZoneOffsetTransition getTransition(LocalDateTime localDateTime) {
 638         Object info = getOffsetInfo(localDateTime);
 639         return (info instanceof ZoneOffsetTransition ? (ZoneOffsetTransition) info : null);
 640     }
 641 
 642     private Object getOffsetInfo(LocalDateTime dt) {
 643         if (savingsInstantTransitions.length == 0) {
 644             return standardOffsets[0];
 645         }
 646         // check if using last rules
 647         if (lastRules.length > 0 &&

 648                 dt.isAfter(savingsLocalTransitions[savingsLocalTransitions.length - 1])) {
 649             ZoneOffsetTransition[] transArray = findTransitionArray(dt.getYear());
 650             Object info = null;
 651             for (ZoneOffsetTransition trans : transArray) {
 652                 info = findOffsetInfo(dt, trans);
 653                 if (info instanceof ZoneOffsetTransition || info.equals(trans.getOffsetBefore())) {
 654                     return info;
 655                 }
 656             }
 657             return info;
 658         }
 659 
 660         // using historic rules
 661         int index  = Arrays.binarySearch(savingsLocalTransitions, dt);
 662         if (index == -1) {
 663             // before first transition
 664             return wallOffsets[0];
 665         }
 666         if (index < 0) {
 667             // switch negative insert position to start of matched range


 739         }
 740         if (year < LAST_CACHED_YEAR) {
 741             lastRulesCache.putIfAbsent(yearObj, transArray);
 742         }
 743         return transArray;
 744     }
 745 
 746     /**
 747      * Gets the standard offset for the specified instant in this zone.
 748      * <p>
 749      * This provides access to historic information on how the standard offset
 750      * has changed over time.
 751      * The standard offset is the offset before any daylight saving time is applied.
 752      * This is typically the offset applicable during winter.
 753      *
 754      * @param instant  the instant to find the offset information for, not null, but null
 755      *  may be ignored if the rules have a single offset for all instants
 756      * @return the standard offset, not null
 757      */
 758     public ZoneOffset getStandardOffset(Instant instant) {
 759         if (savingsInstantTransitions.length == 0) {
 760             return standardOffsets[0];
 761         }
 762         long epochSec = instant.getEpochSecond();
 763         int index  = Arrays.binarySearch(standardTransitions, epochSec);
 764         if (index < 0) {
 765             // switch negative insert position to start of matched range
 766             index = -index - 2;
 767         }
 768         return standardOffsets[index + 1];
 769     }
 770 
 771     /**
 772      * Gets the amount of daylight savings in use for the specified instant in this zone.
 773      * <p>
 774      * This provides access to historic information on how the amount of daylight
 775      * savings has changed over time.
 776      * This is the difference between the standard offset and the actual offset.
 777      * Typically the amount is zero during winter and one hour during summer.
 778      * Time-zones are second-based, so the nanosecond part of the duration will be zero.
 779      * <p>
 780      * This default implementation calculates the duration from the
 781      * {@link #getOffset(java.time.Instant) actual} and
 782      * {@link #getStandardOffset(java.time.Instant) standard} offsets.
 783      *
 784      * @param instant  the instant to find the daylight savings for, not null, but null
 785      *  may be ignored if the rules have a single offset for all instants
 786      * @return the difference between the standard and actual offset, not null
 787      */
 788     public Duration getDaylightSavings(Instant instant) {
 789         if (savingsInstantTransitions.length == 0) {
 790             return Duration.ZERO;
 791         }
 792         ZoneOffset standardOffset = getStandardOffset(instant);
 793         ZoneOffset actualOffset = getOffset(instant);
 794         return Duration.ofSeconds(actualOffset.getTotalSeconds() - standardOffset.getTotalSeconds());
 795     }
 796 
 797     /**
 798      * Checks if the specified instant is in daylight savings.
 799      * <p>
 800      * This checks if the standard offset and the actual offset are the same
 801      * for the specified instant.
 802      * If they are not, it is assumed that daylight savings is in operation.
 803      * <p>
 804      * This default implementation compares the {@link #getOffset(java.time.Instant) actual}
 805      * and {@link #getStandardOffset(java.time.Instant) standard} offsets.
 806      *
 807      * @param instant  the instant to find the offset information for, not null, but null
 808      *  may be ignored if the rules have a single offset for all instants
 809      * @return the standard offset, not null




 453         }
 454         ZoneOffset[] savOffsets = new ZoneOffset[savSize + 1];
 455         for (int i = 0; i < savOffsets.length; i++) {
 456             savOffsets[i] = Ser.readOffset(in);
 457         }
 458         int ruleSize = in.readByte();
 459         ZoneOffsetTransitionRule[] rules = (ruleSize == 0) ?
 460             EMPTY_LASTRULES : new ZoneOffsetTransitionRule[ruleSize];
 461         for (int i = 0; i < ruleSize; i++) {
 462             rules[i] = ZoneOffsetTransitionRule.readExternal(in);
 463         }
 464         return new ZoneRules(stdTrans, stdOffsets, savTrans, savOffsets, rules);
 465     }
 466 
 467     /**
 468      * Checks of the zone rules are fixed, such that the offset never varies.
 469      *
 470      * @return true if the time-zone is fixed and the offset never changes
 471      */
 472     public boolean isFixedOffset() {
 473         return standardTransitions.length == 0 && savingsInstantTransitions.length == 0;
 474     }
 475 
 476     /**
 477      * Gets the offset applicable at the specified instant in these rules.
 478      * <p>
 479      * The mapping from an instant to an offset is simple, there is only
 480      * one valid offset for each instant.
 481      * This method returns that offset.
 482      *
 483      * @param instant  the instant to find the offset for, not null, but null
 484      *  may be ignored if the rules have a single offset for all instants
 485      * @return the offset, not null
 486      */
 487     public ZoneOffset getOffset(Instant instant) {
 488         if (isFixedOffset()) {
 489             return standardOffsets[0];
 490         }
 491         long epochSec = instant.getEpochSecond();
 492         // check if using last rules
 493         if (lastRules.length > 0 &&
 494                 savingsInstantTransitions.length > 0 &&
 495                 epochSec > savingsInstantTransitions[savingsInstantTransitions.length - 1]) {
 496             int year = findYear(epochSec, wallOffsets[wallOffsets.length - 1]);
 497             ZoneOffsetTransition[] transArray = findTransitionArray(year);
 498             ZoneOffsetTransition trans = null;
 499             for (int i = 0; i < transArray.length; i++) {
 500                 trans = transArray[i];
 501                 if (epochSec < trans.toEpochSecond()) {
 502                     return trans.getOffsetBefore();
 503                 }
 504             }
 505             return trans.getOffsetAfter();
 506         }
 507 
 508         // using historic rules
 509         int index  = Arrays.binarySearch(savingsInstantTransitions, epochSec);
 510         if (index < 0) {
 511             // switch negative insert position to start of matched range
 512             index = -index - 2;
 513         }
 514         return wallOffsets[index + 1];


 624      * <pre>
 625      *  ZoneOffsetTransition trans = rules.getTransition(localDT);
 626      *  if (trans != null) {
 627      *    // Gap or Overlap: determine what to do from transition
 628      *  } else {
 629      *    // Normal case: only one valid offset
 630      *    zoneOffset = rule.getOffset(localDT);
 631      *  }
 632      * </pre>
 633      *
 634      * @param localDateTime  the local date-time to query for offset transition, not null, but null
 635      *  may be ignored if the rules have a single offset for all instants
 636      * @return the offset transition, null if the local date-time is not in transition
 637      */
 638     public ZoneOffsetTransition getTransition(LocalDateTime localDateTime) {
 639         Object info = getOffsetInfo(localDateTime);
 640         return (info instanceof ZoneOffsetTransition ? (ZoneOffsetTransition) info : null);
 641     }
 642 
 643     private Object getOffsetInfo(LocalDateTime dt) {
 644         if (isFixedOffset()) {
 645             return standardOffsets[0];
 646         }
 647         // check if using last rules
 648         if (lastRules.length > 0 &&
 649                 savingsInstantTransitions.length > 0 &&
 650                 dt.isAfter(savingsLocalTransitions[savingsLocalTransitions.length - 1])) {
 651             ZoneOffsetTransition[] transArray = findTransitionArray(dt.getYear());
 652             Object info = null;
 653             for (ZoneOffsetTransition trans : transArray) {
 654                 info = findOffsetInfo(dt, trans);
 655                 if (info instanceof ZoneOffsetTransition || info.equals(trans.getOffsetBefore())) {
 656                     return info;
 657                 }
 658             }
 659             return info;
 660         }
 661 
 662         // using historic rules
 663         int index  = Arrays.binarySearch(savingsLocalTransitions, dt);
 664         if (index == -1) {
 665             // before first transition
 666             return wallOffsets[0];
 667         }
 668         if (index < 0) {
 669             // switch negative insert position to start of matched range


 741         }
 742         if (year < LAST_CACHED_YEAR) {
 743             lastRulesCache.putIfAbsent(yearObj, transArray);
 744         }
 745         return transArray;
 746     }
 747 
 748     /**
 749      * Gets the standard offset for the specified instant in this zone.
 750      * <p>
 751      * This provides access to historic information on how the standard offset
 752      * has changed over time.
 753      * The standard offset is the offset before any daylight saving time is applied.
 754      * This is typically the offset applicable during winter.
 755      *
 756      * @param instant  the instant to find the offset information for, not null, but null
 757      *  may be ignored if the rules have a single offset for all instants
 758      * @return the standard offset, not null
 759      */
 760     public ZoneOffset getStandardOffset(Instant instant) {
 761         if (isFixedOffset()) {
 762             return standardOffsets[0];
 763         }
 764         long epochSec = instant.getEpochSecond();
 765         int index  = Arrays.binarySearch(standardTransitions, epochSec);
 766         if (index < 0) {
 767             // switch negative insert position to start of matched range
 768             index = -index - 2;
 769         }
 770         return standardOffsets[index + 1];
 771     }
 772 
 773     /**
 774      * Gets the amount of daylight savings in use for the specified instant in this zone.
 775      * <p>
 776      * This provides access to historic information on how the amount of daylight
 777      * savings has changed over time.
 778      * This is the difference between the standard offset and the actual offset.
 779      * Typically the amount is zero during winter and one hour during summer.
 780      * Time-zones are second-based, so the nanosecond part of the duration will be zero.
 781      * <p>
 782      * This default implementation calculates the duration from the
 783      * {@link #getOffset(java.time.Instant) actual} and
 784      * {@link #getStandardOffset(java.time.Instant) standard} offsets.
 785      *
 786      * @param instant  the instant to find the daylight savings for, not null, but null
 787      *  may be ignored if the rules have a single offset for all instants
 788      * @return the difference between the standard and actual offset, not null
 789      */
 790     public Duration getDaylightSavings(Instant instant) {
 791         if (isFixedOffset()) {
 792             return Duration.ZERO;
 793         }
 794         ZoneOffset standardOffset = getStandardOffset(instant);
 795         ZoneOffset actualOffset = getOffset(instant);
 796         return Duration.ofSeconds(actualOffset.getTotalSeconds() - standardOffset.getTotalSeconds());
 797     }
 798 
 799     /**
 800      * Checks if the specified instant is in daylight savings.
 801      * <p>
 802      * This checks if the standard offset and the actual offset are the same
 803      * for the specified instant.
 804      * If they are not, it is assumed that daylight savings is in operation.
 805      * <p>
 806      * This default implementation compares the {@link #getOffset(java.time.Instant) actual}
 807      * and {@link #getStandardOffset(java.time.Instant) standard} offsets.
 808      *
 809      * @param instant  the instant to find the offset information for, not null, but null
 810      *  may be ignored if the rules have a single offset for all instants
 811      * @return the standard offset, not null


< prev index next >