From e0f4713cc390301e77dfdcb5d466411bb2f73ddd Mon Sep 17 00:00:00 2001 From: Timm Friebe Date: Mon, 30 Dec 2024 19:50:32 +0100 Subject: [PATCH 1/3] Accept strings or util.TimeZone instances --- src/main/php/util/Date.class.php | 41 ++++++++++++------- src/test/php/util/unittest/DateTest.class.php | 21 +++++++--- 2 files changed, 42 insertions(+), 20 deletions(-) diff --git a/src/main/php/util/Date.class.php b/src/main/php/util/Date.class.php index 1385d80f4..84ed33739 100755 --- a/src/main/php/util/Date.class.php +++ b/src/main/php/util/Date.class.php @@ -1,6 +1,6 @@ getHandle(); + } else { + $tz= new DateTimeZone($timezone); + } + if (null === $in) { - $this->handle= date_create('now', $timezone ? $timezone->getHandle() : null); + $this->handle= date_create('now', $tz); } else if ($in instanceof DateTime) { $this->handle= $in; } else if (is_int($in) || (string)(int)$in === $in) { @@ -51,15 +59,15 @@ public function __construct($in= null, ?TimeZone $timezone= null) { // 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()); + $tz && date_timezone_set($this->handle, $tz); } 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()); + $tz && date_timezone_set($this->handle, $tz); } else { - if (false === ($this->handle= date_create($in ?? 'now', $timezone ? $timezone->getHandle() : null))) { + if (false === ($this->handle= date_create($in ?? 'now', $tz))) { throw new IllegalArgumentException('Given argument is neither a timestamp nor a well-formed timestring: '.Objects::stringOf($in)); } } @@ -96,13 +104,16 @@ public function __unserialize($data) { * @param int $hour * @param int $minute * @param int $second - * @param ?util.TimeZone $tz default NULL + * @param ?string|util.TimeZone $timezone * @return self */ - public static function create($year, $month, $day, $hour, $minute, $second, ?TimeZone $tz= null): self { - $date= date_create(); - if ($tz) { - date_timezone_set($date, $tz->getHandle()); + public static function create($year, $month, $day, $hour, $minute, $second, $timezone= null): self { + if (null === $timezone) { + $date= date_create(); + } else if ($timezone instanceof TimeZone) { + $date= date_create('now', $timezone->getHandle()); + } else { + $date= date_create('now', new DateTimeZone($timezone)); } try { @@ -133,9 +144,9 @@ public function equals($cmp): bool { return $cmp instanceof self && $this->getTime() === $cmp->getTime(); } - /** Static method to get current date/time */ - public static function now(?TimeZone $tz= null): self { - return new self(null, $tz); + /** @param ?string|util.TimeZone $timezone */ + public static function now($timezone= null): self { + return new self(null, $timezone); } /** Compare this date to another date */ diff --git a/src/test/php/util/unittest/DateTest.class.php b/src/test/php/util/unittest/DateTest.class.php index 6e40a73e6..101c43d83 100755 --- a/src/test/php/util/unittest/DateTest.class.php +++ b/src/test/php/util/unittest/DateTest.class.php @@ -7,6 +7,12 @@ class DateTest { private $nowTime, $nowDate, $refDate, $tz; + /** @return iterable */ + private function timezones() { + yield 'Europe/Berlin'; + yield new TimeZone('Europe/Berlin'); + } + #[Before] public function setUp() { @@ -51,11 +57,11 @@ public function constructorUnixtimestampWithoutTz() { $this->assertDateEquals('2007-08-23T12:35:47+00:00', new Date(1187872547)); } - #[Test] - public function constructorUnixtimestampWithTz() { - $this->assertDateEquals('2007-08-23T14:35:47+02:00', new Date(1187872547, new TimeZone('Europe/Berlin'))); + #[Test, Values(from: 'timezones')] + public function constructorUnixtimestampWithTz($tz) { + $this->assertDateEquals('2007-08-23T14:35:47+02:00', new Date(1187872547, $tz)); } - + #[Test] public function constructorParseTz() { $date= new Date('2007-01-01 01:00:00 Europe/Berlin'); @@ -157,7 +163,12 @@ public function dateCreate() { // Test with a date before 1971 Assert::equals(-44668800, Date::create(1968, 8, 2, 0, 0, 0)->getTime()); } - + + #[Test, Values(from: 'timezones')] + public function create_date_with_timezone($tz) { + Assert::equals(-44672400, Date::create(1968, 8, 2, 0, 0, 0, $tz)->getTime()); + } + #[Test] public function pre1970() { $this->assertDateEquals('1969-02-01T00:00:00+00:00', new Date('01.02.1969')); From f43610ec660b1b1966d9cbc7400da83cf4083c03 Mon Sep 17 00:00:00 2001 From: Timm Friebe Date: Tue, 31 Dec 2024 10:37:16 +0100 Subject: [PATCH 2/3] Accept string or timezone instances in toString() and format() --- src/main/php/util/Date.class.php | 30 +++++++++++++++---- src/test/php/util/unittest/DateTest.class.php | 27 ++++++++++------- 2 files changed, 40 insertions(+), 17 deletions(-) diff --git a/src/main/php/util/Date.class.php b/src/main/php/util/Date.class.php index 84ed33739..41ca7d3fc 100755 --- a/src/main/php/util/Date.class.php +++ b/src/main/php/util/Date.class.php @@ -210,11 +210,20 @@ public function getTimeZone(): Timezone { * * @see php://date * @param string $format default Date::DEFAULT_FORMAT format-string - * @param ?util.TimeZone $outtz default NULL + * @param ?string|util.TimeZone $timezone * @return string the formatted date */ - public function toString(string $format= self::DEFAULT_FORMAT, ?TimeZone $outtz= null): string { - return date_format(($outtz === null ? $this : $outtz->translate($this))->handle, $format); + public function toString(string $format= self::DEFAULT_FORMAT, $timezone= null): string { + if (null === $timezone) { + $handle= $this->handle; + } else if ($timezone instanceof TimeZone) { + $handle= clone $this->handle; + date_timezone_set($handle, $timezone->getHandle()); + } else { + $handle= clone $this->handle; + date_timezone_set($handle, new DateTimeZone($timezone)); + } + return date_format($handle, $format); } /** @@ -225,11 +234,11 @@ public function toString(string $format= self::DEFAULT_FORMAT, ?TimeZone $outtz= * * @see php://strftime * @param string $format - * @param ?util.TimeZone $outtz default NULL + * @param ?string|util.TimeZone $timezone * @return string * @throws lang.IllegalArgumentException if unsupported token has been given */ - public function format(string $format, ?TimeZone $outtz= null): string { + public function format(string $format, $timezone= null): string { static $replace= [ '%d' => 'd', '%m' => 'm', @@ -264,6 +273,15 @@ public function format(string $format, ?TimeZone $outtz= null): string { '%%' => '%' ]; - return date_format(($outtz === null ? $this : $outtz->translate($this))->handle, strtr($format, $replace)); + if (null === $timezone) { + $handle= $this->handle; + } else if ($timezone instanceof TimeZone) { + $handle= clone $this->handle; + date_timezone_set($handle, $timezone->getHandle()); + } else { + $handle= clone $this->handle; + date_timezone_set($handle, new DateTimeZone($timezone)); + } + return date_format($handle, strtr($format, $replace)); } } \ No newline at end of file diff --git a/src/test/php/util/unittest/DateTest.class.php b/src/test/php/util/unittest/DateTest.class.php index 101c43d83..2aec7284b 100755 --- a/src/test/php/util/unittest/DateTest.class.php +++ b/src/test/php/util/unittest/DateTest.class.php @@ -279,21 +279,29 @@ public function emptyTimeZoneNameIfUnknown() { } #[Test] - public function toStringOutput() { - $date= new Date('2007-11-10 20:15+0100'); - Assert::equals('2007-11-10 20:15:00+0100', $date->toString()); - Assert::equals('2007-11-10 19:15:00+0000', $date->toString(Date::DEFAULT_FORMAT, new TimeZone('GMT'))); + public function string_representation() { + Assert::equals( + '2007-11-10 20:15:00+0100', + (new Date('2007-11-10 20:15+0100'))->toString(Date::DEFAULT_FORMAT) + ); } + #[Test, Values(from: 'timezones')] + public function string_representation_with_timezone($timezone) { + Assert::equals( + '2007-11-10 20:15:00+0100', + (new Date('2007-11-10 19:15+0000'))->toString(Date::DEFAULT_FORMAT, $timezone) + ); + } + #[Test] - public function toStringOutputPreserved() { + public function timezone_preserved_during_serialization() { $date= unserialize(serialize(new Date('2007-11-10 20:15+0100'))); Assert::equals('2007-11-10 20:15:00+0100', $date->toString()); - Assert::equals('2007-11-10 19:15:00+0000', $date->toString(Date::DEFAULT_FORMAT, new TimeZone('GMT'))); } #[Test, Expect(IllegalArgumentException::class)] - public function malformedInputString() { + public function malformed_input_string() { new Date('@@not-a-date@@'); } @@ -320,10 +328,7 @@ public function unknownTimeZoneOffsetInString() { #[Test] public function constructorBrokenAfterException() { Date::now(); - try { - new Date('bogus'); - $this->fail('No exception raised', null, IllegalArgumentException::class); - } catch (\lang\IllegalArgumentException $expected) { } + Assert::throws(IllegalArgumentException::class, fn() => new Date('bogus')); Date::now(); } From 12f4505efc7a7b40879669c58a64a6f00ab49ea5 Mon Sep 17 00:00:00 2001 From: Timm Friebe Date: Tue, 31 Dec 2024 10:40:31 +0100 Subject: [PATCH 3/3] Fix format() thrown exceptions documentation --- src/main/php/util/Date.class.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/php/util/Date.class.php b/src/main/php/util/Date.class.php index 41ca7d3fc..f4d9ee329 100755 --- a/src/main/php/util/Date.class.php +++ b/src/main/php/util/Date.class.php @@ -236,7 +236,6 @@ public function toString(string $format= self::DEFAULT_FORMAT, $timezone= null): * @param string $format * @param ?string|util.TimeZone $timezone * @return string - * @throws lang.IllegalArgumentException if unsupported token has been given */ public function format(string $format, $timezone= null): string { static $replace= [