From 773015399af50cbefca2ef3fa9306d91133619c7 Mon Sep 17 00:00:00 2001 From: John Laswell Date: Tue, 18 Apr 2023 19:09:47 +0000 Subject: [PATCH 1/3] better support rfc3339 Additional support for microsecond values greater than 6 digits. Signed-off-by: John Laswell --- .gitignore | 1 + phpunit.xml.dist | 7 +++--- src/Utilities/TimeFormatter.php | 25 +++++++++++----------- tests/Unit/Utilities/TimeFormatterTest.php | 9 +++++++- 4 files changed, 26 insertions(+), 16 deletions(-) diff --git a/.gitignore b/.gitignore index 7ea05c8..4b21b4a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ .phpunit.cache +.phpunit.result.cache composer.lock phpcs.xml diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 39df3df..0f08581 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,13 +1,14 @@ - + tests/Unit - + + src - + diff --git a/src/Utilities/TimeFormatter.php b/src/Utilities/TimeFormatter.php index b166608..c9ba464 100644 --- a/src/Utilities/TimeFormatter.php +++ b/src/Utilities/TimeFormatter.php @@ -16,9 +16,6 @@ final class TimeFormatter private const TIME_FORMAT = 'Y-m-d\TH:i:s\Z'; private const TIME_ZONE = 'UTC'; - private const RFC3339_FORMAT = 'Y-m-d\TH:i:sP'; - private const RFC3339_EXTENDED_FORMAT = 'Y-m-d\TH:i:s.uP'; - public static function encode(?DateTimeImmutable $time): ?string { if ($time === null) { @@ -34,19 +31,23 @@ public static function decode(?string $time): ?DateTimeImmutable return null; } - /** @psalm-suppress UndefinedFunction */ - $decoded = DateTimeImmutable::createFromFormat( - \str_contains($time, '.') ? self::RFC3339_EXTENDED_FORMAT : self::RFC3339_FORMAT, - \strtoupper($time), - new DateTimeZone(self::TIME_ZONE) - ); - - if ($decoded === false) { + try { + $decoded = new DateTimeImmutable($time); + } catch (\Throwable $th) { throw new ValueError( \sprintf('%s(): Argument #1 ($time) is not a valid RFC3339 timestamp', __METHOD__) ); } - return $decoded; + return self::shiftWithTimezone($time, $decoded); + } + + private static function shiftWithTimezone(string $time, DateTimeImmutable $datetime): DateTimeImmutable + { + if (strpos($time, '+') === false && strpos($time, '-') === false && strtoupper(substr($time, -1)) !== 'Z') { + return $datetime->setTimezone(new \DateTimeZone('UTC')); + } + + return $datetime; } } diff --git a/tests/Unit/Utilities/TimeFormatterTest.php b/tests/Unit/Utilities/TimeFormatterTest.php index be3514e..4152fd3 100644 --- a/tests/Unit/Utilities/TimeFormatterTest.php +++ b/tests/Unit/Utilities/TimeFormatterTest.php @@ -19,7 +19,7 @@ public function testEncode(): void ); } - public function providesDecodeCases(): array + public static function providesDecodeCases(): array { return [ // UTC @@ -36,6 +36,9 @@ public function providesDecodeCases(): array ['1985-04-12T23:20:50.123450Z', '1985-04-12T23:20:50.12345Z'], ['1985-04-12T23:20:50.123450Z', '1985-04-12T23:20:50.123450Z'], ['1985-04-12T23:20:50.123456Z', '1985-04-12T23:20:50.123456Z'], + ['1985-04-12T23:20:50.123456Z', '1985-04-12T23:20:50.1234567Z'], + ['1985-04-12T23:20:50.123456Z', '1985-04-12T23:20:50.12345678Z'], + ['1985-04-12T23:20:50.123456Z', '1985-04-12T23:20:50.123456789Z'], // +01:00 ['2018-04-05T16:31:00Z', '2018-04-05T17:31:00+01:00'], @@ -51,6 +54,10 @@ public function providesDecodeCases(): array ['1985-04-12T22:20:50.123450Z', '1985-04-12T23:20:50.12345+01:00'], ['1985-04-12T22:20:50.123450Z', '1985-04-12T23:20:50.123450+01:00'], ['1985-04-12T22:20:50.123456Z', '1985-04-12T23:20:50.123456+01:00'], + ['1985-04-12T22:20:50.123456Z', '1985-04-12T23:20:50.1234567+01:00'], + ['1985-04-12T22:20:50.123456Z', '1985-04-12T23:20:50.12345678+01:00'], + ['1985-04-12T22:20:50.123456Z', '1985-04-12T23:20:50.123456789+01:00'], + ['1985-04-12T22:20:50.123456Z', '1985-04-12T23:20:50.1234567890+01:00'], ]; } From 4618a84581f71677a1ec39077e0fea38e88ea615 Mon Sep 17 00:00:00 2001 From: John Laswell Date: Wed, 19 Apr 2023 14:10:57 +0000 Subject: [PATCH 2/3] update static workflow to PHP 8.2 Signed-off-by: John Laswell --- .github/workflows/static.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/static.yml b/.github/workflows/static.yml index cb5e2d0..135bab5 100644 --- a/.github/workflows/static.yml +++ b/.github/workflows/static.yml @@ -17,7 +17,7 @@ jobs: - name: Setup PHP uses: shivammathur/setup-php@v2 with: - php-version: '7.4' + php-version: '8.2' tools: composer:v2 coverage: none env: @@ -44,7 +44,7 @@ jobs: - name: Setup PHP uses: shivammathur/setup-php@v2 with: - php-version: '7.4' + php-version: '8.2' tools: composer:v2 coverage: none env: From 876e7380ecddd0f5ea65c795b41bf4e28ad1e4f2 Mon Sep 17 00:00:00 2001 From: John Laswell Date: Wed, 19 Apr 2023 14:43:57 +0000 Subject: [PATCH 3/3] update precision support for php 7.4 Signed-off-by: John Laswell --- src/Utilities/TimeFormatter.php | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/src/Utilities/TimeFormatter.php b/src/Utilities/TimeFormatter.php index c9ba464..5884226 100644 --- a/src/Utilities/TimeFormatter.php +++ b/src/Utilities/TimeFormatter.php @@ -31,6 +31,8 @@ public static function decode(?string $time): ?DateTimeImmutable return null; } + $time = self::trimMicroseconds($time); + try { $decoded = new DateTimeImmutable($time); } catch (\Throwable $th) { @@ -42,9 +44,29 @@ public static function decode(?string $time): ?DateTimeImmutable return self::shiftWithTimezone($time, $decoded); } + private static function trimMicroseconds(string $time): string + { + $microseconds = explode('.', $time, 2); + if (isset($microseconds[1])) { + $microsecondsAndTimezone = explode('+', $microseconds[1], 2); + if (count($microsecondsAndTimezone) === 1) { + $microsecondsAndTimezone = explode('-', $microseconds[1], 2); + } + $timezone = isset($microsecondsAndTimezone[1]) ? sprintf('+%s', $microsecondsAndTimezone[1]) : ''; + $time = sprintf( + "%s.%s%s", + $microseconds[0], + substr($microsecondsAndTimezone[0], 0, 6), + $timezone + ); + } + + return $time; + } + private static function shiftWithTimezone(string $time, DateTimeImmutable $datetime): DateTimeImmutable { - if (strpos($time, '+') === false && strpos($time, '-') === false && strtoupper(substr($time, -1)) !== 'Z') { + if (\strpos($time, '+') === false && \strpos($time, '-') === false && \strtoupper(\substr($time, -1)) !== 'Z') { return $datetime->setTimezone(new \DateTimeZone('UTC')); }