From fd3515c4209b64a9b1302ca8366f7c9be8478708 Mon Sep 17 00:00:00 2001 From: Evgymart Date: Fri, 30 May 2025 18:57:19 +0300 Subject: [PATCH 1/2] #15 Timespan math operations --- src/TimeSpan.php | 20 ++++++++ tests/TimeSpanTest.php | 105 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 125 insertions(+) diff --git a/src/TimeSpan.php b/src/TimeSpan.php index 1db5fc1..0a79865 100644 --- a/src/TimeSpan.php +++ b/src/TimeSpan.php @@ -287,6 +287,26 @@ public function isPositiveOrZero(): bool { return $this->nanoseconds >= 0; } + + public function add(self $timeSpan): self + { + return self::fromNanoseconds($this->nanoseconds + $timeSpan->nanoseconds); + } + + public function sub(self $timeSpan): self + { + return self::fromNanoseconds($this->nanoseconds - $timeSpan->nanoseconds); + } + + public function mul(int|float $times): self + { + return self::fromNanoseconds($this->nanoseconds * $times); + } + + public function div(int|float $factor): self + { + return self::fromNanoseconds($this->nanoseconds / $factor); + } private const array UNITS_MULT_MAP = [ 'd' => self::MULT_DAYS, 'h' => self::MULT_HOURS, diff --git a/tests/TimeSpanTest.php b/tests/TimeSpanTest.php index 0112188..79495c5 100644 --- a/tests/TimeSpanTest.php +++ b/tests/TimeSpanTest.php @@ -529,4 +529,109 @@ public function testIsPositiveOrZero(int $microseconds, bool $expected): void self::assertSame($expected, $actual); } + + #[TestWith([2, 2, 4])] + #[TestWith([250, 250, 500])] + #[TestWith([-250, 250, 0])] + #[TestWith([-250, -250, -500])] + public function testAdd(int $firstDays, int $secondDays, int $sumDays): void + { + $firstSpan = TimeSpan::fromDays($firstDays); + $secondSpan = TimeSpan::fromDays($secondDays); + + $sum = $firstSpan->add($secondSpan); + + self::assertEquals($sumDays, $sum->toDays()); + } + + public function testAddOverflow(): void + { + self::expectException(\OutOfBoundsException::class); + + $tooManyDays = 99999; + $firstSpan = TimeSpan::fromDays($tooManyDays); + $secondSpan = TimeSpan::fromDays($tooManyDays); + + $firstSpan->add($secondSpan); + } + + #[TestWith([4, 2, 2])] + #[TestWith([250, 250, 0])] + #[TestWith([-250, 250, -500])] + #[TestWith([-250, -250, 0])] + public function testSub(int $firstDays, int $secondDays, int $diffDays): void + { + $firstSpan = TimeSpan::fromDays($firstDays); + $secondSpan = TimeSpan::fromDays($secondDays); + + $diff = $firstSpan->sub($secondSpan); + + self::assertEquals($diffDays, $diff->toDays()); + } + + public function testSubOverflow(): void + { + self::expectException(\OutOfBoundsException::class); + + $tooManyDays = 99999; + $zeroSpan = TimeSpan::fromDays(0); + $subSpan = TimeSpan::fromDays($tooManyDays); + + $zeroSpan->sub($subSpan) + ->sub($subSpan); + } + + #[TestWith([2, 2, 4])] + #[TestWith([3, 3, 9])] + #[TestWith([5, 0, 0])] + #[TestWith([10, 0.5, 5])] + public function testMul(int $days, int|float $times, int $daysProduct): void + { + $span = TimeSpan::fromDays($days); + + $product = $span->mul($times); + + self::assertEquals($daysProduct, $product->toDays()); + } + + public function testMulOverflow(): void + { + self::expectException(\OutOfBoundsException::class); + + $tooManyDays = 99999; + $span = TimeSpan::fromDays($tooManyDays); + + $span->mul(2); + } + + #[TestWith([8_640_000_000_000, 1000, 8_640_000_000])] + #[TestWith([1_111_111_111_111, 3, 3_703_703_703_70])] + #[TestWith([1_111_111_111_111, 4, 2_777_777_777_78])] + #[TestWith([8_640_000_00, 0.1, 8_640_000_000])] + public function testDiv(int $nanoseconds, int|float $factor, int $nanosecondsQuotient): void + { + $span = TimeSpan::fromNanoseconds($nanoseconds); + + $quotient = $span->div($factor); + + self::assertEquals($nanosecondsQuotient, $quotient->toNanoseconds()); + } + + public function testDivOverflow(): void + { + self::expectException(\OutOfBoundsException::class); + + $tooManyDays = 99999; + $span = TimeSpan::fromDays($tooManyDays); + + $span->div(0.1); + } + + public function testDivByZero(): void + { + self::expectException(\DivisionByZeroError::class); + + $span = TimeSpan::fromDays(5); + $span->div(0); + } } From ba53dbf7641d635d156baf1b0d6150ca3d831366 Mon Sep 17 00:00:00 2001 From: Evgymart Date: Mon, 2 Jun 2025 14:06:38 +0300 Subject: [PATCH 2/2] Format numbers --- tests/TimeSpanTest.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/TimeSpanTest.php b/tests/TimeSpanTest.php index 79495c5..1d26099 100644 --- a/tests/TimeSpanTest.php +++ b/tests/TimeSpanTest.php @@ -548,7 +548,7 @@ public function testAddOverflow(): void { self::expectException(\OutOfBoundsException::class); - $tooManyDays = 99999; + $tooManyDays = 99_999; $firstSpan = TimeSpan::fromDays($tooManyDays); $secondSpan = TimeSpan::fromDays($tooManyDays); @@ -573,7 +573,7 @@ public function testSubOverflow(): void { self::expectException(\OutOfBoundsException::class); - $tooManyDays = 99999; + $tooManyDays = 99_999; $zeroSpan = TimeSpan::fromDays(0); $subSpan = TimeSpan::fromDays($tooManyDays); @@ -598,7 +598,7 @@ public function testMulOverflow(): void { self::expectException(\OutOfBoundsException::class); - $tooManyDays = 99999; + $tooManyDays = 99_999; $span = TimeSpan::fromDays($tooManyDays); $span->mul(2); @@ -621,7 +621,7 @@ public function testDivOverflow(): void { self::expectException(\OutOfBoundsException::class); - $tooManyDays = 99999; + $tooManyDays = 99_999; $span = TimeSpan::fromDays($tooManyDays); $span->div(0.1);