Skip to content

Commit

Permalink
Better support RFC3339 (#47)
Browse files Browse the repository at this point in the history
  • Loading branch information
jlaswell authored Apr 22, 2023
1 parent f2e22c6 commit 298474a
Show file tree
Hide file tree
Showing 5 changed files with 49 additions and 17 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/static.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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:
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
.phpunit.cache
.phpunit.result.cache

composer.lock
phpcs.xml
Expand Down
7 changes: 4 additions & 3 deletions phpunit.xml.dist
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<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">
<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">
<testsuites>
<testsuite name="Unit Test Suite">
<directory suffix="Test.php">tests/Unit</directory>
</testsuite>
</testsuites>
<coverage>
<coverage/>
<source>
<include>
<directory suffix=".php">src</directory>
</include>
</coverage>
</source>
</phpunit>
45 changes: 34 additions & 11 deletions src/Utilities/TimeFormatter.php
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -34,19 +31,45 @@ 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)
);
$time = self::trimMicroseconds($time);

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 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') {
return $datetime->setTimezone(new \DateTimeZone('UTC'));
}

return $datetime;
}
}
9 changes: 8 additions & 1 deletion tests/Unit/Utilities/TimeFormatterTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public function testEncode(): void
);
}

public function providesDecodeCases(): array
public static function providesDecodeCases(): array
{
return [
// UTC
Expand All @@ -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'],
Expand All @@ -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'],
];
}

Expand Down

0 comments on commit 298474a

Please sign in to comment.