Skip to content

Commit a502003

Browse files
committed
Simplify out of bound check
1 parent fb001b2 commit a502003

2 files changed

Lines changed: 27 additions & 28 deletions

File tree

src/TimeSpan.php

Lines changed: 9 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -93,41 +93,22 @@ private static function fromX(int|float $value, int $multiplier): self
9393
return new self($nanoseconds);
9494
}
9595

96-
if ($value >= 0) {
97-
/** @var non-empty-string */
98-
static $max = (string) PHP_INT_MAX;
99-
/**
100-
* @var non-empty-string
101-
* @psalm-suppress UnusedFunctionCall
102-
*/
103-
static $positiveFormat = \sprintf("%%'0%s.0f", \strlen($max));
104-
105-
$nanoseconds = \sprintf($positiveFormat, round($value * $multiplier));
106-
107-
if (\strlen($nanoseconds) > \strlen($max) || strcmp($nanoseconds, $max) > 0) {
108-
throw new \OutOfBoundsException('The specified time span cannot be expressed as integer nanoseconds due to overflow.');
109-
}
110-
111-
return new self((int) $nanoseconds);
112-
}
113-
114-
/** @var non-empty-string */
115-
static $min = (string) PHP_INT_MIN;
116-
/**
117-
* @var non-empty-string
118-
* @psalm-suppress UnusedFunctionCall
119-
*/
120-
static $negativeFormat = \sprintf("%%'0%s.0f", \strlen($min));
96+
$nanoseconds = \sprintf('%.0f', round($value * $multiplier));
12197

122-
$nanoseconds = \sprintf($negativeFormat, round($value * $multiplier));
123-
124-
if (\strlen($nanoseconds) > \strlen($min) || strcmp($nanoseconds, $min) > 0) {
98+
if ($value > 0 && self::compareUnsignedNumericStrings($nanoseconds, (string) PHP_INT_MAX) > 0
99+
|| $value < 0 && self::compareUnsignedNumericStrings($nanoseconds, (string) PHP_INT_MIN) > 0
100+
) {
125101
throw new \OutOfBoundsException('The specified time span cannot be expressed as integer nanoseconds due to overflow.');
126102
}
127103

128104
return new self((int) $nanoseconds);
129105
}
130106

107+
private static function compareUnsignedNumericStrings(string $a, string $b): int
108+
{
109+
return \strlen($a) <=> \strlen($b) ?: strcmp($a, $b);
110+
}
111+
131112
public static function fromInterval(\DateInterval $interval): self
132113
{
133114
if ($interval->m !== 0 || $interval->y !== 0) {

tests/TimeSpanTest.php

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,10 @@ public function testItThrowsForInvalidFormatWithRepeatingPlaceholder(): void
7373
/**
7474
* @param array{days?: float|int, hours?: float|int, minutes?: float|int, seconds?: float|int, milliseconds?: float|int, microseconds?: float|int} $args
7575
*/
76+
#[TestWith([
77+
[],
78+
0,
79+
])]
7680
#[TestWith([
7781
['seconds' => 987, 'milliseconds' => 654, 'microseconds' => 321, 'nanoseconds' => 123],
7882
987_654_321_123,
@@ -175,6 +179,8 @@ public function testItThrowsForDateTimeInterfaceDiffInterval(): void
175179
TimeSpan::fromInterval($interval);
176180
}
177181

182+
#[TestWith([0, 0])]
183+
#[TestWith([0.0, 0])]
178184
#[TestWith([100, 100])]
179185
#[TestWith([100.1, 100])]
180186
#[TestWith([100.5, 101])]
@@ -190,6 +196,8 @@ public function testFromNanoseconds(int|float $nanoseconds, int $expected): void
190196
self::assertSame($expected, $span->toNanoseconds());
191197
}
192198

199+
#[TestWith([0, 0])]
200+
#[TestWith([0.0, 0])]
193201
#[TestWith([100, 100])]
194202
#[TestWith([100.1, 100])]
195203
#[TestWith([100.5, 101])]
@@ -201,6 +209,8 @@ public function testFromMicroseconds(int|float $microseconds, int $expected): vo
201209
self::assertSame($expected, $span->toMicroseconds());
202210
}
203211

212+
#[TestWith([0, 0])]
213+
#[TestWith([0.0, 0])]
204214
#[TestWith([100, 100_000])]
205215
#[TestWith([100.1, 100_100])]
206216
#[TestWith([100.5, 100_500])]
@@ -212,6 +222,8 @@ public function testFromMilliseconds(int|float $milliseconds, int $expected): vo
212222
self::assertSame($expected, $span->toMicroseconds());
213223
}
214224

225+
#[TestWith([0, 0])]
226+
#[TestWith([0.0, 0])]
215227
#[TestWith([100, 100_000_000])]
216228
#[TestWith([100.1, 100_100_000])]
217229
#[TestWith([100.5, 100_500_000])]
@@ -223,6 +235,8 @@ public function testFromSeconds(int|float $seconds, int $expected): void
223235
self::assertSame($expected, $span->toMicroseconds());
224236
}
225237

238+
#[TestWith([0, 0])]
239+
#[TestWith([0.0, 0])]
226240
#[TestWith([100, 6_000_000_000])]
227241
#[TestWith([100.1, 6_006_000_000])]
228242
#[TestWith([100.5, 6_030_000_000])]
@@ -234,6 +248,8 @@ public function testFromMinutes(int|float $minutes, int $expected): void
234248
self::assertSame($expected, $span->toMicroseconds());
235249
}
236250

251+
#[TestWith([0, 0])]
252+
#[TestWith([0.0, 0])]
237253
#[TestWith([100, 360_000_000_000])]
238254
#[TestWith([100.1, 360_360_000_000])]
239255
#[TestWith([100.5, 361_800_000_000])]
@@ -245,6 +261,8 @@ public function testFromHours(int|float $hours, int $expected): void
245261
self::assertSame($expected, $span->toMicroseconds());
246262
}
247263

264+
#[TestWith([0, 0])]
265+
#[TestWith([0.0, 0])]
248266
#[TestWith([100, 8_640_000_000_000_000])]
249267
#[TestWith([106751, 9_223_286_400_000_000_000])]
250268
#[TestWith([-106751, -9_223_286_400_000_000_000])]

0 commit comments

Comments
 (0)