Skip to content

Commit

Permalink
bugfix: iso8601 timestamp parsing (#2974)
Browse files Browse the repository at this point in the history
  • Loading branch information
stobrien89 authored Aug 2, 2024
1 parent 6d46c8e commit 46c14c3
Show file tree
Hide file tree
Showing 5 changed files with 70 additions and 0 deletions.
7 changes: 7 additions & 0 deletions .changes/nextrelease/iso-8601-fix.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[
{
"type": "bugfix",
"category": "Api",
"description": "Fixes issue with parsing iso8601 timestamps with nanosecond precision in versions 8.0.9 and below."
}
]
10 changes: 10 additions & 0 deletions src/Api/DateTimeResult.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
*/
class DateTimeResult extends \DateTime implements \JsonSerializable
{
private const ISO8601_NANOSECOND_REGEX = '/^(.*\.\d{6})(\d{1,3})(Z|[+-]\d{2}:\d{2})?$/';

/**
* Create a new DateTimeResult from a unix timestamp.
* The Unix epoch (or Unix time or POSIX time or Unix
Expand Down Expand Up @@ -60,6 +62,14 @@ public static function fromISO8601($iso8601Timestamp)
throw new ParserException('Invalid timestamp value passed to DateTimeResult::fromISO8601');
}

// Prior to 8.0.10, nanosecond precision is not supported
// Reduces to microsecond precision if nanosecond precision is detected
if (PHP_VERSION_ID < 80010
&& preg_match(self::ISO8601_NANOSECOND_REGEX, $iso8601Timestamp, $matches)
) {
$iso8601Timestamp = $matches[1] . ($matches[3] ?? '');
}

return new DateTimeResult($iso8601Timestamp);
}

Expand Down
29 changes: 29 additions & 0 deletions tests/Api/DateTimeResultTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,4 +49,33 @@ public function testJsonSerialzesAsIso8601()
$d = DateTimeResult::fromEpoch($t);
$this->assertSame('"' . gmdate('c', $t). '"', json_encode($d));
}

/**
* @return void
*
* @dataProvider nanosecondPrecisionProvider
*/
public function testIso8601NanosecondPrecision($timestamp, $expected)
{
$parsed = DateTimeResult::fromISO8601($timestamp);
$this->assertEquals($expected, (string) $parsed);
}

public function nanosecondPrecisionProvider()
{
return [
['2024-07-31T19:05:47.1234567Z', '2024-07-31T19:05:47+00:00'],
['2024-07-31T19:05:47.12345678Z', '2024-07-31T19:05:47+00:00'],
['2024-07-31T19:05:47.123456789Z', '2024-07-31T19:05:47+00:00'],
['2024-07-31T19:05:47.1234567+02:00', '2024-07-31T19:05:47+02:00'],
['2024-07-31T19:05:47.12345678+02:00', '2024-07-31T19:05:47+02:00'],
['2024-07-31T19:05:47.123456789+02:00', '2024-07-31T19:05:47+02:00'],
['2024-07-31T19:05:47.1234567-05:00', '2024-07-31T19:05:47-05:00'],
['2024-07-31T19:05:47.12345678-05:00', '2024-07-31T19:05:47-05:00'],
['2024-07-31T19:05:47.123456789-05:00', '2024-07-31T19:05:47-05:00'],
['2024-07-31T19:05:47.1234567', '2024-07-31T19:05:47+00:00'],
['2024-07-31T19:05:47.12345678', '2024-07-31T19:05:47+00:00'],
['2024-07-31T19:05:47.123456789', '2024-07-31T19:05:47+00:00']
];
}
}
12 changes: 12 additions & 0 deletions tests/Api/Parser/JsonParserTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,18 @@ public function timeStampModelProvider()
[(float) 0, "ParseIso8601", "1970-01-01T00:00:00+00:00"],
[(float) 0, "ParseUnix", "1970-01-01T00:00:00+00:00"],
[(float) 0, "ParseUnknown", '1970-01-01T00:00:00+00:00'],
['2024-07-31T19:05:47.1234567Z', 'ParseIso8601', '2024-07-31T19:05:47+00:00'],
['2024-07-31T19:05:47.12345678Z', 'ParseIso8601', '2024-07-31T19:05:47+00:00'],
['2024-07-31T19:05:47.123456789Z', 'ParseIso8601', '2024-07-31T19:05:47+00:00'],
['2024-07-31T19:05:47.1234567+02:00', 'ParseIso8601', '2024-07-31T19:05:47+02:00'],
['2024-07-31T19:05:47.12345678+02:00', 'ParseIso8601', '2024-07-31T19:05:47+02:00'],
['2024-07-31T19:05:47.123456789+02:00', 'ParseIso8601', '2024-07-31T19:05:47+02:00'],
['2024-07-31T19:05:47.1234567-05:00', 'ParseIso8601', '2024-07-31T19:05:47-05:00'],
['2024-07-31T19:05:47.12345678-05:00', 'ParseIso8601', '2024-07-31T19:05:47-05:00'],
['2024-07-31T19:05:47.123456789-05:00', 'ParseIso8601', '2024-07-31T19:05:47-05:00'],
['2024-07-31T19:05:47.1234567', 'ParseIso8601', '2024-07-31T19:05:47+00:00'],
['2024-07-31T19:05:47.12345678', 'ParseIso8601', '2024-07-31T19:05:47+00:00'],
['2024-07-31T19:05:47.123456789', 'ParseIso8601', '2024-07-31T19:05:47+00:00']
];
}

Expand Down
12 changes: 12 additions & 0 deletions tests/Api/Parser/XmlParserTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,18 @@ public function timeStampModelProvider()
[(float) 0, "ParseIso8601", "1970-01-01T00:00:00+00:00"],
[(float) 0, "ParseUnix", "1970-01-01T00:00:00+00:00"],
[(float) 0, "ParseUnknown", '1970-01-01T00:00:00+00:00'],
['2024-07-31T19:05:47.1234567Z', 'ParseIso8601', '2024-07-31T19:05:47+00:00'],
['2024-07-31T19:05:47.12345678Z', 'ParseIso8601', '2024-07-31T19:05:47+00:00'],
['2024-07-31T19:05:47.123456789Z', 'ParseIso8601', '2024-07-31T19:05:47+00:00'],
['2024-07-31T19:05:47.1234567+02:00', 'ParseIso8601', '2024-07-31T19:05:47+02:00'],
['2024-07-31T19:05:47.12345678+02:00', 'ParseIso8601', '2024-07-31T19:05:47+02:00'],
['2024-07-31T19:05:47.123456789+02:00', 'ParseIso8601', '2024-07-31T19:05:47+02:00'],
['2024-07-31T19:05:47.1234567-05:00', 'ParseIso8601', '2024-07-31T19:05:47-05:00'],
['2024-07-31T19:05:47.12345678-05:00', 'ParseIso8601', '2024-07-31T19:05:47-05:00'],
['2024-07-31T19:05:47.123456789-05:00', 'ParseIso8601', '2024-07-31T19:05:47-05:00'],
['2024-07-31T19:05:47.1234567', 'ParseIso8601', '2024-07-31T19:05:47+00:00'],
['2024-07-31T19:05:47.12345678', 'ParseIso8601', '2024-07-31T19:05:47+00:00'],
['2024-07-31T19:05:47.123456789', 'ParseIso8601', '2024-07-31T19:05:47+00:00']
];
}

Expand Down

0 comments on commit 46c14c3

Please sign in to comment.