< prev index next >

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

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


 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) {


 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];


 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 standardOffsets[0] == wallOffsets[0] &&
 474                 standardTransitions.length == 0 &&
 475                 savingsInstantTransitions.length == 0 &&
 476                 lastRules.length == 0;
 477     }
 478 
 479     /**
 480      * Gets the offset applicable at the specified instant in these rules.
 481      * <p>
 482      * The mapping from an instant to an offset is simple, there is only
 483      * one valid offset for each instant.
 484      * This method returns that offset.
 485      *
 486      * @param instant  the instant to find the offset for, not null, but null
 487      *  may be ignored if the rules have a single offset for all instants
 488      * @return the offset, not null
 489      */
 490     public ZoneOffset getOffset(Instant instant) {
 491         if (savingsInstantTransitions.length == 0) {
 492             return wallOffsets[0];
 493         }
 494         long epochSec = instant.getEpochSecond();
 495         // check if using last rules
 496         if (lastRules.length > 0 &&
 497                 epochSec > savingsInstantTransitions[savingsInstantTransitions.length - 1]) {
 498             int year = findYear(epochSec, wallOffsets[wallOffsets.length - 1]);
 499             ZoneOffsetTransition[] transArray = findTransitionArray(year);
 500             ZoneOffsetTransition trans = null;
 501             for (int i = 0; i < transArray.length; i++) {
 502                 trans = transArray[i];
 503                 if (epochSec < trans.toEpochSecond()) {
 504                     return trans.getOffsetBefore();
 505                 }
 506             }
 507             return trans.getOffsetAfter();
 508         }
 509 
 510         // using historic rules
 511         int index  = Arrays.binarySearch(savingsInstantTransitions, epochSec);
 512         if (index < 0) {


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


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


< prev index next >