public function testMinDateEpochSec() { $offset = ZoneOffset::ofTotalSeconds(0); $seconds = LocalDateTime::MIN()->toEpochSecond($offset); $new = LocalDateTime::ofEpochSecond($seconds, 0, $offset); $this->assertEquals(LocalDateTime::MIN(), $new); }
/** * Obtains an instance of {@code OffsetDateTime} from an {@code Instant} and zone ID. * <p> * This creates an offset date-time with the same instant as that specified. * Finding the offset from UTC/Greenwich is simple as there is only one valid * offset for each instant. * * @param Instant $instant the instant to create the date-time from, not null * @param ZoneId $zone the time-zone, which may be an offset, not null * @return OffsetDateTime the offset date-time, not null * @throws DateTimeException if the result exceeds the supported range */ public static function ofInstant(Instant $instant, ZoneId $zone) { $rules = $zone->getRules(); $offset = $rules->getOffset($instant); $ldt = LocalDateTime::ofEpochSecond($instant->getEpochSecond(), $instant->getNano(), $offset); return new OffsetDateTime($ldt, $offset); }
/** * 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); }
public function test_factory_ofEpochSecond_longOffset_nullOffset() { TestHelper::assertNullException($this, function () { LocalDateTime::ofEpochSecond(0, 500, null); }); }
/** * Obtains an instance from an instant using the specified time-zone. * * @param Chronology $chrono the chronology, not null * @param Instant $instant the instant, not null * @param ZoneId $zone the zone identifier, not null * @return ChronoZonedDateTimeImpl the zoned date-time, not null */ static function ofInstant(Chronology $chrono, Instant $instant, ZoneId $zone) { $rules = $zone->getRules(); $offset = $rules->getOffset($instant); // TODO Objects.requireNonNull(offset, "offset"); // protect against bad ZoneRules $ldt = LocalDateTime::ofEpochSecond($instant->getEpochSecond(), $instant->getNano(), $offset); $cldt = $chrono->localDateTime($ldt); return new ChronoZonedDateTimeImpl($cldt, $offset, $zone); }
/** * Creates an instance from epoch-second and offsets. * * @param int $epochSecond the transition epoch-second * @param ZoneOffset $offsetBefore the offset before the transition, not null * @param ZoneOffset $offsetAfter the offset at and after the transition, not null * @return ZoneOffsetTransition */ public static function ofEpoch($epochSecond, ZoneOffset $offsetBefore, ZoneOffset $offsetAfter) { return self::of(LocalDateTime::ofEpochSecond($epochSecond, 0, $offsetBefore), $offsetBefore, $offsetAfter); }
public function format(DateTimePrintContext $context, &$buf) { // use INSTANT_SECONDS, thus this code is not bound by Instant.MAX $inSecs = $context->getValueField(ChronoField::INSTANT_SECONDS()); $inNanos = null; if ($context->getTemporal()->isSupported(ChronoField::NANO_OF_SECOND())) { $inNanos = $context->getTemporal()->getLong(ChronoField::NANO_OF_SECOND()); } if ($inSecs === null) { return false; } $inSec = $inSecs; $inNano = ChronoField::NANO_OF_SECOND()->checkValidIntValue($inNanos !== null ? $inNanos : 0); // format mostly using LocalDateTime.toString if ($inSec >= -self::SECONDS_0000_TO_1970) { // current era $zeroSecs = $inSec - self::SECONDS_PER_10000_YEARS + self::SECONDS_0000_TO_1970; $hi = Math::floorDiv($zeroSecs, self::SECONDS_PER_10000_YEARS) + 1; $lo = Math::floorMod($zeroSecs, self::SECONDS_PER_10000_YEARS); $ldt = LocalDateTime::ofEpochSecond($lo - self::SECONDS_0000_TO_1970, 0, ZoneOffset::UTC()); if ($hi > 0) { $buf .= '+' . $hi; } $buf .= $ldt; if ($ldt->getSecond() === 0) { $buf .= ":00"; } } else { // before current era $zeroSecs = $inSec + self::SECONDS_0000_TO_1970; $hi = Math::div($zeroSecs, self::SECONDS_PER_10000_YEARS); $lo = $zeroSecs % self::SECONDS_PER_10000_YEARS; $ldt = LocalDateTime::ofEpochSecond($lo - self::SECONDS_0000_TO_1970, 0, ZoneOffset::UTC()); $pos = strlen($buf); $buf .= $ldt; if ($ldt->getSecond() === 0) { $buf .= ":00"; } if ($hi < 0) { if ($ldt->getYear() === -10000) { $buf = substr_replace($buf, $hi - 1, $pos, 2); } else { if ($lo === 0) { $buf = substr_replace($buf, $hi, $pos, 0); } else { $buf = substr_replace($buf, Math::abs($hi), $pos + 1, 0); } } } } // add fraction if ($this->fractionalDigits < 0 && $inNano > 0 || $this->fractionalDigits > 0) { $buf .= '.'; $div = 100000000; for ($i = 0; $this->fractionalDigits === -1 && $inNano > 0 || $this->fractionalDigits === -2 && ($inNano > 0 || $i % 3 !== 0) || $i < $this->fractionalDigits; $i++) { $digit = Math::div($inNano, $div); $buf .= $digit; $inNano = $inNano - $digit * $div; $div = Math::div($div, 10); } } $buf .= 'Z'; return true; }
/** * Obtains an instance of {@code ZonedDateTime} using seconds from the * epoch of 1970-01-01T00:00:00Z. * * @param int $epochSecond the number of seconds from the epoch of 1970-01-01T00:00:00Z * @param int $nanoOfSecond the nanosecond within the second, from 0 to 999,999,999 * @param ZoneId $zone the time-zone, not null * @return ZonedDateTime the zoned date-time, not null * @throws DateTimeException if the result exceeds the supported range */ private static function create($epochSecond, $nanoOfSecond, ZoneId $zone) { $rules = $zone->getRules(); $instant = Instant::ofEpochSecond($epochSecond, $nanoOfSecond); // TODO: rules should be queryable by epochSeconds $offset = $rules->getOffset($instant); $ldt = LocalDateTime::ofEpochSecond($epochSecond, $nanoOfSecond, $offset); return new ZonedDateTime($ldt, $offset, $zone); }
public function test_compareTo_sameInstant() { $a = ZoneOffsetTransition::of(LocalDateTime::ofEpochSecond(23875287, 0, self::OFFSET_0200()), self::OFFSET_0200(), self::OFFSET_0300()); $b = ZoneOffsetTransition::of(LocalDateTime::ofEpochSecond(23875287, 0, self::OFFSET_0300()), self::OFFSET_0300(), self::OFFSET_0200()); $c = ZoneOffsetTransition::of(LocalDateTime::ofEpochSecond(23875287, 0, self::OFFSET_0100()), self::OFFSET_0100(), self::OFFSET_0400()); $this->assertEquals($a->compareTo($a) == 0, true); $this->assertEquals($a->compareTo($b) == 0, true); $this->assertEquals($a->compareTo($c) == 0, true); $this->assertEquals($b->compareTo($a) == 0, true); $this->assertEquals($b->compareTo($b) == 0, true); $this->assertEquals($b->compareTo($c) == 0, true); $this->assertEquals($c->compareTo($a) == 0, true); $this->assertEquals($c->compareTo($b) == 0, true); $this->assertEquals($c->compareTo($c) == 0, true); }