From a8d7420fa720b24416a934e7b12fb374fda359a2 Mon Sep 17 00:00:00 2001 From: Timm Friebe Date: Sat, 17 Aug 2024 14:11:24 +0200 Subject: [PATCH 1/4] QA: Condense testValidUnixTimestamp() using `#[Values]` --- src/test/php/util/unittest/DateTest.class.php | 20 ++++--------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/src/test/php/util/unittest/DateTest.class.php b/src/test/php/util/unittest/DateTest.class.php index 6816e4a2c..b88809002 100755 --- a/src/test/php/util/unittest/DateTest.class.php +++ b/src/test/php/util/unittest/DateTest.class.php @@ -343,22 +343,10 @@ public function createDateFromTime() { Assert::equals(strtotime('19.19'), $date->getTime()); } - #[Test] - public function testValidUnixTimestamp() { - $this->assertDateEquals('1970-01-01T00:00:00+00:00', new Date(0)); - $this->assertDateEquals('1970-01-01T00:00:00+00:00', new Date('0')); - - $this->assertDateEquals('1970-01-01T00:00:01+00:00', new Date(1)); - $this->assertDateEquals('1970-01-01T00:00:01+00:00', new Date('1')); - - $this->assertDateEquals('1969-12-31T23:59:59+00:00', new Date(-1)); - $this->assertDateEquals('1969-12-31T23:59:59+00:00', new Date('-1')); - - $this->assertDateEquals('1969-12-20T10:13:20+00:00', new Date(-1000000)); - $this->assertDateEquals('1969-12-20T10:13:20+00:00', new Date('-1000000')); - - $this->assertDateEquals('1970-01-12T13:46:40+00:00', new Date(1000000)); - $this->assertDateEquals('1970-01-12T13:46:40+00:00', new Date('1000000')); + #[Test, Values([[0, '1970-01-01T00:00:00+00:00'], [1, '1970-01-01T00:00:01+00:00'], [-1, '1969-12-31T23:59:59+00:00'], [-1000000, '1969-12-20T10:13:20+00:00'], [1000000, '1970-01-12T13:46:40+00:00']])] + public function testValidUnixTimestamp($timestamp, $expected) { + $this->assertDateEquals($expected, new Date($timestamp)); + $this->assertDateEquals($expected, new Date((string)$timestamp)); } #[Test, Expect(IllegalArgumentException::class)] From 754b663ea0df560804274c7f434f7dc76be5cccd Mon Sep 17 00:00:00 2001 From: Timm Friebe Date: Sat, 17 Aug 2024 14:20:00 +0200 Subject: [PATCH 2/4] Support passing floating point numbers to constructor, setting microseconds --- src/main/php/util/Date.class.php | 13 ++++++++----- src/test/php/util/unittest/DateTest.class.php | 5 +++++ 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/main/php/util/Date.class.php b/src/main/php/util/Date.class.php index c636b1b62..1d0f47e51 100755 --- a/src/main/php/util/Date.class.php +++ b/src/main/php/util/Date.class.php @@ -1,5 +1,6 @@ handle= date_create('now', $timezone ? $timezone->getHandle() : null); + } else if ($in instanceof DateTime) { $this->handle= $in; - } else if ((string)(int)$in === (string)$in) { + } else if (is_int($in) || is_float($in) || (string)(int)$in === $in) { // Specially mark timestamps for parsing (we assume here that strings // containing only digits are timestamps) $this->handle= date_create('@'.$in); - date_timezone_set($this->handle, $timezone ? $timezone->getHandle() : timezone_open(date_default_timezone_get())); + $timezone && date_timezone_set($this->handle, $timezone->getHandle()); } else { if (false === ($this->handle= date_create($in ?? 'now', $timezone ? $timezone->getHandle() : null))) { throw new IllegalArgumentException('Given argument is neither a timestamp nor a well-formed timestring: '.Objects::stringOf($in)); @@ -62,7 +65,7 @@ public function hashCode(): string { } /** Retrieve handle of underlying DateTime object. */ - public function getHandle(): \DateTime { + public function getHandle(): DateTime { return clone $this->handle; } diff --git a/src/test/php/util/unittest/DateTest.class.php b/src/test/php/util/unittest/DateTest.class.php index b88809002..6e40a73e6 100755 --- a/src/test/php/util/unittest/DateTest.class.php +++ b/src/test/php/util/unittest/DateTest.class.php @@ -358,4 +358,9 @@ public function testInvalidUnixTimestamp() { public function microseconds() { Assert::equals(393313, (new Date('2019-07-03 15:18:10.393313'))->getMicroSeconds()); } + + #[Test] + public function float_timestamp() { + Assert::equals(393000, (new Date(1723896922.393))->getMicroSeconds()); + } } \ No newline at end of file From 22c9231fc2e18e2d917d8c5e7742f14ece6cd79c Mon Sep 17 00:00:00 2001 From: Timm Friebe Date: Sat, 17 Aug 2024 14:46:09 +0200 Subject: [PATCH 3/4] Ensure floating point arguments do not yield microsecond fractions > 6 digits --- src/main/php/util/Date.class.php | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/main/php/util/Date.class.php b/src/main/php/util/Date.class.php index 1d0f47e51..f74f44db8 100755 --- a/src/main/php/util/Date.class.php +++ b/src/main/php/util/Date.class.php @@ -46,12 +46,18 @@ public function __construct($in= null, ?TimeZone $timezone= null) { $this->handle= date_create('now', $timezone ? $timezone->getHandle() : null); } else if ($in instanceof DateTime) { $this->handle= $in; - } else if (is_int($in) || is_float($in) || (string)(int)$in === $in) { - + } else if (is_int($in) || (string)(int)$in === $in) { + // Specially mark timestamps for parsing (we assume here that strings // containing only digits are timestamps) $this->handle= date_create('@'.$in); $timezone && date_timezone_set($this->handle, $timezone->getHandle()); + } else if (is_float($in)) { + + // Timestamps with microseconds are defined as `"@" "-"? [0-9]+ "." [0-9]{0,6}`, + // see https://www.php.net/manual/en/datetime.formats.php#datetime.formats.relative + $this->handle= date_create('@'.sprintf('%.6f', $in); + $timezone && date_timezone_set($this->handle, $timezone->getHandle()); } else { if (false === ($this->handle= date_create($in ?? 'now', $timezone ? $timezone->getHandle() : null))) { throw new IllegalArgumentException('Given argument is neither a timestamp nor a well-formed timestring: '.Objects::stringOf($in)); From a01a5769b933718ad90d0bb77af92678123aab82 Mon Sep 17 00:00:00 2001 From: Timm Friebe Date: Sat, 17 Aug 2024 14:47:33 +0200 Subject: [PATCH 4/4] Fix creation from floating points --- src/main/php/util/Date.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/php/util/Date.class.php b/src/main/php/util/Date.class.php index f74f44db8..1385d80f4 100755 --- a/src/main/php/util/Date.class.php +++ b/src/main/php/util/Date.class.php @@ -56,7 +56,7 @@ public function __construct($in= null, ?TimeZone $timezone= null) { // Timestamps with microseconds are defined as `"@" "-"? [0-9]+ "." [0-9]{0,6}`, // see https://www.php.net/manual/en/datetime.formats.php#datetime.formats.relative - $this->handle= date_create('@'.sprintf('%.6f', $in); + $this->handle= date_create('@'.sprintf('%.6f', $in)); $timezone && date_timezone_set($this->handle, $timezone->getHandle()); } else { if (false === ($this->handle= date_create($in ?? 'now', $timezone ? $timezone->getHandle() : null))) {