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)); }
/** * 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); }
/** * Gets the complete list of fully defined transitions. * <p> * The complete set of transitions for this rules instance is defined by this method * and {@link #getTransitionRules()}. This method returns those transitions that have * been fully defined. These are typically historical, but may be in the future. * <p> * The list will be empty for fixed offset rules and for any time-zone where there has * only ever been a single offset. The list will also be empty if the transition rules are unknown. * * @return ZoneOffsetTransition[] an immutable list of fully defined transitions, not null */ public function getTransitions() { $list = []; for ($i = 0; $i < count($this->savingsInstantTransitions); $i++) { $list[] = ZoneOffsetTransition::ofEpoch($this->savingsInstantTransitions[$i], $this->wallOffsets[$i], $this->wallOffsets[$i + 1]); } return $list; }
/** * Creates a transition instance for the specified year. * <p> * Calculations are performed using the ISO-8601 chronology. * * @param int $year the year to create a transition for, not null * @return ZoneOffsetTransition the transition instance, not null */ public function createTransition($year) { if ($this->dom < 0) { $date = LocalDate::ofMonth($year, $this->month, $this->month->length(IsoChronology::INSTANCE()->isLeapYear($year)) + 1 + $this->dom); if ($this->dow !== null) { $date = $date->adjust(TemporalAdjusters::previousOrSame($this->dow)); } } else { $date = LocalDate::ofMonth($year, $this->month, $this->dom); if ($this->dow !== null) { $date = $date->adjust(TemporalAdjusters::nextOrSame($this->dow)); } } if ($this->timeEndOfDay) { $date = $date->plusDays(1); } $localDT = LocalDateTime::ofDateAndTime($date, $this->time); $transition = $this->timeDefinition->createDateTime($localDT, $this->standardOffset, $this->offsetBefore); return ZoneOffsetTransition::of($transition, $this->offsetBefore, $this->offsetAfter); }
public function test_createTransition_fixedDate() { $test = ZoneOffsetTransitionRule::of(Month::MARCH(), 20, null, self::TIME_0100(), false, TimeDefinition::STANDARD(), self::OFFSET_0200(), self::OFFSET_0200(), self::OFFSET_0300()); $trans = ZoneOffsetTransition::of(LocalDateTime::ofMonth(2000, Month::MARCH(), 20, 1, 0), self::OFFSET_0200(), self::OFFSET_0300()); $this->assertEquals($test->createTransition(2000), $trans); }
/** * Compares this transition to another based on the transition instant. * <p> * This compares the instants of each transition. * The offsets are ignored, making this order inconsistent with equals. * * @param ZoneOffsetTransition $transition the transition to compare to, not null * @return bool the comparator value, negative if less, positive if greater */ public function compareTo(ZoneOffsetTransition $transition) { return $this->getInstant()->compareTo($transition->getInstant()); }
public function test_toString_overlap() { $ldt = LocalDateTime::of(2010, 10, 31, 1, 0); $test = ZoneOffsetTransition::of($ldt, self::OFFSET_0300(), self::OFFSET_0200()); $this->assertEquals("Transition[Overlap at 2010-10-31T01:00+03:00 to +02:00]", $test->__toString()); }