Add ISO 8601 date format constant with millisecond precision

php.internals

Théo Attali

3 days ago
Hi ! Sorry derick for the duplicated email but I was not registered. This is my first contribution, so I would appreciate any help on the proposal and on following the project's contribution process. I opened issue #23491 for a possible addition to ext/date: https://github.com/php/php-src/issues/23491 I would appreciate feedback before preparing an implementation. PHP currently provides DATE_RFC3339_EXTENDED, which includes millisecond precision. For a UTC DateTime, it produces: 1970-01-01T00:00:00.000+00:00 Some applications need the equivalent representation with the ISO 8601 UTC designator Z: 1970-01-01T00:00:00.000Z This is also the format produced by JavaScript's Date.prototype.toISOString(): new Date(0).toISOString(); // "1970-01-01T00:00:00.000Z" Would a predefined format for this representation be appropriate for ext/date? One possible API would be: DATE_ISO8601_MILLISECONDS_UTC DateTimeInterface::ISO8601_MILLISECONDS_UTC with the format string: "Y-m-d\\TH:i:s.v\\Z" For example: $date = new DateTimeImmutable('@0'); echo $date->setTimezone(new DateTimeZone('UTC')) ->format(DATE_ISO8601_MILLISECONDS_UTC); // 1970-01-01T00:00:00.000Z The name and API shape are open for discussion. Another option would be an offset-preserving format: DATE_ISO8601_MILLISECONDS DateTimeInterface::ISO8601_MILLISECONDS using: "Y-m-d\\TH:i:s.vP" I understand that date format constants only define formatting; they do not change the timezone of the DateTime object. A format containing a literal Z would therefore require the caller to normalize the object to UTC first. For context, issue #14593 discusses the interpretation of the Z suffix when parsing DateTime values: https://github.com/php/php-src/issues/14593 That issue concerns parsing and timezone representation, whereas this proposal concerns predefined formatting constants. I would appreciate feedback on: 1. Whether a millisecond-precision format is useful in addition to DATE_RFC3339_EXTENDED. 2. Whether an offset-preserving format or a UTC-suffix format is preferable. 3. Whether the proposed names follow the preferred ext/date convention. 4. Whether an RFC is required before implementation. Thank you, Théo Attali

Andreas Heigl

3 days ago
Hey Théo On 29.08.26 11:47, Théo Attali wrote:
> Hi ! > > Sorry derick for the duplicated email but I was not registered. > > This is my first contribution, so I would appreciate any help on the > proposal and on following the project's contribution process. > > I opened issue #23491 for a possible addition to ext/date: > > https://github.com/php/php-src/issues/23491 > > I would appreciate feedback before preparing an implementation. > > PHP currently provides DATE_RFC3339_EXTENDED, which includes millisecond > precision. For a UTC DateTime, it produces: > > 1970-01-01T00:00:00.000+00:00 > > Some applications need the equivalent representation with the ISO 8601 UTC > designator Z: > > 1970-01-01T00:00:00.000Z > > This is also the format produced by JavaScript's > Date.prototype.toISOString(): > > new Date(0).toISOString(); > // "1970-01-01T00:00:00.000Z" > > Would a predefined format for this representation be appropriate for > ext/date? > > One possible API would be: > > DATE_ISO8601_MILLISECONDS_UTC > DateTimeInterface::ISO8601_MILLISECONDS_UTC > > with the format string: > > "Y-m-d\\TH:i:s.v\\Z" > > For example: > > $date = new DateTimeImmutable('@0'); > echo $date->setTimezone(new DateTimeZone('UTC')) > ->format(DATE_ISO8601_MILLISECONDS_UTC); > > // 1970-01-01T00:00:00.000Z > > The name and API shape are open for discussion. Another option would be an > offset-preserving format: > > DATE_ISO8601_MILLISECONDS > DateTimeInterface::ISO8601_MILLISECONDS > > using: > > "Y-m-d\\TH:i:s.vP" > > I understand that date format constants only define formatting; they do not > change the timezone of the DateTime object. > A format containing a literal Z would therefore require the caller to > normalize the object to UTC first. > > For context, issue #14593 discusses the interpretation of the Z suffix when > parsing DateTime values: > > https://github.com/php/php-src/issues/14593 > > That issue concerns parsing and timezone representation, whereas this > proposal concerns predefined formatting constants. > > I would appreciate feedback on: > > 1. Whether a millisecond-precision format is useful in addition to > DATE_RFC3339_EXTENDED. > 2. Whether an offset-preserving format or a UTC-suffix format is preferable. > 3. Whether the proposed names follow the preferred ext/date convention. > 4. Whether an RFC is required before implementation. > > Thank you, > > Théo Attali >
I see some serious issues with the idea of adding the format with the `\\Z` at the end as you already described. It would require a prerequisite that can'T be enforced and that will therefore cause a lot of confusion. To ease that confusion I would recommend anyone that has that explicit requirement to create a Formatter - perhaps tehr eeven is one already available that in essence just does something like this: class Formatter { public static function formatIso(DateTimeImmutable $date): string { return $date->setTimezone(new DateTimeZone('UTC'))->format('Y-m-d\\TH:i:s.vP'); } } Maintaining such a set of Formatters in Userland seems to be much easier than adding that in the PHP-Src. It would also make the formatter available to ALL PHP-Versions that have a DateTimeImmutable object and not only PHP8.6/8.7 onwards. From my side I would by now not add any more constants to the PHP-Source as they will not be available to earler versions. And I say that as the person that added the _EXTENDED constants... By now I would create a formatter in userland and promote that for usage as it's a small library that can be used by *any* PHP-Version that needs it. My 0.02€ Cheers Andreas
-- ,,, (o o) +---------------------------------------------------------ooO-(_)-Ooo-+ | Andreas Heigl | | mailto:andreas@heigl.org N 50°22'59.5" E 08°23'58" | | https://andreas.heigl.org | +---------------------------------------------------------------------+ | https://hei.gl/appointmentwithandreas | +---------------------------------------------------------------------+ | GPG-Key: https://hei.gl/keyandreasheiglorg | +---------------------------------------------------------------------+

Théo Attali

3 days ago
Hi Andreas, Thank you for your feedback. I agree that a format constant containing a literal Z is not ideal because the format string cannot enforce UTC. A userland formatter is safer because it can normalize the value before formatting it. After considering this, I think an instance method may be a better fit than a new format constant: $date->toISOString(); The method could normalize the instant to UTC and return exactly: 1970-01-01T00:00:00.000Z It would not modify the original object, which is particularly important for DateTimeImmutable. I also found that Carbon provides: $date->toIso8601ZuluString('millisecond'); However, that requires an external dependency. My motivation is to provide a dependency-free way to produce a common ISO 8601 UTC representation used when exchanging timestamps between PHP, JavaScript, Java, Go, and other ecosystems. I searched for an existing PHP issue or RFC proposing this exact method but found only the older, inactive DateTime::__toString() RFC, which addressed a different problem. Would you consider a UTC-normalizing instance method a more appropriate direction for this issue than adding a format constant? Best regards, Théo Attali El sáb, 29 ago 2026 a las 12:36, Andreas Heigl (<andreas@heigl.org>) escribió:

Andreas Heigl

3 days ago
Hey Théo On 29.08.26 18:04, Théo Attali wrote:
> Hi Andreas, > > Thank you for your feedback. > > I agree that a format constant containing a literal Z is not ideal because > the format string cannot enforce UTC. A userland formatter is safer because > it can normalize the value before formatting it. > > After considering this, I think an instance method may be a better fit than > a new format constant: > > $date->toISOString(); > > The method could normalize the instant to UTC and return exactly: > > 1970-01-01T00:00:00.000Z > > It would not modify the original object, which is particularly important for > DateTimeImmutable. > > I also found that Carbon provides: > > $date->toIso8601ZuluString('millisecond'); > > However, that requires an external dependency. My motivation is to provide > a dependency-free way to produce a common ISO 8601 UTC representation used > when exchanging timestamps between PHP, JavaScript, Java, Go, and other > ecosystems. > > I searched for an existing PHP issue or RFC proposing this exact method but > found only the older, inactive DateTime::__toString() RFC, which addressed > a different problem. > > Would you consider a UTC-normalizing instance method a more appropriate > direction for this issue than adding a format constant?
Well... PHP already *has* a dependency-free way to format any datetime-object into an ISO string: echo $anyDateTimeImmutable ->setTimezone(new DateTimeZone('UTC')) ->format('Y-m-d\\TH:i:s.vP'); If you want to avoid having to write that string all the time, feel free to do something like Interface IsoDateTime { const WITH_MILLISECONDS = 'Y-m-d\\TH:i:s.vP'; const JUST_SECONDS = 'Y-m-d\\TH:i:sP'; } and then call echo $anyDateTimeImmutable ->setTimezone(new DateTimeZone('UTC')) ->format(IsoDateTimeInterface::WITH_MILLISECONDS); That works since PHP5.3 Anything else is adding convenience at a cost. And for me (but I am just one person here on the list) that cost (limited availability to older versions, increasingly polluted constants, very specific use-case, possibly broken output due to wrong timezone) outweighs the benfits. Just my 0.02€ Cheers Andreas
> > Best regards, > > Théo Attali > > El sáb, 29 ago 2026 a las 12:36, Andreas Heigl (<andreas@heigl.org>) > escribió: > >> Hey Théo >> >> On 29.08.26 11:47, Théo Attali wrote: >>> Hi ! >>> >>> Sorry derick for the duplicated email but I was not registered. >>> >>> This is my first contribution, so I would appreciate any help on the >>> proposal and on following the project's contribution process. >>> >>> I opened issue #23491 for a possible addition to ext/date: >>> >>> https://github.com/php/php-src/issues/23491 >>> >>> I would appreciate feedback before preparing an implementation. >>> >>> PHP currently provides DATE_RFC3339_EXTENDED, which includes millisecond >>> precision. For a UTC DateTime, it produces: >>> >>> 1970-01-01T00:00:00.000+00:00 >>> >>> Some applications need the equivalent representation with the ISO 8601 >> UTC >>> designator Z: >>> >>> 1970-01-01T00:00:00.000Z >>> >>> This is also the format produced by JavaScript's >>> Date.prototype.toISOString(): >>> >>> new Date(0).toISOString(); >>> // "1970-01-01T00:00:00.000Z" >>> >>> Would a predefined format for this representation be appropriate for >>> ext/date? >>> >>> One possible API would be: >>> >>> DATE_ISO8601_MILLISECONDS_UTC >>> DateTimeInterface::ISO8601_MILLISECONDS_UTC >>> >>> with the format string: >>> >>> "Y-m-d\\TH:i:s.v\\Z" >>> >>> For example: >>> >>> $date = new DateTimeImmutable('@0'); >>> echo $date->setTimezone(new DateTimeZone('UTC')) >>> ->format(DATE_ISO8601_MILLISECONDS_UTC); >>> >>> // 1970-01-01T00:00:00.000Z >>> >>> The name and API shape are open for discussion. Another option would be >> an >>> offset-preserving format: >>> >>> DATE_ISO8601_MILLISECONDS >>> DateTimeInterface::ISO8601_MILLISECONDS >>> >>> using: >>> >>> "Y-m-d\\TH:i:s.vP" >>> >>> I understand that date format constants only define formatting; they do >> not >>> change the timezone of the DateTime object. >>> A format containing a literal Z would therefore require the caller to >>> normalize the object to UTC first. >>> >>> For context, issue #14593 discusses the interpretation of the Z suffix >> when >>> parsing DateTime values: >>> >>> https://github.com/php/php-src/issues/14593 >>> >>> That issue concerns parsing and timezone representation, whereas this >>> proposal concerns predefined formatting constants. >>> >>> I would appreciate feedback on: >>> >>> 1. Whether a millisecond-precision format is useful in addition to >>> DATE_RFC3339_EXTENDED. >>> 2. Whether an offset-preserving format or a UTC-suffix format is >> preferable. >>> 3. Whether the proposed names follow the preferred ext/date convention. >>> 4. Whether an RFC is required before implementation. >>> >>> Thank you, >>> >>> Théo Attali >>> >> I see some serious issues with the idea of adding the format with the >> `\\Z` at the end as you already described. It would require a >> prerequisite that can'T be enforced and that will therefore cause a lot >> of confusion. >> >> To ease that confusion I would recommend anyone that has that explicit >> requirement to create a Formatter - perhaps tehr eeven is one already >> available that in essence just does something like this: >> >> class Formatter >> { >> public static function formatIso(DateTimeImmutable $date): string >> { >> return $date->setTimezone(new >> DateTimeZone('UTC'))->format('Y-m-d\\TH:i:s.vP'); >> } >> } >> >> Maintaining such a set of Formatters in Userland seems to be much easier >> than adding that in the PHP-Src. It would also make the formatter >> available to ALL PHP-Versions that have a DateTimeImmutable object and >> not only PHP8.6/8.7 onwards. >> >> From my side I would by now not add any more constants to the >> PHP-Source as they will not be available to earler versions. And I say >> that as the person that added the _EXTENDED constants... >> >> By now I would create a formatter in userland and promote that for usage >> as it's a small library that can be used by *any* PHP-Version that needs >> it. >> >> My 0.02€ >> >> Cheers >> >> Andreas >> -- >> ,,, >> (o o) >> +---------------------------------------------------------ooO-(_)-Ooo-+ >> | Andreas Heigl | >> | mailto:andreas@heigl.org N 50°22'59.5" E 08°23'58" | >> | https://andreas.heigl.org | >> +---------------------------------------------------------------------+ >> | https://hei.gl/appointmentwithandreas | >> +---------------------------------------------------------------------+ >> | GPG-Key: https://hei.gl/keyandreasheiglorg | >> +---------------------------------------------------------------------+ >> >> >
-- ,,, (o o) +---------------------------------------------------------ooO-(_)-Ooo-+ | Andreas Heigl | | mailto:andreas@heigl.org N 50°22'59.5" E 08°23'58" | | https://andreas.heigl.org | +---------------------------------------------------------------------+ | https://hei.gl/appointmentwithandreas | +---------------------------------------------------------------------+ | GPG-Key: https://hei.gl/keyandreasheiglorg | +---------------------------------------------------------------------+

Tim Düsterhus

1 day ago
Hi On 2026-08-29 11:47, Théo Attali wrote:
> I would appreciate feedback on: > > 1. Whether a millisecond-precision format is useful in addition to > DATE_RFC3339_EXTENDED. > 2. Whether an offset-preserving format or a UTC-suffix format is > preferable. > 3. Whether the proposed names follow the preferred ext/date convention. > 4. Whether an RFC is required before implementation.
There are some long-standing plans to introduce a new date and time API and with PHP 8.6 the first part of it will ship: https://wiki.php.net/rfc/duration_class. I believe at this point it may be more useful to focus on continuing shipping a new API than to add even more stuff to the existing API. As an example, the proposed Time\Instant is intentionally timezone-less and an ISO 8601 string with the Z timezone would be an obvious method to add there. Best regards Tim Düsterhus