Hi Tim,
> On 29.10.2026 14:39 CET Tim Düsterhus <[email protected]> wrote:
>
>
> Hi
>
> Due to the security releases it's been a while since I last looked into
> this RFC and I probably lost some of my working memory. Please indicate
> if there is something obvious that I missed somewhere or similar.
>
> On 2026-10-06 11:17, [email protected] wrote:
> > 3. Clock resolution
> >
> [...]
>
> … but we can see how exposing the (nominal) resolution of specifically
> the SystemClock can be useful. I assume that a
> `SystemClock::getNominalResolution(): Duration` with the `Duration`
> being the greatest common divisor of possible returned values is what
> you would expect? [...]
Yes, that’s exactly what I would expect. Thanks for adding it to the future
scope.
>
> > 5. Taking a Unix timestamp directly from a clock
> >
> > Unix timestamps are used everywhere, not only in PHP, so "current time
> > as a Unix timestamp" is a very common operation. Today that's time(),
> > which can't be mocked. With this RFC the mockable replacement is
> > $clock->now()->getUnixTimestamp(), which always goes through an Instant
> > object. I'd like a way to take the Unix timestamp directly from the
> > clock.
>
> Our goal with this RFC series is to provide a well-designed and
> well-typed new API that nudges the user to do the right thing. Making
> “raw integers” a first class citizen would go against that goal to save
> 7 characters (and one object creation). The previous arguments against
> adding a `takeZonedDateTime()` or similar also apply here.
This isn’t about saving characters. Software reads the current timestamp all
the time and for many reasons, so that call should be as cheap as possible.
With the proposed API, getting the Unix timestamp integer means creating an
Instant object and making one more method call, only to get back the integer
the system already returned in the first place.
>
> >
> > 8. getUnixTimestamp() / getUnixTimestampMilliseconds()
> >
> > Only the milliseconds variant names its unit, and microseconds (used
> > all
> > over PHP: microtime(), DateTime) and nanoseconds are missing entirely.
> > A
> > single pair taking the unit as an argument would cover all of them and
> > stay symmetric:
>
> The `toUnixTimestamp()` + `getNanoseconds()` pair is the canonical
> representation of a Unix timestamp - with “seconds” also being arguably
> by far the most common interpretation when hearing “Unix timestamp”. The
> “milliseconds” variant is provided for interoperability convenience, in
> particular with JavaScript.
I find it odd to give milliseconds a dedicated method just because one other
language uses them as its main Unix timestamp resolution. And JavaScript
doesn’t even use an integer there - it's a floating point. The result is an API
that looks inconsistent: seconds and milliseconds are covered, microseconds and
nanoseconds are not.
>
> PHP’s existing `DateTime` does not provide functionality to obtain the
> timestamp as an integral number of microseconds, and `microtime()`
> either returns a `float` or a weird two-component pair as a string. I am
> not aware of anything commonly used that returns “integral microseconds
> since the Unix epoch”, do you know of anything?
Microseconds are the finest resolution in a lot of what PHP applications work
with every day:
* PHP itself: DateTime/DateTimeImmutable, microtime()
* MySQL/MariaDB: DATETIME/TIMESTAMP with up to 6 fractional digits
* PostgreSQL: timestamp/timestamptz
* Apache Spark: TIMESTAMP
* Python: datetime/timedelta
>
> > public static function fromUnixTimestamp(int $timestamp, TimeUnit
> > $unit = TimeUnit::Second): self;
> > public function toUnixTimestamp(TimeUnit $unit = TimeUnit::Second):
> > int;
> >
> > TimeUnit would be an enum of Second, Millisecond, Microsecond and
> > Nanosecond, rounding towards negative infinity as already specified.
> > The
>
> I do not find it obvious at all that “seconds” would be the largest
> supported unit of a `TimeUnit`.
Agreed, it isn’t really a time unit. What about something like FractionUnit or
SecondUnit, so that the name makes clear it covers seconds and their fractions
only?
>
> > 10. Concepts the ISO-8601 pair brings into Instant
> >
> > An Instant is described as a timezone-less point in time. The ISO-8601
> > constructor and getter bring in several concepts that Instant otherwise
> > deliberately avoids:
> >
> > a) parsing and formatting of date-time strings;
> > b) UTC as the reference ("Z" means a zero offset from UTC; since RFC
> > 9557 it formally means "UTC known, local offset unknown");
> > c) a calendar: ISO 8601 uses the proleptic Gregorian calendar with
> > year
> > 0000;
> > d) an opinionated input and output format
>
> Yes. I don't understand what you are getting at, though. There clearly
> has to be a way to represent a point in time in some way - and an
> ISO-8601 datetime string is one of the possible options, probably the
> most widely used one. The Unix timestamp is another one.
The RFC defines Instant as "an absolute point on the timeline of the universe".
It also says the timeline of the universe "does not know about days or months".
An ISO-8601 string is made of exactly those things: a calendar (years, months,
days) and an offset from UTC. Both belong to the Earth, not to the timeline of
the universe.
The Unix timestamp is different in nature. It is the distance from one point in
time to another. Any point on the timeline of the universe needs at least one
reference point to be expressed.
I see why the ISO-8601 representation is convenient, and I have never had to
represent a time outside Earth myself. But is it really the right thing to do?
At the very least, it conflicts with the definition of Instant.
>
> > 11. The accepted input grammar
> >
> > The RFC says the parser is strict but "may not support all legal
> > formats",
> > and that accepted formats can be extended "by a simple pull request".
> > That
> > means the vote doesn't decide the accepted grammar. Widening it later
> > is
> > also not BC-neutral for code that uses the parser as a validator. I'd
> > like
>
> Since the RFC guarantees that only legal formats will be accepted, you
> are able to use it as a validator. If your use case requires narrower
> validation, then you will need to perform custom validation according to
> whatever specification you are dealing with. This is not unique to the
> Instant class.
My concern is the wording in the RFC: “It will only accept well-formed inputs,
but may not support all legal formats” is very vague. It doesn’t say which
legal formats are not supported, and I think that should be written out
explicitly. ...
>
> > the RFC to specify the grammar explicitly and to state the outcome for
> > the
> > cases Ilia listed: comma decimal sign, lowercase t/z, space separator,
> > -00:00, 24:00:00, 23:59:60, more than 9 fractional digits.
>
> See my reply to Ilia (https://news-web.php.net/php.internals/132764).
> The RFC changes are still open.
... OK
>
> > A related point:
> > the docblock requires "a zone offset" while the prose requires "a
> > timezone". Is an RFC 9557 suffix such as [Europe/Berlin] accepted,
> > rejected or ignored?
>
> Thanks, I adjusted the prose to also require a “zone offset”.
>
> > 12. The output format
> >
> > The getter always emits Z, has a fractional part whose width depends on
> > the value (omitted when zero, otherwise 9 digits), and uses signed
> > expanded years outside 0000-9999.
> >
> > You mentioned that the getter implements the RFC 3339 subset of
> > ISO-8601.
> > That is not quite true: RFC 3339 only allows 4-digit years 0000-9999,
> > so the output isn't RFC 3339 for expanded years.
>
> That is a bit of a distinction without difference: RFC 3339 is only
> capable of representing years 0000 to 9999, so years outside of that
> range are by definition not representable as RFC 3339. The ISO-8601
> getter specifically only switches to the expanded format outside that
> range. Adding a separate RFC 3339 getter that differs only by throwing
> an Exception for unrepresentable instants does not sound useful, since
> this Exception is not actionable in any way.
I did not ask for a separate RFC 3339 getter. I only wanted to point out that
the output of toIso8601DateTimeString() does not conform to RFC 3339 in all
cases - not more.
>
> > I also tested how well the possible outputs work as input for the
> > existing
> > DateTime API (PHP 8.5):
> >
> > - new DateTimeImmutable($s) accepts all of them, but truncates the 9
> > fractional digits to 6 without notice.
> > - With createFromFormat() no single format string works. DATE_ATOM
> > only
> > matches whole seconds with 4-digit years. DATE_RFC3339_EXTENDED
> > (.v,
> > 3 digits) never matches. 'Y-m-d\TH:i:s.uP' fails on 9 digits
> > because
> > 'u' takes at most 6, so you need a hack like 'Y-m-d\TH:i:s.u???P'.
> > Expanded years need 'X' instead of 'Y'.
> >
> > Because the fractional part is only present for some values, any strict
> > consumer needs at least two format strings and has to choose between
> > them,
> > which is the trap Ilia described. An output that always includes the
> > fractional part would at least make 'X-m-d\TH:i:s.u???P' work for every
> > value.
>
> I do not believe that the existing `DateTime` API is a model of good
> design in that regard (and there are better ways for interoperability
> with it, as noted in https://news-web.php.net/php.internals/132761).
> Only taking a fixed format is already a problem as of now, because
> “conditionally omitting the fractional part” is common.
A lot of code depends on the existing DateTime API, so there should be a simple
way to convert in both directions. The RFC already adds
DateTimeInterface::toInstant(). Why not also add the reverse, e.g.
DateTimeImmutable::createFromInstant() / DateTime::createFromInstant()?
>
> >
> > 13. A dedicated parser/formatter instead
> >
> > I'd prefer parsing and formatting to live in a dedicated
> > parser/formatter
> > API (future scope) rather than on Instant, where it would sit next to
> > the
> > other ISO-8601 profiles and custom patterns. If the pair stays on
> > Instant,
> > the name should say what it really is (a fixed RFC 3339-like profile),
> > and
> > the grammar should be part of what we vote on.
>
> I agree with Larry’s DX argument here. I'd also like to note that the
> *output* format is fixed by the RFC. The input format is less
> constrained, but the RFC guarantees that it stays true to its name by
> only accepting what ISO-8601 specifies.
About DX - the simplicity comes from having a dedicated function to
parse/format to/from ISO-8601/Instant without having to instantiate or
configure anything - which is a good argument but this can be solved
differently as well without introducing concepts to Instant it is not designed
for e.g. by proving helper functions `Time\parseIso8601DateTimeToInstant´,
`Time\instantToIso8601DateTime`.
>
> >
> > 14. until() vs Duration::between()
> >
> > Was Duration::between(Instant $a, Instant $b) considered? Calculating a
> > duration feels like Duration's responsibility to me.
>
> That suggestion breaks down when measuring elapsed time with a monotonic
> clock. PHP does not support method overloading, so it would need to
> become `Duration::between(Instant|MonoInstant, Instant|MonoInstant)`
> which then also allows non-sense combinations.
mh true
Thanks,
Marc Bennewitz