Skip to content

Commit 27a7fbb

Browse files
committed
[Clock] Polyfill DateTimeImmutable::createFromTimestamp()
1 parent 3f2ed0f commit 27a7fbb

File tree

2 files changed

+59
-0
lines changed

2 files changed

+59
-0
lines changed

src/Symfony/Component/Clock/DatePoint.php

+24
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,30 @@ public static function createFromMutable(\DateTime $object): static
6666
return parent::createFromMutable($object);
6767
}
6868

69+
public static function createFromTimestamp(int|float $timestamp): static
70+
{
71+
if (\PHP_VERSION_ID >= 80400) {
72+
return parent::createFromTimestamp($timestamp);
73+
}
74+
75+
if (\is_int($timestamp)) {
76+
return (new static())->setTimestamp($timestamp);
77+
}
78+
79+
if (!is_finite($timestamp) || $timestamp > \PHP_INT_MAX + 1.0 || $timestamp < \PHP_INT_MIN) {
80+
throw new \DateRangeError(sprintf('DateTimeImmutable::createFromTimestamp(): Argument #1 ($timestamp) must be a finite number between %s and %s.999999, %s given', \PHP_INT_MIN, \PHP_INT_MAX, $timestamp));
81+
}
82+
83+
$microsecond = (int) ((abs($timestamp) - (int) abs($timestamp)) * 1_000_000);
84+
85+
if (0 > $timestamp) {
86+
$microsecond = 1_000_000 - $microsecond;
87+
}
88+
89+
return (new static())->setTimestamp((int) floor($timestamp))
90+
->setMicrosecond($microsecond);
91+
}
92+
6993
public function add(\DateInterval $interval): static
7094
{
7195
return parent::add($interval);

src/Symfony/Component/Clock/Tests/DatePointTest.php

+35
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,41 @@ public function testCreateFromFormat()
4545
DatePoint::createFromFormat('Y-m-d H:i:s', 'Bad Date');
4646
}
4747

48+
/** @dataProvider provideValidTimestamps */
49+
public function testCreateFromTimestamp(int|float $timestamp, string $expected)
50+
{
51+
$date = DatePoint::createFromTimestamp($timestamp);
52+
53+
$this->assertInstanceOf(DatePoint::class, $date);
54+
$this->assertSame($expected, $date->format('Y-m-d\TH:i:s.uP'));
55+
}
56+
57+
public static function provideValidTimestamps(): iterable
58+
{
59+
yield 'positive integer' => [1359188516, '2013-01-26T08:21:56.000000+00:00'];
60+
yield 'positive float' => [1359188516.123456, '2013-01-26T08:21:56.123456+00:00'];
61+
yield 'zero as integer' => [0, '1970-01-01T00:00:00.000000+00:00'];
62+
yield 'zero as float' => [0.0, '1970-01-01T00:00:00.000000+00:00'];
63+
yield 'negative integer' => [-100, '1969-12-31T23:58:20.000000+00:00'];
64+
yield 'negative float' => [-100.123456, '1969-12-31T23:58:19.876544+00:00'];
65+
}
66+
67+
/** @dataProvider provideOutOfRangeFloatTimestamps */
68+
public function testCreateFromTimestampWithFloatOutOfRange(float $timestamp)
69+
{
70+
$this->expectException(\DateRangeError::class);
71+
$this->expectExceptionMessage('DateTimeImmutable::createFromTimestamp(): Argument #1 ($timestamp) must be a finite number between');
72+
DatePoint::createFromTimestamp(1e20);
73+
}
74+
75+
public function provideOutOfRangeFloatTimestamps(): iterable
76+
{
77+
yield 'too large (positive)' => [1e20];
78+
yield 'too large (negative)' => [-1e20];
79+
yield 'NaN' => [\NAN];
80+
yield 'infinity' => [\INF];
81+
}
82+
4883
public function testModify()
4984
{
5085
$date = new DatePoint('2010-01-28 15:00:00');

0 commit comments

Comments
 (0)