Skip to content

Commit 3931abb

Browse files
authored
Simplify out of bound check (#22)
1 parent a74c554 commit 3931abb

2 files changed

Lines changed: 19 additions & 11 deletions

File tree

src/TimeSpan.php

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -48,25 +48,20 @@ public static function fromNanoseconds(int|float $nanoseconds): self
4848
return new self($nanoseconds);
4949
}
5050

51-
$nanoseconds = \sprintf('%.0f', round($nanoseconds));
51+
$nanoseconds = round($nanoseconds);
5252

53-
if ($nanoseconds > 0 && self::comparePositiveNumericStrings($nanoseconds, (string) PHP_INT_MAX) > 0
54-
|| $nanoseconds < 0 && self::compareNegativeNumericStrings($nanoseconds, (string) PHP_INT_MIN) < 0
55-
) {
53+
if (self::isOutOfBounds($nanoseconds)) {
5654
throw new \OutOfBoundsException('The specified time span cannot be expressed as integer nanoseconds due to overflow.');
5755
}
5856

5957
return new self((int) $nanoseconds);
6058
}
6159

62-
private static function comparePositiveNumericStrings(string $a, string $b): int
60+
private static function isOutOfBounds(float $nanoseconds): bool
6361
{
64-
return \strlen($a) <=> \strlen($b) ?: strcmp($a, $b);
65-
}
66-
67-
private static function compareNegativeNumericStrings(string $a, string $b): int
68-
{
69-
return -(\strlen($a) <=> \strlen($b) ?: strcmp($a, $b));
62+
return !is_finite($nanoseconds)
63+
|| $nanoseconds >= ($bound = 2 ** 63)
64+
|| $nanoseconds < -$bound;
7065
}
7166

7267
public static function fromMicroseconds(int|float $microseconds): self

tests/TimeSpanTest.php

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,7 @@ public function testConstructorWithoutArgs(): void
208208
#[TestWith([100.999_99, 101])]
209209
#[TestWith([PHP_INT_MAX, PHP_INT_MAX])]
210210
#[TestWith([PHP_INT_MIN, PHP_INT_MIN])]
211+
#[TestWith([PHP_INT_MIN - 1_024, PHP_INT_MIN])]
211212
#[TestWith([9_223_372_036_854_775_000.0, 9_223_372_036_854_774_784])]
212213
#[TestWith([-9_223_372_036_854_775_000.0, -9_223_372_036_854_774_784])]
213214
public function testFromNanoseconds(int|float $nanoseconds, int $expected): void
@@ -322,6 +323,8 @@ public function testFromDaysPHPSince84(float $days, int $expected): void
322323
#[TestWith([106_751.991_2])]
323324
#[TestWith([-106_752])]
324325
#[TestWith([-106_751.991_2])]
326+
#[TestWith([NAN])]
327+
#[TestWith([INF])]
325328
public function testFromDaysThrowsOutOfBounds(int|float $days): void
326329
{
327330
$this->expectException(\OutOfBoundsException::class);
@@ -330,6 +333,16 @@ public function testFromDaysThrowsOutOfBounds(int|float $days): void
330333
TimeSpan::fromDays($days);
331334
}
332335

336+
#[TestWith([PHP_INT_MAX + 1])]
337+
#[TestWith([PHP_INT_MIN - 1_025])]
338+
public function testFromNanosecondsThrowsOutOfBounds(float $nanoseconds): void
339+
{
340+
$this->expectException(\OutOfBoundsException::class);
341+
$this->expectExceptionMessage('The specified time span cannot be expressed as integer nanoseconds due to overflow.');
342+
343+
TimeSpan::fromNanoseconds($nanoseconds);
344+
}
345+
333346
#[TestWith([100_000, 100.0, 100])]
334347
#[TestWith([100_100, 100.1, 100])]
335348
#[TestWith([100_500, 100.5, 101])]

0 commit comments

Comments
 (0)