From 1e7f4778395047cd9354e3e90c297c6d1a565f94 Mon Sep 17 00:00:00 2001 From: Valentin Udaltsov Date: Fri, 3 Apr 2026 00:04:59 +0300 Subject: [PATCH] Split duration to multiple classes --- .env | 2 +- .php-cs-fixer.dist.php | 6 +- composer.json | 5 +- src/Duration/Microseconds.php | 18 +++++ src/Duration/Milliseconds.php | 18 +++++ src/Duration/Nanoseconds.php | 126 ++++++++++++++++++++++++++++++++++ src/Duration/toInt.php | 29 ++++++++ 7 files changed, 198 insertions(+), 6 deletions(-) create mode 100644 src/Duration/Microseconds.php create mode 100644 src/Duration/Milliseconds.php create mode 100644 src/Duration/Nanoseconds.php create mode 100644 src/Duration/toInt.php diff --git a/.env b/.env index bc024b6..7cf1cee 100644 --- a/.env +++ b/.env @@ -1,3 +1,3 @@ # Put env variables defaults here # Override locally in gitignored .env.local -PHP_IMAGE_VERSION=8.3 +PHP_IMAGE_VERSION=8.4 diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php index e9c9810..c4440e0 100644 --- a/.php-cs-fixer.dist.php +++ b/.php-cs-fixer.dist.php @@ -7,7 +7,7 @@ use PhpCsFixer\Runner\Parallel\ParallelConfigFactory; use PHPyh\CodingStandard\PhpCsFixerCodingStandard; -$config = (new Config()) +$config = new Config() ->setFinder( Finder::create() ->in(__DIR__ . '/src') @@ -19,8 +19,8 @@ ->setParallelConfig(ParallelConfigFactory::detect()) ->setCacheFile(__DIR__ . '/var/' . basename(__FILE__) . '.cache'); -(new PhpCsFixerCodingStandard())->applyTo($config, [ - // 'rule' => ['overridden' => 'config'], +new PhpCsFixerCodingStandard()->applyTo($config, [ + 'final_class' => false, ]); return $config; diff --git a/composer.json b/composer.json index b7330ef..7f8df00 100644 --- a/composer.json +++ b/composer.json @@ -14,7 +14,7 @@ } ], "require": { - "php-64bit": "^8.3" + "php-64bit": "^8.4" }, "require-dev": { "phpunit/phpunit": "^12.1.4", @@ -25,6 +25,7 @@ "Thesis\\": "src/" }, "files": [ + "src/Duration/toInt.php", "src/Time/TimeSpan.php", "src/TimeSpan/Internal/calculateFormatReplacements.php", "src/TimeSpan/Internal/isCastableToInt.php" @@ -32,7 +33,7 @@ }, "autoload-dev": { "psr-4": { - "Thesis\\": "tests/" + "Thesis\\Time\\": "tests/" } }, "config": { diff --git a/src/Duration/Microseconds.php b/src/Duration/Microseconds.php new file mode 100644 index 0000000..7af01ed --- /dev/null +++ b/src/Duration/Microseconds.php @@ -0,0 +1,18 @@ +nanoseconds = toInt($nanoseconds, $roundingMode); + } + + final public function abs(): static + { + if ($this->nanoseconds >= 0) { + return $this; + } + + return new static(-$this->nanoseconds); + } + + final public function negated(): static + { + return new static(-$this->nanoseconds); + } + + final public function toMicroseconds(?\RoundingMode $roundingMode = null): Microseconds + { + if ($this instanceof Microseconds) { + return $this; + } + + return new Microseconds($this->nanoseconds / Unit::MICROSECONDS, $roundingMode); + } + + final public function toMilliseconds(?\RoundingMode $roundingMode = null): Milliseconds + { + if ($this instanceof Milliseconds) { + return $this; + } + + return new Milliseconds($this->nanoseconds / Unit::MILLISECONDS, $roundingMode); + } + + final public function totalNanoseconds(): int + { + return $this->nanoseconds; + } + + final public function totalMicroseconds(\RoundingMode $roundingMode = \RoundingMode::HalfAwayFromZero): int + { + return (int) round($this->nanoseconds / Unit::MICROSECONDS, mode: $roundingMode); + } + + final public function totalMilliseconds(\RoundingMode $roundingMode = \RoundingMode::HalfAwayFromZero): int + { + return (int) round($this->nanoseconds / Unit::MILLISECONDS, mode: $roundingMode); + } + + /** + * @template T of self + * @param T $duration + * @return ($duration is static ? static : T) + */ + final public function add(self $duration): self + { + $sum = $this->nanoseconds + $duration->nanoseconds; + + if ($duration instanceof $this) { + return $this->with($sum); + } + + return $duration->with($sum); + } + + /** + * @template T of self + * @param T $duration + * @return ($duration is static ? static : T) + */ + final public function sub(self $duration): self + { + $diff = $this->nanoseconds - $duration->nanoseconds; + + if ($this instanceof $duration) { + return $duration->with($diff); + } + + return $this->with($diff); + } + + /** + * @return ($times is int ? static : self) + */ + final public function mul(int|float $times): self + { + $product = $this->nanoseconds * $times; + + if (\is_int($times)) { + return $this->with($product); + } + + return new self($this->nanoseconds * $times); + } + + final public function div(int|float $factor): self + { + return new self($this->nanoseconds / $factor); + } + + private function with(int|float $nanoseconds): static + { + $copy = clone $this; + $copy->nanoseconds = toInt($nanoseconds, \RoundingMode::HalfAwayFromZero); + + return $copy; + } +} diff --git a/src/Duration/toInt.php b/src/Duration/toInt.php new file mode 100644 index 0000000..ac2be22 --- /dev/null +++ b/src/Duration/toInt.php @@ -0,0 +1,29 @@ += PHP_INT_MIN && $value < PHP_INT_MAX)) { + throw new \OverflowException(); + } + + if (fmod($value, 1.0) !== 0.0) { + if ($roundingMode === null) { + throw new \LogicException('Rounding mode required'); + } + + $value = round($value, mode: $roundingMode); + } + + return (int) $value; +}