Skip to content

Commit 298474a

Browse files
authored
Better support RFC3339 (#47)
1 parent f2e22c6 commit 298474a

File tree

5 files changed

+49
-17
lines changed

5 files changed

+49
-17
lines changed

.github/workflows/static.yml

+2-2
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ jobs:
1717
- name: Setup PHP
1818
uses: shivammathur/setup-php@v2
1919
with:
20-
php-version: '7.4'
20+
php-version: '8.2'
2121
tools: composer:v2
2222
coverage: none
2323
env:
@@ -44,7 +44,7 @@ jobs:
4444
- name: Setup PHP
4545
uses: shivammathur/setup-php@v2
4646
with:
47-
php-version: '7.4'
47+
php-version: '8.2'
4848
tools: composer:v2
4949
coverage: none
5050
env:

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
.phpunit.cache
2+
.phpunit.result.cache
23

34
composer.lock
45
phpcs.xml

phpunit.xml.dist

+4-3
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
<?xml version="1.0" encoding="UTF-8"?>
2-
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/10.0/phpunit.xsd" beStrictAboutOutputDuringTests="true" bootstrap="vendor/autoload.php" executionOrder="depends,defects" failOnRisky="true" failOnWarning="true">
2+
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/10.1/phpunit.xsd" beStrictAboutOutputDuringTests="true" bootstrap="vendor/autoload.php" executionOrder="depends,defects" failOnRisky="true" failOnWarning="true">
33
<testsuites>
44
<testsuite name="Unit Test Suite">
55
<directory suffix="Test.php">tests/Unit</directory>
66
</testsuite>
77
</testsuites>
8-
<coverage>
8+
<coverage/>
9+
<source>
910
<include>
1011
<directory suffix=".php">src</directory>
1112
</include>
12-
</coverage>
13+
</source>
1314
</phpunit>

src/Utilities/TimeFormatter.php

+34-11
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,6 @@ final class TimeFormatter
1616
private const TIME_FORMAT = 'Y-m-d\TH:i:s\Z';
1717
private const TIME_ZONE = 'UTC';
1818

19-
private const RFC3339_FORMAT = 'Y-m-d\TH:i:sP';
20-
private const RFC3339_EXTENDED_FORMAT = 'Y-m-d\TH:i:s.uP';
21-
2219
public static function encode(?DateTimeImmutable $time): ?string
2320
{
2421
if ($time === null) {
@@ -34,19 +31,45 @@ public static function decode(?string $time): ?DateTimeImmutable
3431
return null;
3532
}
3633

37-
/** @psalm-suppress UndefinedFunction */
38-
$decoded = DateTimeImmutable::createFromFormat(
39-
\str_contains($time, '.') ? self::RFC3339_EXTENDED_FORMAT : self::RFC3339_FORMAT,
40-
\strtoupper($time),
41-
new DateTimeZone(self::TIME_ZONE)
42-
);
34+
$time = self::trimMicroseconds($time);
4335

44-
if ($decoded === false) {
36+
try {
37+
$decoded = new DateTimeImmutable($time);
38+
} catch (\Throwable $th) {
4539
throw new ValueError(
4640
\sprintf('%s(): Argument #1 ($time) is not a valid RFC3339 timestamp', __METHOD__)
4741
);
4842
}
4943

50-
return $decoded;
44+
return self::shiftWithTimezone($time, $decoded);
45+
}
46+
47+
private static function trimMicroseconds(string $time): string
48+
{
49+
$microseconds = explode('.', $time, 2);
50+
if (isset($microseconds[1])) {
51+
$microsecondsAndTimezone = explode('+', $microseconds[1], 2);
52+
if (count($microsecondsAndTimezone) === 1) {
53+
$microsecondsAndTimezone = explode('-', $microseconds[1], 2);
54+
}
55+
$timezone = isset($microsecondsAndTimezone[1]) ? sprintf('+%s', $microsecondsAndTimezone[1]) : '';
56+
$time = sprintf(
57+
"%s.%s%s",
58+
$microseconds[0],
59+
substr($microsecondsAndTimezone[0], 0, 6),
60+
$timezone
61+
);
62+
}
63+
64+
return $time;
65+
}
66+
67+
private static function shiftWithTimezone(string $time, DateTimeImmutable $datetime): DateTimeImmutable
68+
{
69+
if (\strpos($time, '+') === false && \strpos($time, '-') === false && \strtoupper(\substr($time, -1)) !== 'Z') {
70+
return $datetime->setTimezone(new \DateTimeZone('UTC'));
71+
}
72+
73+
return $datetime;
5174
}
5275
}

tests/Unit/Utilities/TimeFormatterTest.php

+8-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ public function testEncode(): void
1919
);
2020
}
2121

22-
public function providesDecodeCases(): array
22+
public static function providesDecodeCases(): array
2323
{
2424
return [
2525
// UTC
@@ -36,6 +36,9 @@ public function providesDecodeCases(): array
3636
['1985-04-12T23:20:50.123450Z', '1985-04-12T23:20:50.12345Z'],
3737
['1985-04-12T23:20:50.123450Z', '1985-04-12T23:20:50.123450Z'],
3838
['1985-04-12T23:20:50.123456Z', '1985-04-12T23:20:50.123456Z'],
39+
['1985-04-12T23:20:50.123456Z', '1985-04-12T23:20:50.1234567Z'],
40+
['1985-04-12T23:20:50.123456Z', '1985-04-12T23:20:50.12345678Z'],
41+
['1985-04-12T23:20:50.123456Z', '1985-04-12T23:20:50.123456789Z'],
3942

4043
// +01:00
4144
['2018-04-05T16:31:00Z', '2018-04-05T17:31:00+01:00'],
@@ -51,6 +54,10 @@ public function providesDecodeCases(): array
5154
['1985-04-12T22:20:50.123450Z', '1985-04-12T23:20:50.12345+01:00'],
5255
['1985-04-12T22:20:50.123450Z', '1985-04-12T23:20:50.123450+01:00'],
5356
['1985-04-12T22:20:50.123456Z', '1985-04-12T23:20:50.123456+01:00'],
57+
['1985-04-12T22:20:50.123456Z', '1985-04-12T23:20:50.1234567+01:00'],
58+
['1985-04-12T22:20:50.123456Z', '1985-04-12T23:20:50.12345678+01:00'],
59+
['1985-04-12T22:20:50.123456Z', '1985-04-12T23:20:50.123456789+01:00'],
60+
['1985-04-12T22:20:50.123456Z', '1985-04-12T23:20:50.1234567890+01:00'],
5461
];
5562
}
5663

0 commit comments

Comments
 (0)