= 0); \assert($nanoseconds >= 0); \assert($nanoseconds < 1_000_000_000); } /** * Create a duration representing $seconds seconds and $nanoseconds nanoseconds. Neither parameter * may be negative. $nanoseconds must be less than 1_000_000_000 (the number of nanoseconds in a * second). * * This contructor creates a Duration from its “atomic” components. */ public static function fromSeconds(int $seconds, int $nanoseconds = 0): self { if ($seconds < 0) { throw new \ValueError('$seconds must not be negative'); } if ($nanoseconds < 0 || $nanoseconds >= 1_000_000_000) { throw new \ValueError('$nanoseconds must be between 0 and 999_999_999'); } return new self($seconds, $nanoseconds, false); } /** * Create a duration representing $nanoseconds nano-seconds. $nanoseconds must not be negative. */ public static function fromNanoseconds(int $nanoseconds): self { $seconds = \intdiv($nanoseconds, 1_000_000_000); $nanoseconds = $nanoseconds % 1_000_000_000; return self::fromSeconds($seconds, $nanoseconds); } /** * Create a duration representing $microseconds micro-seconds. $microseconds must not be negative. */ public static function fromMicroseconds(int $microseconds): self { return self::fromNanoseconds($microseconds * 1_000); } /** * Create a duration representing $milliseconds milli-seconds. $milliseconds must not be negative. */ public static function fromMilliseconds(int $milliseconds): self { return self::fromMicroseconds($milliseconds * 1_000); } /** * Create a duration representing $minutes minutes. $minutes must not be negative. */ public static function fromMinutes(int $minutes): self { return self::fromSeconds($minutes * 60); } /** * Create a duration representing $hours hours. $hours must not be negative. */ public static function fromHours(int $hours): self { return self::fromMinutes($hours * 60); } /** * Parse a ISO-8601 period. ISO-8601 periods with a date component will be rejected. * The biggest allowed component is H. */ public static function fromIso8601String(string $specification): self { /* Omitted */ } /** * Negates the duration. * * @return self -$this */ public function negate(): self { return clone($this, ['negative' => !$this->negative]); } /** * Add the given duration to the duration. * * @return self $this + $duration */ public function add(self $duration): self { /* (+x) + (-y) == (+x) - (+y) */ if (!$this->negative && $duration->negative) { return $this->sub($duration->negate()); } /* (-x) + (+y) == (+y) - (+x) */ if ($this->negative && !$duration->negative) { return $duration->sub($this->negate()); } /* (-x) + (-y) = -((+x) + (+y)) */ if ($this->negative && $duration->negative) { return $this->negate()->add($duration->negate())->negate(); } \assert(!$this->negative); \assert(!$duration->negative); $seconds = $this->seconds + $duration->seconds; $nanoseconds = $this->nanoseconds + $duration->nanoseconds; $seconds += \intdiv($nanoseconds, 1_000_000_000); $nanoseconds = $nanoseconds % 1_000_000_000; return self::fromSeconds($seconds, $nanoseconds); } /** * Subtract the given duration from the duration. * * @return self $this - $duration */ public function sub(self $duration): self { /* (+x) - (-y) == (+x) + (+y) */ if (!$this->negative && $duration->negative) { return $this->add($duration->negate()); } /* (-x) - (+y) == -((+x) + (+y)) */ if ($this->negative && !$duration->negative) { return $this->negate()->add($duration)->negate(); } /* (-x) - (-y) == (-x) + (+y) */ if ($this->negative && $duration->negative) { return $this->add($duration->negate()); } \assert(!$this->negative); \assert(!$duration->negative); if (self::compare($this, $duration) >= 0) { $seconds = $this->seconds - $duration->seconds; $nanoseconds = $this->nanoseconds - $duration->nanoseconds; if ($nanoseconds < 0) { $nanoseconds += 1_000_000_000; $seconds--; } return self::fromSeconds($seconds, $nanoseconds); } else { /* (+x) - (+y) = -((+y) - (+x)) */ return $duration->sub($this)->negate(); } } /** * Multiply the length of the duration by the given factor: * * @return self $this * $factor */ public function multiplyBy(int $factor): self { $seconds = $this->seconds * $factor; $nanoseconds = $this->nanoseconds * $factor; $seconds += \intdiv($nanoseconds, 1_000_000_000); $nanoseconds = $nanoseconds % 1_000_000_000; return clone($this, ['seconds' => $seconds, 'nanoseconds' => $nanoseconds]); } /** * Divide the length of the duration by the given divisor. * * Fractional nanoseconds will be truncated. * * @return self $this / $factor */ public function divideBy(int $divisor): self { $seconds = \intdiv($this->seconds, $divisor); $nanoseconds = $this->nanoseconds + (($this->seconds % $divisor) * 1_000_000_000); $nanoseconds = \intdiv($nanoseconds, $divisor); return clone($this, ['seconds' => $seconds, 'nanoseconds' => $nanoseconds]); } /** * Returns -1, 0, 1 if $a is less than, equal to, or greater than $b respectively. */ public static function compare(self $a, self $b): int { if ($a->negative && !$b->negative) { return -1; } if (!$a->negative && $b->negative) { return 1; } if ($a->negative && $b->negative) { return - ($a->seconds <=> $b->seconds) ?: - ($a->nanoseconds <=> $b->nanoseconds); } if (!$a->negative && !$b->negative) { return ($a->seconds <=> $b->seconds) ?: ($a->nanoseconds <=> $b->nanoseconds); } throw new \Error('unreachable'); } }