fix: emit full seconds in Instant and ZonedDateTime toISOString (RFC 3339)

Instant::toISOString() and ZonedDateTime::toISOString() emitted a compact
time that dropped zero seconds (e.g. 2023-11-14T22:14Z), which is valid
ISO 8601 but not valid RFC 3339. Section 5.6 of RFC 3339 requires the full
HH:MM:SS time even when the seconds are zero. These types are meant for
interoperability, so they must always emit RFC 3339 compliant output.

Build the time part of ZonedDateTime::toISOString() explicitly with a
mandatory seconds component instead of delegating to LocalTime's compact
formatter. Instant delegates to ZonedDateTime, so it is fixed transitively;
jsonSerialize() and __toString() route through toISOString(). LocalTime's
documented compact format is intentional and left unchanged.

This changes the serialized string representation and is therefore a BC
break; fixtures that pinned the compact output are updated accordingly.
This commit is contained in:
dualfroz committed 2026-09-06 01:04:05 +02:00
1 parent d37085b46a
commit 491e7ada29
5 files changed
+67 -36

No files matched your search

+7 -4
View File
@@ -573,11 +573,11 @@ class InstantTest extends AbstractTestCase
public static function providerGetIntervalTo(): array
{
return [
[1672567200, 0, 1672567200, 0, '2023-01-01T10:00Z/2023-01-01T10:00Z'],
[1672567200, 0, 1672567210, 0, '2023-01-01T10:00Z/2023-01-01T10:00:10Z'],
[1672567200, 0, 1672567200, 0, '2023-01-01T10:00:00Z/2023-01-01T10:00:00Z'],
[1672567200, 0, 1672567210, 0, '2023-01-01T10:00:00Z/2023-01-01T10:00:10Z'],
[1672567200, 1000000, 1672567210, 2000000, '2023-01-01T10:00:00.001Z/2023-01-01T10:00:10.002Z'],
[1672567200, 1, 1672567200, 9, '2023-01-01T10:00:00.000000001Z/2023-01-01T10:00:00.000000009Z'],
[1672567200, 0, 1672653600, 0, '2023-01-01T10:00Z/2023-01-02T10:00Z'],
[1672567200, 0, 1672653600, 0, '2023-01-01T10:00:00Z/2023-01-02T10:00:00Z'],
];
}
@@ -648,11 +648,14 @@ class InstantTest extends AbstractTestCase
[-2000000000, 0, '1906-08-16T20:26:40Z'],
[-1, 0, '1969-12-31T23:59:59Z'],
[-1, 123, '1969-12-31T23:59:59.000000123Z'],
[0, 0, '1970-01-01T00:00Z'],
[0, 0, '1970-01-01T00:00:00Z'],
[0, 123456, '1970-01-01T00:00:00.000123456Z'],
[1, 0, '1970-01-01T00:00:01Z'],
[1, 123456789, '1970-01-01T00:00:01.123456789Z'],
[2000000000, 0, '2033-05-18T03:33:20Z'],
// whole minute and whole hour must keep the full ":00" seconds (RFC 3339 section 5.6)
[1700000040, 0, '2023-11-14T22:14:00Z'],
[1700002800, 0, '2023-11-14T23:00:00Z'],
];
}