[PHP-DEV] Add ISO 8601 date format constant with millisecond precision

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

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:

     Add ISO 8601 date format constant with millisecond precision · Issue #23491 · php/php-src · GitHub

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:

     DateTime: Z not recognised as UTC (+00:00) · Issue #14593 · php/php-src · GitHub

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 |
+---------------------------------------------------------------------+

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ó:

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 |
±--------------------------------------------------------------------+

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:

      Add ISO 8601 date format constant with millisecond precision · Issue #23491 · php/php-src · GitHub

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:

      DateTime: Z not recognised as UTC (+00:00) · Issue #14593 · php/php-src · GitHub

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 |
+---------------------------------------------------------------------+

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: PHP: 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