Skip to content

Commit 602cd26

Browse files
Support up to microsecond precision input timestamps (#37)
* Support up to microsecond precision input timestamps Signed-off-by: Graham Campbell <hello@gjcampbell.co.uk> * Prefix global functions with slash Signed-off-by: Graham Campbell <hello@gjcampbell.co.uk> * Upgraded psalm to fix false positives Signed-off-by: Graham Campbell <hello@gjcampbell.co.uk> * Added test coverage with a non-UTC timezone Signed-off-by: Graham Campbell <hello@gjcampbell.co.uk>
1 parent 53d1f2f commit 602cd26

File tree

5 files changed

+51
-10
lines changed

5 files changed

+51
-10
lines changed

.github/workflows/static.yml

Lines changed: 1 addition & 1 deletion
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.0'
2121
tools: composer:v2
2222
coverage: none
2323

composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
"guzzlehttp/psr7": "^2.0",
2828
"php-http/discovery": "^1.14",
2929
"phpunit/phpunit": "^9.5 || ^10.0",
30-
"psalm/phar": "4.8.1",
30+
"psalm/phar": "4.15.0",
3131
"psr/http-factory": "^1.0.1",
3232
"psr/http-message": "^1.0.1",
3333
"squizlabs/php_codesniffer": "3.6.0"

src/Utilities/TimeFormatter.php

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@ 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+
1922
public static function encode(?DateTimeImmutable $time): ?string
2023
{
2124
if ($time === null) {
@@ -31,7 +34,11 @@ public static function decode(?string $time): ?DateTimeImmutable
3134
return null;
3235
}
3336

34-
$decoded = DateTimeImmutable::createFromFormat(self::TIME_FORMAT, $time, new DateTimeZone(self::TIME_ZONE));
37+
$decoded = DateTimeImmutable::createFromFormat(
38+
\str_contains($time, '.') ? self::RFC3339_EXTENDED_FORMAT : self::RFC3339_FORMAT,
39+
\strtoupper($time),
40+
new DateTimeZone(self::TIME_ZONE)
41+
);
3542

3643
if ($decoded === false) {
3744
throw new ValueError(

src/V1/CloudEventTrait.php

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -273,10 +273,6 @@ private function setExtension(string $attribute, $value): self
273273
);
274274
}
275275

276-
/**
277-
* @psalm-suppress UndefinedFunction
278-
* @var string
279-
*/
280276
$type = \get_debug_type($value);
281277
$types = ['bool', 'int', 'string', 'null'];
282278

tests/Unit/Utilities/TimeFormatterTest.php

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,49 @@ public function testEncode(): void
1919
);
2020
}
2121

22-
public function testDecode(): void
22+
public function providesDecodeCases(): array
23+
{
24+
return [
25+
// UTC
26+
['2018-04-05T17:31:00Z', '2018-04-05T17:31:00Z'],
27+
['1985-04-12T23:20:50.100000Z', '1985-04-12T23:20:50.1Z'],
28+
['1985-04-12T23:20:50.100000Z', '1985-04-12T23:20:50.10Z'],
29+
['1985-04-12T23:20:50.100000Z', '1985-04-12T23:20:50.100Z'],
30+
['1985-04-12T23:20:50.120000Z', '1985-04-12T23:20:50.12Z'],
31+
['1985-04-12T23:20:50.120000Z', '1985-04-12T23:20:50.120Z'],
32+
['1985-04-12T23:20:50.123000Z', '1985-04-12T23:20:50.123Z'],
33+
['1985-04-12T23:20:50.123000Z', '1985-04-12T23:20:50.12300Z'],
34+
['1985-04-12T23:20:50.123400Z', '1985-04-12T23:20:50.1234Z'],
35+
['1985-04-12T23:20:50.123400Z', '1985-04-12T23:20:50.123400Z'],
36+
['1985-04-12T23:20:50.123450Z', '1985-04-12T23:20:50.12345Z'],
37+
['1985-04-12T23:20:50.123450Z', '1985-04-12T23:20:50.123450Z'],
38+
['1985-04-12T23:20:50.123456Z', '1985-04-12T23:20:50.123456Z'],
39+
40+
// +01:00
41+
['2018-04-05T16:31:00Z', '2018-04-05T17:31:00+01:00'],
42+
['1985-04-12T22:20:50.100000Z', '1985-04-12T23:20:50.1+01:00'],
43+
['1985-04-12T22:20:50.100000Z', '1985-04-12T23:20:50.10+01:00'],
44+
['1985-04-12T22:20:50.100000Z', '1985-04-12T23:20:50.100+01:00'],
45+
['1985-04-12T22:20:50.120000Z', '1985-04-12T23:20:50.12+01:00'],
46+
['1985-04-12T22:20:50.120000Z', '1985-04-12T23:20:50.120+01:00'],
47+
['1985-04-12T22:20:50.123000Z', '1985-04-12T23:20:50.123+01:00'],
48+
['1985-04-12T22:20:50.123000Z', '1985-04-12T23:20:50.12300+01:00'],
49+
['1985-04-12T22:20:50.123400Z', '1985-04-12T23:20:50.1234+01:00'],
50+
['1985-04-12T22:20:50.123400Z', '1985-04-12T23:20:50.123400+01:00'],
51+
['1985-04-12T22:20:50.123450Z', '1985-04-12T23:20:50.12345+01:00'],
52+
['1985-04-12T22:20:50.123450Z', '1985-04-12T23:20:50.123450+01:00'],
53+
['1985-04-12T22:20:50.123456Z', '1985-04-12T23:20:50.123456+01:00'],
54+
];
55+
}
56+
57+
/**
58+
* @dataProvider providesDecodeCases
59+
*/
60+
public function testDecode(string $expected, string $input): void
2361
{
2462
self::assertEquals(
25-
new DateTimeImmutable('2018-04-05T17:31:00Z'),
26-
TimeFormatter::decode('2018-04-05T17:31:00Z')
63+
new DateTimeImmutable($expected),
64+
TimeFormatter::decode($input)
2765
);
2866
}
2967

0 commit comments

Comments
 (0)