예제 #1
0
 /**
  * Completes the build converting the builder to a set of time-zone rules.
  * <p>
  * Calling this method alters the state of the builder.
  * Further rules should not be added to this builder once this method is called.
  *
  * @param string $zoneId the time-zone ID, not null
  * @param array $deduplicateMap a map for deduplicating the values, not null
  * @return ZoneRules the zone rules, not null
  * @throws \LogicException if no windows have been added
  * @throws \LogicException if there is only one rule defined as being forever for any given window
  */
 public function _toRules($zoneId, &$deduplicateMap)
 {
     $this->deduplicateMap = $deduplicateMap;
     if (empty($this->windowList)) {
         throw new \LogicException("No windows have been added to the builder");
     }
     /** @var ZoneOffsetTransition[] $standardTransitionList */
     $standardTransitionList = [];
     /** @var ZoneOffsetTransition[] */
     $transitionList = [];
     /** @var ZoneOffsetTransitionRule[] */
     $lastTransitionRuleList = [];
     // initialize the standard offset calculation
     $firstWindow = $this->windowList[0];
     $loopStandardOffset = $firstWindow->standardOffset;
     $loopSavings = 0;
     if ($firstWindow->fixedSavingAmountSecs !== null) {
         $loopSavings = $firstWindow->fixedSavingAmountSecs;
     }
     /** @var ZoneOffset $firstWallOffset */
     $firstWallOffset = $this->deduplicate(ZoneOffset::ofTotalSeconds($loopStandardOffset->getTotalSeconds() + $loopSavings));
     /** @var LocalDateTime $loopWindowStart */
     $loopWindowStart = $this->deduplicate(LocalDateTime::of(Year::MIN_VALUE, 1, 1, 0, 0));
     $loopWindowOffset = $firstWallOffset;
     // build the windows and rules to interesting data
     foreach ($this->windowList as $window) {
         // tidy the state
         $window->tidy($loopWindowStart->getYear());
         // calculate effective savings at the start of the window
         $effectiveSavings = $window->fixedSavingAmountSecs;
         if ($effectiveSavings === null) {
             // apply rules from this window together with the standard offset and
             // savings from the last window to find the savings amount applicable
             // at start of this window
             $effectiveSavings = 0;
             foreach ($window->ruleList as $rule) {
                 $trans = $rule->toTransition($loopStandardOffset, $loopSavings);
                 if ($trans->toEpochSecond() > $loopWindowStart->toEpochSecond($loopWindowOffset)) {
                     // previous savings amount found, which could be the savings amount at
                     // the instant that the window starts (hence isAfter)
                     break;
                 }
                 $effectiveSavings = $rule->savingAmountSecs;
             }
         }
         // check if standard offset changed, and update it
         if ($loopStandardOffset->equals($window->standardOffset) === false) {
             $standardTransitionList[] = $this->deduplicate(ZoneOffsetTransition::of(LocalDateTime::ofEpochSecond($loopWindowStart->toEpochSecond($loopWindowOffset), 0, $loopStandardOffset), $loopStandardOffset, $window->standardOffset));
             $loopStandardOffset = $this->deduplicate($window->standardOffset);
         }
         // check if the start of the window represents a transition
         $effectiveWallOffset = $this->deduplicate(ZoneOffset::ofTotalSeconds($loopStandardOffset->getTotalSeconds() + $effectiveSavings));
         if ($loopWindowOffset->equals($effectiveWallOffset) === false) {
             $trans = $this->deduplicate(ZoneOffsetTransition::of($loopWindowStart, $loopWindowOffset, $effectiveWallOffset));
             $transitionList[] = $trans;
         }
         $loopSavings = $effectiveSavings;
         // apply rules within the window
         foreach ($window->ruleList as $rule) {
             /** @var ZoneOffsetTransition $trans */
             $trans = $this->deduplicate($rule->toTransition($loopStandardOffset, $loopSavings));
             if ($trans !== null && $trans->toEpochSecond() < $loopWindowStart->toEpochSecond($loopWindowOffset) === false && $trans->toEpochSecond() < $window->createDateTimeEpochSecond($loopSavings) && $trans->getOffsetBefore()->equals($trans->getOffsetAfter()) === false) {
                 $transitionList[] = $trans;
                 $loopSavings = $rule->savingAmountSecs;
             }
         }
         // calculate last rules
         foreach ($window->lastRuleList as $lastRule) {
             $transitionRule = $this->deduplicate($lastRule->toTransitionRule($loopStandardOffset, $loopSavings));
             $lastTransitionRuleList[] = $transitionRule;
             $loopSavings = $lastRule->savingAmountSecs;
         }
         // finally we can calculate the true end of the window, passing it to the next window
         $loopWindowOffset = $this->deduplicate($window->createWallOffset($loopSavings));
         $loopWindowStart = $this->deduplicate(LocalDateTime::ofEpochSecond($window->createDateTimeEpochSecond($loopSavings), 0, $loopWindowOffset));
     }
     return ZoneRules::of($firstWindow->standardOffset, $firstWallOffset, $standardTransitionList, $transitionList, $lastTransitionRuleList);
 }
예제 #2
0
 public function test_of()
 {
     //used for standard offset
     $stdOffset1 = ZoneOffset::UTC();
     $stdOffset2 = ZoneOffset::ofHours(1);
     $time_of_stdOffsetTransition1 = LocalDateTime::of(2013, 1, 5, 1, 0);
     $stdOffsetTransition1 = ZoneOffsetTransition::of($time_of_stdOffsetTransition1, $stdOffset1, $stdOffset2);
     $stdOffsetTransition_list = [];
     $stdOffsetTransition_list[] = $stdOffsetTransition1;
     //used for wall offset
     $wallOffset1 = ZoneOffset::ofHours(2);
     $wallOffset2 = ZoneOffset::ofHours(4);
     $wallOffset3 = ZoneOffset::ofHours(7);
     $time_of_wallOffsetTransition1 = LocalDateTime::of(2013, 2, 5, 1, 0);
     $time_of_wallOffsetTransition2 = LocalDateTime::of(2013, 3, 5, 1, 0);
     $time_of_wallOffsetTransition3 = LocalDateTime::of(2013, 10, 5, 1, 0);
     $wallOffsetTransition1 = ZoneOffsetTransition::of($time_of_wallOffsetTransition1, $wallOffset1, $wallOffset2);
     $wallOffsetTransition2 = ZoneOffsetTransition::of($time_of_wallOffsetTransition2, $wallOffset2, $wallOffset3);
     $wallOffsetTransition3 = ZoneOffsetTransition::of($time_of_wallOffsetTransition3, $wallOffset3, $wallOffset1);
     $wallOffsetTransition_list = [];
     $wallOffsetTransition_list[] = $wallOffsetTransition1;
     $wallOffsetTransition_list[] = $wallOffsetTransition2;
     $wallOffsetTransition_list[] = $wallOffsetTransition3;
     //used for ZoneOffsetTransitionRule
     $ruleOffset = ZoneOffset::ofHours(3);
     $timeDefinition = TimeDefinition::WALL();
     $rule1 = ZoneOffsetTransitionRule::of(Month::FEBRUARY(), 2, DayOfWeek::MONDAY(), LocalTime::of(1, 0), false, $timeDefinition, ZoneOffset::UTC(), ZoneOffset::UTC(), $ruleOffset);
     $rule_list = [];
     $rule_list[] = $rule1;
     //Begin verification
     $zoneRule = ZoneRules::of($stdOffset1, $wallOffset1, $stdOffsetTransition_list, $wallOffsetTransition_list, $rule_list);
     $before_time_of_stdOffsetTransition1 = OffsetDateTime::ofDateTime($time_of_stdOffsetTransition1, $stdOffset1)->minusSeconds(1);
     $after_time_of_stdOffsetTransition1 = OffsetDateTime::ofDateTime($time_of_stdOffsetTransition1, $stdOffset1)->plusSeconds(1);
     $this->assertEquals($zoneRule->getStandardOffset($before_time_of_stdOffsetTransition1->toInstant()), $stdOffset1);
     $this->assertEquals($zoneRule->getStandardOffset($after_time_of_stdOffsetTransition1->toInstant()), $stdOffset2);
     $before_time_of_wallOffsetTransition1 = OffsetDateTime::ofDateTime($time_of_wallOffsetTransition1, $wallOffset1)->minusSeconds(1);
     $after_time_of_wallOffsetTransition1 = OffsetDateTime::ofDateTime($time_of_wallOffsetTransition1, $wallOffset1)->plusSeconds(1);
     $this->assertEquals($zoneRule->nextTransition($before_time_of_wallOffsetTransition1->toInstant()), $wallOffsetTransition1);
     $this->assertEquals($zoneRule->nextTransition($after_time_of_wallOffsetTransition1->toInstant()), $wallOffsetTransition2);
     $before_time_of_wallOffsetTransition2 = OffsetDateTime::ofDateTime($time_of_wallOffsetTransition2, $wallOffset2)->minusSeconds(1);
     $after_time_of_wallOffsetTransition2 = OffsetDateTime::ofDateTime($time_of_wallOffsetTransition2, $wallOffset2)->plusSeconds(1);
     $this->assertEquals($zoneRule->nextTransition($before_time_of_wallOffsetTransition2->toInstant()), $wallOffsetTransition2);
     $this->assertEquals($zoneRule->nextTransition($after_time_of_wallOffsetTransition2->toInstant()), $wallOffsetTransition3);
     $before_time_of_wallOffsetTransition3 = OffsetDateTime::ofDateTime($time_of_wallOffsetTransition3, $wallOffset3)->minusSeconds(1);
     $after_time_of_wallOffsetTransition3 = OffsetDateTime::ofDateTime($time_of_wallOffsetTransition3, $wallOffset3)->plusSeconds(1);
     $this->assertEquals($zoneRule->nextTransition($before_time_of_wallOffsetTransition3->toInstant()), $wallOffsetTransition3);
     $this->assertEquals($zoneRule->nextTransition($after_time_of_wallOffsetTransition3->toInstant()), $rule1->createTransition(2014));
 }