# [RFC] Time\Instant and Time\Clock

- Thread: https://externals.io/message/132588
- Original archive: https://news-web.php.net/php.internals/132588
- Started by tim@bastelstu.be on 2026-09-22T14:20:19+00:00
- Messages: 44
- RFC: Time\Instant and Time\Clock (Under discussion) — https://externals.io/rfc/time_instant_class.md
- Page 1 of 2: messages 1 to 25 (25 per page, add `?page=N` to the URL)
- Next page: https://externals.io/message/132588.md?page=2
- Reply by email to internals@lists.php.net
- More for agents: search with https://externals.io/search.md?q={query} · RFCs at https://externals.io/rfc.md · JSON API at https://externals.io/api · documentation at https://externals.io/llms.txt

---

## #132588 — tim@bastelstu.be — 2026-09-22T14:20:19+00:00

URL: https://externals.io/message/132588#132588

Hi

following Time\Duration in PHP 8.6, Derick and I created an RFC for 
Time\Instant and Time\Clock as the next part of the new date and time 
API:

https://wiki.php.net/rfc/time_instant_class

This time we have several months until the next feature freeze, so 
there’s place to discuss additional functionality that we missed. 
Nevertheless we would like to keep the RFC focused so that every 
decision gets the attention it deserves and some bits are already listed 
as “Future Scope” to that effect.

Best regards
Tim Düsterhus

---

## #132590 — Andreas Heigl — 2026-09-22T14:54:23+00:00

URL: https://externals.io/message/132588#132590 · In reply to: #132588

Hey Tim, Hey Derick


> Hi
>
> following Time\Duration in PHP 8.6, Derick and I created an RFC for Time\Instant and Time\Clock as the next part of the new date and time API:
>
> https://wiki.php.net/rfc/time_instant_class
>
> This time we have several months until the next feature freeze, so there’s place to discuss additional functionality that we missed. Nevertheless we would like to keep the RFC focused so that every decision gets the attention it deserves and some bits are already listed as “Future Scope” to that effect.

Thanks for the proposal.

I do see some clashes within the proposal though:

Right at the start you are mentioning that "An Time\Instant carries no timezone. It represents a unique point on the timeline of the universe. This point is the same for everyone, no matter where they are located on the Earth (or not on Earth at all), i.e. no matter their timezone."

I am totally in favour of that!

Later on though you are mentioning that "Following the lead of virtually all programming languages and operating systems, leap seconds are ignored."

Is that only with relation to the Iso8601 strings? Or is that a general shortcoming?

The other point I find irritating is the naming of the `Clock` interface. While I can understand the reasoning behind it I see irritation in the community upcoming as the `CLockInterface` now suddenly returns 2 different things, depending on which ClockInterface people are talking about.

Is there a way to Unify the ideas behind Time\Clock and Psr\Clock\CLockInterface?

As right now the Time\Clock is not a direct replacement of Psr\Clock\ClockInterface as - at the current time - there is no way to generate a DateTimeImmutable directly from a Time\Instant.

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

---

## #132591 — Seifeddine Gmati — 2026-09-22T15:14:03+00:00

URL: https://externals.io/message/132588#132591 · In reply to: #132588

>
> Hi
>
> following Time\Duration in PHP 8.6, Derick and I created an RFC for
> Time\Instant and Time\Clock as the next part of the new date and time
> API:
>
> https://wiki.php.net/rfc/time_instant_class
>
> This time we have several months until the next feature freeze, so
> there’s place to discuss additional functionality that we missed.
> Nevertheless we would like to keep the RFC focused so that every
> decision gets the attention it deserves and some bits are already listed
> as “Future Scope” to that effect.
>
> Best regards
> Tim Düsterhus

Hi Tim,

Thanks for putting this together. I have a few suggestions about
naming, obtaining the current time, and the clock implementations.

Could we name the proposed class `Time\SystemTime` and reserve
`Time\Instant` for a future high-resolution monotonic clock API? Rust
uses this distinction, and I find it helpful:
[`SystemTime`](https://doc.rust-lang.org/std/time/struct.SystemTime.html)
represents wall-clock time, which can change following clock
corrections, while
[`Instant`](https://doc.rust-lang.org/std/time/struct.Instant.html)
represents monotonic time, suitable for measuring elapsed time,
benchmarking, etc.

I appreciate that monotonic time is explicitly left to future scope.
I’m suggesting we settle the naming with both concepts in mind now,
without necessarily introducing both in this RFC. This is also the
distinction I use in Whim's
[Instant](https://github.com/carthage-software/whim/blob/main/lib/src/Time/Instant.whim)
and [SystemTime](https://github.com/carthage-software/whim/blob/main/lib/src/Time/SystemTime.whim)
types for reference.

I would also like to see a static `SystemTime::now()` factory, and
eventually `Instant::now()` for monotonic time. I understand the
rationale for an injectable clock, but I think the two approaches can
coexist. When I simply need the current time, I would prefer:

```php
$time = SystemTime::now();
```

Having to instantiate a clock, or pass one through several layers of
an existing application for an occasional time read, feels
unnecessarily cumbersome. People who need control over time can use an
injected clock; callers using the static factory would knowingly give
up that control. Is there a reason to exclude the convenience API?

Also, If we are adding `now` static method, I think adding
[`elapsed()`](https://doc.rust-lang.org/src/std/time.rs.html#660-662)
would also be helpful. ( a shorter way of doing
`InstantOrSystemTime::now()->durationSince($this)` ).

Finally, I would reconsider including `FrozenClock` and `OffsetClock`.
The RFC notes that specialised clocks can have different behaviours,
but these two seem useful and sufficiently well-defined:

- `FrozenClock` takes a time value and always returns that value. (
potentionally with `advance(Duration $duration): void` and
`travelTo(SystemTime $moment): void` )
- `OffsetClock` takes another clock and a duration, and returns the
wrapped clock’s current time plus that duration.

More elaborate behaviour could remain in userland. For these basic
implementations, though, I don’t see much ambiguity in either the API
or the semantics. Including them would save users from repeatedly
implementing the same small classes or adding a Packagist dependency
for them, and would make the clock abstraction useful out of the box
for testing.

Best regards,
Seifeddine

---

## #132594 — tim@bastelstu.be — 2026-09-22T16:20:49+00:00

URL: https://externals.io/message/132588#132594 · In reply to: #132591

Hi

Replying with my personal opinion, not as the RFC author (since I didn't 
discuss this reply with Derick).


> Could we name the proposed class `Time\SystemTime` and reserve
> `Time\Instant` for a future high-resolution monotonic clock API? Rust
> uses this distinction, and I find it helpful:
> [`SystemTime`](https://doc.rust-lang.org/std/time/struct.SystemTime.html)
> represents wall-clock time, which can change following clock
> corrections, while
> [`Instant`](https://doc.rust-lang.org/std/time/struct.Instant.html)
> represents monotonic time, suitable for measuring elapsed time,
> benchmarking, etc.

The proposed naming is consistent with JavaScript’s Temporal 
(https://developer.mozilla.org/de/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Instant) 
and Java’s java.time 
(https://docs.oracle.com/javase/8/docs/api/java/time/Instant.html), 
which are the primary sources of reference we used.

I also believe that “real world time” and instead of “monotonic” time 
will be the primary use case and would thus prefer the simpler (and more 
widely used) name for that.

> I appreciate that monotonic time is explicitly left to future scope.
> I’m suggesting we settle the naming with both concepts in mind now,
> without necessarily introducing both in this RFC. This is also the

I agree that naming should be taken into account as part of this RFC, 
similarly how we already decided on Duration::divideInto(), despite not 
yet shipping it.

> I would also like to see a static `SystemTime::now()` factory, and
> eventually `Instant::now()` for monotonic time. I understand the
> rationale for an injectable clock, but I think the two approaches can
> coexist. When I simply need the current time, I would prefer:
> 
> ```php
> $time = SystemTime::now();
> ```
> 
> Having to instantiate a clock, or pass one through several layers of
> an existing application for an occasional time read, feels
> unnecessarily cumbersome. People who need control over time can use an
> injected clock; callers using the static factory would knowingly give
> up that control. Is there a reason to exclude the convenience API?

For the monotonic timer having a single static constructor definitely 
makes sense to me, because the use cases are much different and you 
can't meaningfully mock it anyway.

For the real world clock, I think I would want to nudge users towards 
“doing the right thing” and use an injectable factory and therefore now 
provide the static factory, but I don't have particularly strong 
opinions regarding that. I don't think it should be a static method on 
the `Instant` class, though, because that would intimately tie it to the 
`SystemClock`, which feels wrong. The correct approach would probably be 
a `Time\now(): Instant` function.

(Note: Please keep the RFC terminology in discussion of topics that are 
not about changing the terminology, seeing SystemTime in your example 
was very confusing since the RFC also has SystemClock.)

> Also, If we are adding `now` static method, I think adding
> [`elapsed()`](https://doc.rust-lang.org/src/std/time.rs.html#660-662)
> would also be helpful. ( a shorter way of doing
> `InstantOrSystemTime::now()->durationSince($this)` ).

Similarly, I can see that being a first class citizen for the monotonic 
timer (since the prime use case is measuring elapsed time), but not so 
much for the real world clock, where measuring elapsed time is just one 
operation of many.

> Finally, I would reconsider including `FrozenClock` and `OffsetClock`.
> The RFC notes that specialised clocks can have different behaviours,
> but these two seem useful and sufficiently well-defined:
> 
> - `FrozenClock` takes a time value and always returns that value. (
> potentionally with `advance(Duration $duration): void` and
> `travelTo(SystemTime $moment): void` )
> - `OffsetClock` takes another clock and a duration, and returns the
> wrapped clock’s current time plus that duration.

I would be open to doing those two as an (immediate) follow-up, since I 
feel they have plenty of bike-shedding potential on their own. So they 
would also land in PHP 8.7, but not distract from the main API design.

Best regards
Tim Düsterhus

---

## #132595 — Seifeddine Gmati — 2026-09-22T16:51:11+00:00

URL: https://externals.io/message/132588#132595 · In reply to: #132594

Hi Tim,

Thanks for the response.

> The proposed naming is consistent with JavaScript’s Temporal
> (https://developer.mozilla.org/de/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Instant)
> and Java’s java.time
> (https://docs.oracle.com/javase/8/docs/api/java/time/Instant.html),
> which are the primary sources of reference we used.
>
> I also believe that “real world time” and instead of “monotonic” time
> will be the primary use case and would thus prefer the simpler (and more
> widely used) name for that.

I think the JavaScript and Java background explains why I found the
naming confusing. `Instant` may feel natural for wall-clock time to
developers familiar with Java, and perhaps JavaScript, although
`Temporal` is still relatively new. Because i work more with Rust,
where `Instant` specifically represents monotonic time and
`SystemTime` represents wall-clock time.

I agree that wall-clock time will be used more often, but I’m not
convinced that `Instant` is necessarily simpler or clearer than
`SystemTime`. Arguably, the latter communicates more directly that the
value comes from the system clock and is subject to clock adjustments.
That said, let’s see what Derick and others think about the naming.

> For the real world clock, I think I would want to nudge users towards
> “doing the right thing” and use an injectable factory and therefore now
> provide the static factory, but I don't have particularly strong
> opinions regarding that. I don't think it should be a static method on
> the `Instant` class, though, because that would intimately tie it to the
> `SystemClock`, which feels wrong. The correct approach would probably be
> a `Time\now(): Instant` function.

Regarding nudging users towards “doing the right thing,” I don’t think
injecting a clock is always the right choice. It is valuable when the
code needs deterministic control over time, but sometimes keeping
things simple is preferable. For an occasional time read, passing a
clock through several layers can add ceremony without providing much
practical benefit. I think a direct API and injectable clocks can
coexist without suggesting that either should be used universally.

A `Time\now()` function would address the convenience issue, although
I still think discoverability is better when the operation is
available directly on the relevant type. But I don't have a strong
opinion here.

> > […]
>
> Similarly, I can see that being a first class citizen for the monotonic
> timer (since the prime use case is measuring elapsed time), but not so
> much for the real world clock, where measuring elapsed time is just one
> operation of many.

I also see some value in `elapsed()` for wall-clock instants, even
though I agree that it is more useful and reliable with a monotonic
clock. For example, I might use something like this for quick
debugging or logging:

```php
$startedAt = Instant::now();

$result = evaluate_expression($expr);

fwrite(STDERR, 'Took ' . $startedAt->elapsed());
```

For this kind of informal measurement, I may not need the stronger
guarantees of a monotonic clock. The operation would, of course,
remain subject to wall-clock adjustments. Rust returns an error if the
clock moves backwards; PHP could throw an exception in that case. I’m
not strongly attached to including this method for wall-clock time,
but I do think it has plausible uses.

> > […]
>
> I would be open to doing those two as an (immediate) follow-up, since I
> feel they have plenty of bike-shedding potential on their own. So they
> would also land in PHP 8.7, but not distract from the main API design.

I’m fine with leaving `FrozenClock` and `OffsetClock` to an immediate
follow-up RFC. My only concern is the current wording that test clocks
are better left to userland because their behaviour varies widely.
That argument could later be used against adding even these
well-defined clocks to the standard library. Perhaps they could
instead be mentioned explicitly under “Future Scope,” without
committing this RFC to their exact APIs.

Best regards,
Seifeddine

---

## #132596 — tim@bastelstu.be — 2026-09-22T17:26:25+00:00

URL: https://externals.io/message/132588#132596 · In reply to: #132595

Hi


> I agree that wall-clock time will be used more often, but I’m not
> convinced that `Instant` is necessarily simpler or clearer than
> `SystemTime`. Arguably, the latter communicates more directly that the
> value comes from the system clock and is subject to clock adjustments.
> That said, let’s see what Derick and others think about the naming.

Yes, `Instant` is clearer than `SystemTime`, because of the `Time` 
suffix that implies “time as shown on a clock”, which is *not* what the 
proposed `Instant` represents: Namely a point on the timeline of the 
universe. Other names that I've seen used for this concept are 
“Timestamp” or “Moment”, with “Instant” being the most widely used in 
the references we looked at.

Specifically, as part of future scope we're also planning for “Date” and 
“Time” classes that represent a calendar date (year, month, day) and a 
“clock time” (hour, minute, second, fractional second) respectively. 
Java calls these LocalDate and LocalTime. Calling the “point in time” 
class “SystemTime” would invite confusion with whatever the “clock time” 
object would be.

> A `Time\now()` function would address the convenience issue, although
> I still think discoverability is better when the operation is
> available directly on the relevant type. But I don't have a strong
> opinion here.

Java has an overloaded Instant.now() and Instant.now(Clock) where the 
parameter-less version defaults to the system clock. That would 
theoretically work for PHP, but I feel that a free-standing function 
matches PHP’s existing API design and capabilities better (Java doesn't 
have bare functions, unless that changed since I last looked at it).

> I also see some value in `elapsed()` for wall-clock instants, even
> though I agree that it is more useful and reliable with a monotonic
> clock. For example, I might use something like this for quick
> debugging or logging:
> 
> ```php
> $startedAt = Instant::now();
> 
> $result = evaluate_expression($expr);
> 
> fwrite(STDERR, 'Took ' . $startedAt->elapsed());
> ```
> 
> For this kind of informal measurement, I may not need the stronger
> guarantees of a monotonic clock. The operation would, of course,
> remain subject to wall-clock adjustments. Rust returns an error if the
> clock moves backwards; PHP could throw an exception in that case. I’m
> not strongly attached to including this method for wall-clock time,
> but I do think it has plausible uses.

The monotonic clock would not be much more complicated. Using the 
hypothetical name “Stopwatch”, it could be:

     $watch = Stopwatch::start();
     // …
     echo "Took ", $watch->elapsed();

In fact using Stopwatch as the name might allow for a nice API where a 
method could store “named round timers” as an array. Something like:

     $start = Stopwatch::start();
     prepare();
     $start->snapshot('preparation');
     execute();
     $start->snapshot('execution');
     var_dump($start->snapshots);

Where the 'execution' snapshot would be measured starting from the 
'preparation' snapshot. Or even:

     $duration = Stopwatch::measure(execute(...));

to measure a single function call.

> > […]
> 
> I’m fine with leaving `FrozenClock` and `OffsetClock` to an immediate
> follow-up RFC. My only concern is the current wording that test clocks
> are better left to userland because their behaviour varies widely.
> That argument could later be used against adding even these
> well-defined clocks to the standard library. Perhaps they could
> instead be mentioned explicitly under “Future Scope,” without
> committing this RFC to their exact APIs.

Fair enough. I'll put rephrasing that paragraph on my list to discuss 
with Derick for the next RFC update.

Best regards
Tim Düsterhus

---

## #132597 — Juris Evertovskis — 2026-09-22T19:31:30+00:00

URL: https://externals.io/message/132588#132597 · In reply to: #132595

> I agree that wall-clock time will be used more often, but I’m not
> convinced that `Instant` is necessarily simpler or clearer than
> `SystemTime`. Arguably, the latter communicates more directly that the
> value comes from the system clock and is subject to clock adjustments.
> That said, let’s see what Derick and others think about the naming.

Hi!

Is this not an argument FOR `Instant` instead of against it?

`SystemTime` sounds more like something that would belong in that `Clock
namespace while `Instant` represents a point in time that might well be
far before or after the existence of the system itself. It does not
advertise any relation to the system or wall clock. It could be the time
of the big bang. Naming it `SystemTime` wouldn't make any sense.

BR,
Juris

---

## #132600 — tim@bastelstu.be — 2026-09-23T10:24:57+00:00

URL: https://externals.io/message/132588#132600 · In reply to: #132590

Hi


> Later on though you are mentioning that "Following the lead of 
> virtually all programming languages and operating systems, leap seconds 
> are ignored."
> 
> Is that only with relation to the Iso8601 strings? Or is that a general 
> shortcoming?

Leap seconds are treated as non-existent as an integral part of the 
class design. Operating systems, in particular Unix-based systems as the 
arguably most common runtime environment of PHP, don't expose leap 
seconds in their time retrieval APIs and pretend very hard that leap 
seconds don't exist, either by “halting the clock” for 1 second, by 
repeating the second, or by smearing the leap second over a larger 
time-frame of “slightly more than a second”-seconds (e.g. across the 
preceding 1000 seconds as proposed by UTC-SLS).

Trying to support leap seconds in PHP when the operating system does not 
would mean that PHP would need to keep its own list of when a leap 
second should have occurred and would require users to actually update 
PHP to get correct information (which is something that most certainly 
won't happen).

It would necessarily also mean that the difference between two Instant’s 
->getUnixTimestamp() values would differ from the duration returned by 
`until()` and that two Instants with the same Unix timestamps might 
compare unequal.

Given that virtually everyone ignores leap seconds and given that there 
hasn't been one for the past 10 years and there are plans to abolish 
them by 2035, I don't think it is useful to make PHP in any way special. 
This would just invite bug reports from confused users.

So no shortcoming, intentional and deliberate design decision. The 
“unique point on the timeline” phrasing is to establish a reasonable 
mental model of why Instants don’t have a timezone and why this is a 
useful concept, not as a 100% accurate representation of physics.

> The other point I find irritating is the naming of the `Clock` 
> interface. While I can understand the reasoning behind it I see 
> irritation in the community upcoming as the `CLockInterface` now 
> suddenly returns 2 different things, depending on which ClockInterface 
> people are talking about.

While it doesn't seem to be written down as policy - but I could swear 
this topic came up on Internals at least - PHP doesn't use the 
`Interface` suffix to indicate interfaces in newly designed APIs. 
Following the precedent established by ext/random in PHP 8.2 with 
Random\Engine, the interface is the bare name and the concrete 
implementations sit in a sub-namespace named after the interface.

Thus there is a clear difference in naming even for the unqualified 
interface name.

> Is there a way to Unify the ideas behind Time\Clock and 
> Psr\Clock\CLockInterface?

The proposed new date/time API is a greenfield design to fix issues with 
the existing API. We deliberately don't want to “infect” the new API 
with ideas from the legacy API and returning an object carrying a 
timezone from a clock, as done in PSR-20, is the wrong design. `now()` 
is the obvious name for the method and that's why the RFC indicates that 
an adapter is required to satisfy both interfaces from the same source 
of truth during the migration phase.

> As right now the Time\Clock is not a direct replacement of 
> Psr\Clock\ClockInterface as - at the current time - there is no way to 
> generate a DateTimeImmutable directly from a Time\Instant.

Yesn't: You can bridge the gap by using 
DateTimeImmutable::createFromTimestamp($instant->getUnixTimestamp())->setMicrosecond(intdiv($instant->getNanoseconds(), 
1000)).

That said, I acknowledge that it's not particularly pretty and we 
discussed adding another fromInstant() constructor and ->toInstant() 
getter to DateTimeImmutable. The compatibility layer would be sitting on 
the old API to keep the new API clean.

Best regards
Tim Düsterhus

---

## #132601 — Andreas Heigl — 2026-09-23T11:16:46+00:00

URL: https://externals.io/message/132588#132601 · In reply to: #132600

Hey All, Hey Tim.

Thanks for the feedback!


> > […]
>
> While it doesn't seem to be written down as policy - but I could swear this topic came up on Internals at least - PHP doesn't use the `Interface` suffix to indicate interfaces in newly designed APIs. Following the precedent established by ext/random in PHP 8.2 with Random\Engine, the interface is the bare name and the concrete implementations sit in a sub-namespace named after the interface.
>
> Thus there is a clear difference in naming even for the unqualified interface name.

I am totally in favour of omitting the `Interface`. Still people will refer to the `Clock` Interface and the `ClockInterface` (Hopefully never the `ClockInterface` Interface). So - while the naming is clearly distinct also due to the different namespaces - People *will* refer to both using the same "name".

But I do assume that very soon people will refer either to the `PHP Clock interface` and the FIG (or PSR) ClockInterface.

> > […]
>
> The proposed new date/time API is a greenfield design to fix issues with the existing API. We deliberately don't want to “infect” the new API with ideas from the legacy API and returning an object carrying a timezone from a clock, as done in PSR-20, is the wrong design. `now()` is the obvious name for the method and that's why the RFC indicates that an adapter is required to satisfy both interfaces from the same source of truth during the migration phase.
>
> > […]
>
> Yesn't: You can bridge the gap by using DateTimeImmutable::createFromTimestamp($instant->getUnixTimestamp())->setMicrosecond(intdiv($instant->getNanoseconds(), 1000)).
>
> That said, I acknowledge that it's not particularly pretty and we discussed adding another fromInstant() constructor and ->toInstant() getter to DateTimeImmutable. The compatibility layer would be sitting on the old API to keep the new API clean.

Sounds absolutely right.

Thanks for the explanations!

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

---

## #132607 — Larry Garfield — 2026-09-23T15:02:03+00:00

URL: https://externals.io/message/132588#132607 · In reply to: #132588

> Hi
>
> following Time\Duration in PHP 8.6, Derick and I created an RFC for 
> Time\Instant and Time\Clock as the next part of the new date and time 
> API:
>
> https://wiki.php.net/rfc/time_instant_class
>
> This time we have several months until the next feature freeze, so 
> there’s place to discuss additional functionality that we missed. 
> Nevertheless we would like to keep the RFC focused so that every 
> decision gets the attention it deserves and some bits are already listed 
> as “Future Scope” to that effect.
>
> Best regards
> Tim Düsterhus

I am broadly in favor of this proposal, though I have some questions/concerns.

(In reading order...)

- Why is the representable range unspecified?  Can we at least hint at what it is?  If I cannot even guarantee that next week is within range, I basically cannot trust this API at all.  (Later on in the prose the text says "the same as DateTimeImmutable", but I don't know what that is off hand.  It should be specified more explicitly, and that later captured in documentation, even if it's just a minimum and subject to system details.)

- Why is a compare() method needed if Instant already supports <, >, etc?

- "Serialization of Time\Instant will be supported, the exact format is considered an implementation detail. " - Should be a period, not a comma.  Also, the serialization format of other values has often been subject to discussion (eg, Enums), so why is it omitted here?

- I am fine with this being essentially a port of PSR-20, and the naming doesn't bother me.  

- I also agree that not having Instant:now() is the correct approach.  If someone really wants to just pluck the current time out of thin air, testing be damned, that's easy enough:

$now = new SystemClock()->now();

Moreover, making it injectable is also quite trivial thanks to modern syntax:

class SomeService {
  public function __construct(
    private SomeDependency $dep,
    private Clock $clock = new SystemClock(),
  ) {}

  public function doThings() {
    $now = $this->clock->now(); // The system time, unless it's been overridden by injection.
    // ...
  }
}

That's a perfectly fine approach in my mind, and offers all the pieces of flexibility that we need in that regard.

That said, I am also on-board with having the trivial/obvious test clocks provided in core, be they in this RFC or a follow-up.

In short, yes please deprecate PSR-20. :-)

- It's not clear to me how I would serialize an Instant outside of PHP, say to store it in a DB.  UTC ISO8601?  If so, that should be stated explicitly (and again, replicated to the docs eventually) to avoid confusion and people trying to invent clever mechanisms.

My big issue, though, is context.  This is very clearly part 2 of N, which is fine.  Presumably you and Derick have a roadmap between you of what the end goal looks like and the moving parts that will be added, even if it's in steps.  But that's not documented anywhere other than your heads, AFAIK, and the future scope section as currently written is barely 3 of N, and not in detail.

I realize that designs change over time as they're implemented, which is totally fine, and all the details of later steps have likely not been worked out yet, which is also totally fine.  But I still need to see the big picture, at least at a coarse resolution, to understand this RFC in context.  Things that we feel are missing may be missing not out of incompleteness but "that's step N+3", which may be a perfectly good design but that's not at all apparent.

I would strongly urge you to post (probably as an RFC page, even though it's not a full RFC) an overarching roadmap/plan for PHP Time TNG, so we can get a sense of where we're going.  That will allow us to see each RFC in its appropriate context, and clearly note when things have been pushed to later that "later" is defined and documented.  (Eg, the FrozenClock idea.)

--Larry Garfield

---

## #132608 — tim@bastelstu.be — 2026-09-23T17:29:19+00:00

URL: https://externals.io/message/132588#132608 · In reply to: #132607

Hi


> - Why is the representable range unspecified?  Can we at least hint at 
> what it is?  If I cannot even guarantee that next week is within range, 
> I basically cannot trust this API at all.  (Later on in the prose the 
> text says "the same as DateTimeImmutable", but I don't know what that 
> is off hand.  It should be specified more explicitly, and that later 
> captured in documentation, even if it's just a minimum and subject to 
> system details.)

“and will be left to implementation constraints”. I plan to clarify that 
further when the general API design is finalized and Derick and I are 
looking into the implementation to figure out the details. The limits 
will be “reasonable computational limits” - so you’ll be able to 
represent Instants until at least the release of PHP 8.7 ;-)

I added an item to the Open Issues to keep track of that.

> - Why is a compare() method needed if Instant already supports <, >, 
> etc?

API consistency with Duration. Also a method has proper typing and works 
with first class callables / PFA. Duration specifically had this 
example:

     usort($durations, Duration::compare(...));

> Also, the serialization format of other values has often been subject 
> to discussion (eg, Enums), so why is it omitted here?

The internal state of Instant is deliberately unspecified and that 
extends to serialization. The serialization format will be portable 
across 32- and 64-bit versions of PHP and backwards compatibility with 
existing serialized data will be kept across PHP versions. I just 
clarified that part in the RFC text. If you need to look at the output 
of serialization you are doing something very wrong. I consider the enum 
discussion to be a different case, since they introduced an entirely new 
type specifier `E`. Instant will just be a plain old class that 
implements (the equivalent of) `__serialize()` and `__unserialize()`.

> - It's not clear to me how I would serialize an Instant outside of PHP, 
> say to store it in a DB.  UTC ISO8601?  If so, that should be stated 
> explicitly (and again, replicated to the docs eventually) to avoid 
> confusion and people trying to invent clever mechanisms.

As with any other value object, the best serialization format depends on 
your exact use case. If an HTTP API provides you times as the number of 
milliseconds since the Unix epoch, then you would use the 
`fromUnixTimestampMilliseconds()` constructor to create an Instant from 
it. If an API expects an ISO-8601 string as input, you would use the 
`toIso8601DateTimeString()` getter. All the getters and constructors are 
valid options for serialization and each constructor is paired with a 
getter. Even just `serialize($instant)` can be a valid option. As 
already noted in the RFC, the ISO-8601 format (and of course 
`serialize()`) is the portable one that is capable of representing all 
possible Instants.

For custom formats, in particular formats with an implied timezone, 
you’ll need to wait for the future scope “Instant + Timezone” class.

> My big issue, though, is context.  This is very clearly part 2 of N, 
> which is fine.  Presumably you and Derick have a roadmap between you of 
> what the end goal looks like and the moving parts that will be added, 
> even if it's in steps.  But that's not documented anywhere other than 
> your heads, AFAIK, and the future scope section as currently written is 
> barely 3 of N, and not in detail.
> 
> I realize that designs change over time as they're implemented, which 
> is totally fine, and all the details of later steps have likely not 
> been worked out yet, which is also totally fine.  But I still need to 
> see the big picture, at least at a coarse resolution, to understand 
> this RFC in context.  Things that we feel are missing may be missing 
> not out of incompleteness but "that's step N+3", which may be a 
> perfectly good design but that's not at all apparent.
> 
> I would strongly urge you to post (probably as an RFC page, even though 
> it's not a full RFC) an overarching roadmap/plan for PHP Time TNG, so 
> we can get a sense of where we're going.  That will allow us to see 
> each RFC in its appropriate context, and clearly note when things have 
> been pushed to later that "later" is defined and documented.  (Eg, the 
> FrozenClock idea.)

Each part of the series is intended to stand on its own and to be 
complete enough to be usable for production use cases rather than just 
toy examples. The end goal is to model (all) real-world concepts of time 
and the focus of each RFC text is explaining that concept and how it was 
modeled. If you expected the modeling to cover something and the RFC 
doesn’t mention it (“I expected it to do X, why doesn’t it?”), we failed 
at that explanation and I recommend raising the issue on the mailing 
list.

The evolution of the new date and time API is also not linear, but 
rather a graph connecting the various concepts that can be worked on in 
any order, as long as the dependencies are satisfied. To get a rough 
idea of where we’re heading you can take a look at java.time and 
JavaScript’s Temporal.

Best regards
Tim Düsterhus

---

## #132610 — theoattali@gmail.com — 2026-09-23T19:57:14+00:00

URL: https://externals.io/message/132588#132610 · In reply to: #132608

Hi Tim,

Thank you for considering the ISO 8601 date-time representation in the new API !

If I may add one small suggestion: could toIso8601DateTimeString() be shortened to toIso8601String() and fromIso8601DateTimeString() to fromIso8601String() ?

Since Time\Instant already represents a date-time value, these shorter names remain clear and are easier to use.

Best regards,
Théo

> 
> 
> Hi
> 
> 
> > […]
> 
> “and will be left to implementation constraints”. I plan to clarify that further when the general API design is finalized and Derick and I are looking into the implementation to figure out the details. The limits will be “reasonable computational limits” - so you’ll be able to represent Instants until at least the release of PHP 8.7 ;-)
> 
> I added an item to the Open Issues to keep track of that.
> 
> > […]
> 
> API consistency with Duration. Also a method has proper typing and works with first class callables / PFA. Duration specifically had this example:
> 
>    usort($durations, Duration::compare(...));
> 
> > […]
> 
> The internal state of Instant is deliberately unspecified and that extends to serialization. The serialization format will be portable across 32- and 64-bit versions of PHP and backwards compatibility with existing serialized data will be kept across PHP versions. I just clarified that part in the RFC text. If you need to look at the output of serialization you are doing something very wrong. I consider the enum discussion to be a different case, since they introduced an entirely new type specifier `E`. Instant will just be a plain old class that implements (the equivalent of) `__serialize()` and `__unserialize()`.
> 
> > […]
> 
> As with any other value object, the best serialization format depends on your exact use case. If an HTTP API provides you times as the number of milliseconds since the Unix epoch, then you would use the `fromUnixTimestampMilliseconds()` constructor to create an Instant from it. If an API expects an ISO-8601 string as input, you would use the `toIso8601DateTimeString()` getter. All the getters and constructors are valid options for serialization and each constructor is paired with a getter. Even just `serialize($instant)` can be a valid option. As already noted in the RFC, the ISO-8601 format (and of course `serialize()`) is the portable one that is capable of representing all possible Instants.
> 
> For custom formats, in particular formats with an implied timezone, you’ll need to wait for the future scope “Instant + Timezone” class.
> 
> > […]
> 
> Each part of the series is intended to stand on its own and to be complete enough to be usable for production use cases rather than just toy examples. The end goal is to model (all) real-world concepts of time and the focus of each RFC text is explaining that concept and how it was modeled. If you expected the modeling to cover something and the RFC doesn’t mention it (“I expected it to do X, why doesn’t it?”), we failed at that explanation and I recommend raising the issue on the mailing list.
> 
> The evolution of the new date and time API is also not linear, but rather a graph connecting the various concepts that can be worked on in any order, as long as the dependencies are satisfied. To get a rough idea of where we’re heading you can take a look at java.time and JavaScript’s Temporal.
> 
> Best regards
> Tim Düsterhus

---

## #132611 — Larry Garfield — 2026-09-23T20:15:03+00:00

URL: https://externals.io/message/132588#132611 · In reply to: #132608

> > […]
>
> API consistency with Duration. Also a method has proper typing and works 
> with first class callables / PFA. Duration specifically had this 
> example:
>
>      usort($durations, Duration::compare(...));

Ah, valid use case indeed.  Thanks.

> For custom formats, in particular formats with an implied timezone, 
> you’ll need to wait for the future scope “Instant + Timezone” class.

I am indeed waiting with baited breath.  (That will be the DateTimeImmutable replacement, essentially, yes?)

> > […]
>
> Each part of the series is intended to stand on its own and to be 
> complete enough to be usable for production use cases rather than just 
> toy examples. The end goal is to model (all) real-world concepts of time 
> and the focus of each RFC text is explaining that concept and how it was 
> modeled. If you expected the modeling to cover something and the RFC 
> doesn’t mention it (“I expected it to do X, why doesn’t it?”), we failed 
> at that explanation and I recommend raising the issue on the mailing 
> list.
>
> The evolution of the new date and time API is also not linear, but 
> rather a graph connecting the various concepts that can be worked on in 
> any order, as long as the dependencies are satisfied. To get a rough 
> idea of where we’re heading you can take a look at java.time and 
> JavaScript’s Temporal.

Then please share the graph.  There is nowhere right now that someone can go to canonically see "oh, they are planning to add a new timezone object and a new DateTimeImmutable replacement later, too.  Good to know."

I know you and I have discussed this before, but I am going to keep riding this horse: You clearly have a roadmap in your heads.  Share it.  At whatever level of granularity it exists, share it.  We need that sort of context.,  It builds trust in the process and in the people that are working on it.  Everyone understands it's not a promise, but a communication mechanism, and a very important one for this sort of effort.

--Larry Garfield

---

## #132612 — theoattali@gmail.com — 2026-09-23T20:16:22+00:00

URL: https://externals.io/message/132588#132612 · In reply to: #132608

Following up on my previous message about the method names,I noticed one separate technical point.

The RFC specifies nanosecond precision for Time\Instant, but it is not clear whether toIso8601DateTimeString() preserves that precision in its output. Could the RFC clarify the fractional-second format and whether an optional precision argument is supported?

I’m suggesting this only to clarify the existing method’s contract.

Best regards,
Théo

> 
> 
> Hi
> 
> 
> > […]
> 
> “and will be left to implementation constraints”. I plan to clarify that further when the general API design is finalized and Derick and I are looking into the implementation to figure out the details. The limits will be “reasonable computational limits” - so you’ll be able to represent Instants until at least the release of PHP 8.7 ;-)
> 
> I added an item to the Open Issues to keep track of that.
> 
> > […]
> 
> API consistency with Duration. Also a method has proper typing and works with first class callables / PFA. Duration specifically had this example:
> 
>    usort($durations, Duration::compare(...));
> 
> > […]
> 
> The internal state of Instant is deliberately unspecified and that extends to serialization. The serialization format will be portable across 32- and 64-bit versions of PHP and backwards compatibility with existing serialized data will be kept across PHP versions. I just clarified that part in the RFC text. If you need to look at the output of serialization you are doing something very wrong. I consider the enum discussion to be a different case, since they introduced an entirely new type specifier `E`. Instant will just be a plain old class that implements (the equivalent of) `__serialize()` and `__unserialize()`.
> 
> > […]
> 
> As with any other value object, the best serialization format depends on your exact use case. If an HTTP API provides you times as the number of milliseconds since the Unix epoch, then you would use the `fromUnixTimestampMilliseconds()` constructor to create an Instant from it. If an API expects an ISO-8601 string as input, you would use the `toIso8601DateTimeString()` getter. All the getters and constructors are valid options for serialization and each constructor is paired with a getter. Even just `serialize($instant)` can be a valid option. As already noted in the RFC, the ISO-8601 format (and of course `serialize()`) is the portable one that is capable of representing all possible Instants.
> 
> For custom formats, in particular formats with an implied timezone, you’ll need to wait for the future scope “Instant + Timezone” class.
> 
> > […]
> 
> Each part of the series is intended to stand on its own and to be complete enough to be usable for production use cases rather than just toy examples. The end goal is to model (all) real-world concepts of time and the focus of each RFC text is explaining that concept and how it was modeled. If you expected the modeling to cover something and the RFC doesn’t mention it (“I expected it to do X, why doesn’t it?”), we failed at that explanation and I recommend raising the issue on the mailing list.
> 
> The evolution of the new date and time API is also not linear, but rather a graph connecting the various concepts that can be worked on in any order, as long as the dependencies are satisfied. To get a rough idea of where we’re heading you can take a look at java.time and JavaScript’s Temporal.
> 
> Best regards
> Tim Düsterhus

---

## #132621 — tim@bastelstu.be — 2026-09-24T12:03:26+00:00

URL: https://externals.io/message/132588#132621 · In reply to: #132612

Hi

Note: When replying on this list, please keep your reply below the 
quoted parts and cut the quote to a minimum. And please try to reply to 
the fit appropriate email to keep the threading from working well (see 
the thread view at the bottom of 
https://news-web.php.net/php.internals/132612), in the Gmail web 
interface you can do that by using the Reply button on the email itself, 
instead of the big box at the bottom.


> The RFC specifies nanosecond precision for Time\Instant, but it is not 
> clear whether toIso8601DateTimeString() preserves that precision in its 
> output. Could the RFC clarify the fractional-second format and whether 
> an optional precision argument is supported?

As the RFC notes, the ISO-8601 representation is the universal one. It 
therefore keeps full nanosecond precision. I clarified that in the doc 
comment of the stub after having made the executive decision that it 
will omit the fractional part if it is zero.

No precision argument is supported, and I don't think it would be a good 
idea doing that as part of the “presentation layer”. Cutting off the 
fractional part is possible using 
$instant->sub(Duration::fromNanoseconds($instant->getNanoseconds())), 
which while a mouthful would be an explicit action. I can imagine adding 
a `->truncateTo()` method in the future, but that one will require some 
design as to how to specify the the desired precision in a useful way 
without opening up footguns.

Best regards
Tim Düsterhus

---

## #132631 — tim@bastelstu.be — 2026-09-25T08:03:28+00:00

URL: https://externals.io/message/132588#132631 · In reply to: #132611

Hi


> > […]
> 
> I am indeed waiting with baited breath.  (That will be the 
> DateTimeImmutable replacement, essentially, yes?)

Instant+Timezone would be the same information that DateTimeImmutable 
holds, yes. What would likely be another future scope after that is the 
“calendar-based math” (i.e. the replacement for what's currently 
DateInterval and `setDate()` and similar) since that's an entire rabbit 
hole of its own :-)

> There is nowhere right now that someone can go to canonically see "oh, 
> they are planning to add a new timezone object and a new 
> DateTimeImmutable replacement later, too.  Good to know."

Well, it's listed in the Future Scope of this one. And me pointing 
towards java.time and JavaScript’s Temporal was a sincere answer: The 
extent of the planning is that it will look somewhat like that and each 
step is slicing off a small standalone part along the way.

Best regards
Tim Düsterhus

---

## #132636 — tim@bastelstu.be — 2026-09-25T13:57:13+00:00

URL: https://externals.io/message/132588#132636 · In reply to: #132610

Hi


> If I may add one small suggestion: could toIso8601DateTimeString() be 
> shortened to toIso8601String() and fromIso8601DateTimeString() to 
> fromIso8601String() ?
> 
> Since Time\Instant already represents a date-time value, these shorter 
> names remain clear and are easier to use.

The proposed wording is consistent with 
`Time\Duration::fromIso8601DurationString()` which also includes the 
explicit “Duration” indicator. It also has some practical benefits: 
ISO-8601 defines a multitude of interchange formats that could be 
reasonably interpreted as being applicable, particularly with some 
components being implied as accepted by DateTimeImmutable. As an example 
`Instant::fromIso8601String('2026-09-25')` could be argued to mean 
“midnight UTC on 2026-09-25”.

I believe the naming strikes an appropriate middle-ground between 
specific, while not being overly verbose and it leaves some future space 
for a `toIso8601OrdinalDateTimeString()` to emit `2026-268T13:55:00Z` 
(with 268 referring to the 268th day of the year 2026), with the 
2026-09-25 being the “calendar date” format, where the “calendar” part 
is being implied (and also the “extended” representation being implied).

Best regards
Tim Düsterhus

---

## #132698 — tim@bastelstu.be — 2026-09-29T17:17:49+00:00

URL: https://externals.io/message/132588#132698 · In reply to: #132588

Hi


> following Time\Duration in PHP 8.6, Derick and I created an RFC for 
> Time\Instant and Time\Clock as the next part of the new date and time 
> API:
> 
> https://wiki.php.net/rfc/time_instant_class

I just had a chat with Derick about the discussion points that have come 
up and made some changes to the RFC as a result:

- We added `DateTime(Immutable)::toInstant()` to the proposal as a basic 
compatibility layer between the old and new API. `toInstant()` naturally 
drops the timezone information, but is otherwise fully lossless, since 
Time\Instant is capable of representing better precison (nanoseconds) 
than DTI and DT (microseconds). A `DTI::fromInstant()` is missing, since 
it's not obvious how to deal with the extended precision. Truncating 
might be one choice, rejecting another. The snippet mentioned in 
https://news-web.php.net/php.internals/132600 will work and make the 
decision (truncation) explicit.

- The behavior of `Instant::toIso8601DateTimeString()` regarding 
fractional seconds was adjusted again: Trailing zeros will now be kept 
to make the precision supported by Time\Instant explicit. 
`2026-09-29T16:42:45.5Z` could mean “exactly 0.5 seconds” or “0.5 
seconds ± 0.05 seconds” whereas `2026-09-29T16:42:45.500000000Z` is 
explicit as to how precise the data is. This might matter for consumers 
that also store an “uncertainty” range.

- The language regarding testing clocks as adjusted as per Seifeddine’s 
suggestion: They are not ruled out explicitly and mentioned as possible 
future scope. But Derick and I want to be clear in that we don’t plan to 
write an RFC for testing clocks, since we remain unconvinced they belong 
in core. Personally I also haven't had sufficient exposure to testing 
clocks in practice, so I'm not the best person to design the API. 
Instead we want to invite you (as the PHP internals community) to write 
the follow-up RFC for testing clocks if you'd like to see them in core 
and have a good API design ready. Given that the clocks are scoped away 
in the dedicated Time\Clock namespace this follow-up RFC also won't need 
any coordination with Derick and I and doesn't conflict with our vision 
for the new date/time API.

It didn't result in a change to the RFC, but Derick confirmed he agreed 
with my reasoning regarding the naming of the ISO-8601 constructor / 
getter that I provided in https://news-web.php.net/php.internals/132636. 
So I would consider that discussion thread settled.

----------------

Other than that it feels that this RFC has much fewer opinion than 
Time\Duration in the same timeframe. Are you all happy and thus didn't 
say anything or did you not get around to reading and evaluating the 
RFC? If it's the former, feel free to provide a LGTM, ship it. And if 
there's anything that bothers you or remains unclear, please mention it, 
no matter how big or small.

Best regards
Tim Düsterhus

---

## #132699 — tim@bastelstu.be — 2026-09-29T17:35:50+00:00

URL: https://externals.io/message/132588#132699 · In reply to: #132698

Hi


> - The behavior of `Instant::toIso8601DateTimeString()` regarding 
> fractional seconds was adjusted again: Trailing zeros will now be kept 
> to make the precision supported by Time\Instant explicit. 
> `2026-09-29T16:42:45.5Z` could mean “exactly 0.5 seconds” or “0.5 
> seconds ± 0.05 seconds” whereas `2026-09-29T16:42:45.500000000Z` is 
> explicit as to how precise the data is. This might matter for consumers 
> that also store an “uncertainty” range.

Forgot to mention, but it's in the RFC: The fractional part will be 
entirely omitted if it's zero. While that drops the explicit precision 
information in *that* case, it should also improve interoperability with 
consumers who are not prepared to handle fractional seconds. A consumer 
that already supports fractional seconds should be able to deal with 
trailing zeros just fine.

Best regards
Tim Düsterhus

---

## #132723 — Mirco Babin — 2026-09-30T17:40:39+00:00

URL: https://externals.io/message/132588#132723 · In reply to: #132588

Hello Tim Düsterhus,

-----------------------------------------------------------------------
Tue, 22 Sep 2026 14:20:19 +0000

> following Time\Duration in PHP 8.6, Derick and I created an RFC for
> Time\Instant and Time\Clock as the next part of the
> new date and time API:
>
> https://wiki.php.net/rfc/time_instant_class

And Tue, 29 Sep 2026 17:17:49 +0000

> Other than that it feels that this RFC has much fewer opinion than
> Time\Duration in the same timeframe. Are you all happy and thus
> didn't say anything or did you not get around to reading and
> evaluating the RFC? If it's the former, feel free to provide a LGTM,
> ship it. And if there's anything that bothers you or remains unclear,
> please mention it, no matter how big or small.
-----------------------------------------------------------------------

=========
Prologue
=========

Well, I do have 8 comments on the Request For Comments (RFC).
This is a lengthy post, be prepared for a long reading time.

=========
Comment 1
=========
Is \Time\Instant meant to be immutable? If so, please state that in
the RFC.

=========
Comment 2
=========
The RFC states:

> An Time\Instant carries no timezone. It represents a unique point
> on the timeline of the universe.

Why is there no explicit or implicit timezone attached? The RFC reads
to me like there is an implicit timezone attached, namely the UTC
timezone. Especially the `toIso8601DateTimeString()` function which
always returns the 'Z' timezone identifier seems to imply an implicit
UTC timezone?

=========
Comment 3
=========
Why is it called \Time\Instant? I find \Time\UtcInstant a better name,
which embeds the timeline unit used.

\Time\UtcInstant leaves room for future different timeline Instants
like:
- \Time\TaiInstant (International Atomic Time)
- \Time\Ut1Instant (Universal Time)
- \Time\TtInstant (Terrestrial Time)

=========
Comment 4
=========
The \Time\Clock interface conflicts with PSR-20 Clock interface, see
https://www.php-fig.org/psr/psr-20/ . A class can never implement both
interfaces at the same time. This will hinder adoption.

Consider renaming the `function `now()`: \Time\Instant` function to
`function nowAsInstant(): \Time\Instant`.

To clarify, with the current proposal the following will not work:

```php
<?php

namespace Time
{
    final readonly class Instant
    {
        // Omitted for the sake of brevity.
    }

    interface Clock
    {
        /**
         * The current instant, at the resolution offered by the
         * underlying clock.
         */
        public function `now()`: Instant;
    }
}

namespace Psr\Clock
{
    interface ClockInterface
    {
        /**
         * Returns the current time as a DateTimeImmutable Object
         */
        public function `now()`: \DateTimeImmutable;
    }
}

namespace MyApp
{
    class MyClock implements \Psr\Clock\ClockInterface, \Time\Clock
    {
        public function `now()`: \DateTimeImmutable
        {
            return new \DateTimeImmutable();
        }

        public function nowAsInstant(): \Time\Instant
        {
            // return (new \DateTimeImmutable())->toInstant();
        }
    }
}

// Fatal error: Declaration of MyApp\MyClock::now(): DateTimeImmutable
//              must be compatible with Time\Clock::now(): Time\Instant
?>
```

=========
Comment 5
=========
The RFC introduces a SystemClock class:

```php
<?php

final readonly class SystemClock implements \Time\Clock
{
    public function __construct() {}

    /**
     * The current instant, at the resolution offered by the platform
     * clock,
     * which is generally coarser than nanoseconds.
     *
     * Returned values are not guaranteed to be monotonically
     * increasing across calls.
     */
    public function `now()`: \Time\Instant {}
}

?>
```

Why is SystemClock not a Singleton? Can there be multiple different
system clocks in practice? I believe a System Clock, with the emphasis
on "System" is a System Wide clock. This clock is not bound to PHP,
but to all processes running on the system, including Apache,
shell-scripts, NGINX and others.

The RFC also states a FrozenClock for testing purposes. Well this
pattern is not always going to work. Especially when an application
(the main program) uses Composer libraries and wants to freeze time
for each and everyone, including the `vendor` directory. Because not
every library in the `vendor` directory uses SystemClock. They all
use `time()`, because that is currently the standard way to obtain
the System Clock. Time freezing must involve the `time()` function!

I think `SystemClock` should be removed from this RFC, it deserves
a seperate RFC. That RFC should also explore a frozen `time()`
function. Meaning the output of `time()` can be frozen recursively.
Because of this probably the \Time\Clock interface should also
be moved to that new RFC.

After removal, how to obtain a \Time\Instant from the System Clock
is in comment 6.

=========
Comment 6
=========
Why does \Time\Instant not have a named constructor
`public function fromSystemClock(): \Time\Instant` ?

Why all the complexity of constructing a \Time\SystemClock and
calling `now()`? The System Clock is a Singleton and is always
available, as the `time()` function shows.

=========
Comment 7
=========
The RFC states:

> PHP currently offers two ways to represent such a point, and both
> are unsatisfying for the general case. A plain int as returned by
> `time()` discards all sub-second precision and carries no type
> information, leaving the question of “is this seconds, milliseconds
> or something entirely different” to documentation instead of the
> type system.

I want to bring something else to the table. What if one wants *less*
precision? What if one does not want seconds, milliseconds,
microseconds, nanoseconds? How is that going to fit into the
type system?

As a practical example, take a public transportation coach. The coach
has a schedule which is expressed in *minutes*, never in *seconds*. The
same argument, only *minutes* precision, goes for flight departures
and arrivals. Also ferries express their times in *minutes*.

One could use a milliseconds \Time\Instant and state that seconds and
lower must always be 0. But how can the type system then differentiate
between a milliseconds precision \Time\Instant and a minutes precision
\Time\Instant? Both are exactly the same type.

I think *precision* should somehow be an explicit part of \Time\Instant
class. How precise is the \Time\Instant? That can only be answered by
the application/system who new-ed the \Time\Instant. Even with
`fromUnixTimestamp()` the precision might not be 'seconds', if the
agreement in the application-system is to never provide seconds, then
only timestamps having :00 seconds are valid.

Also the struggle with `toIso8601DateTimeString()` and its output
precision indicates there is a need for explicitly specifying the
precision. That would also eliminate the assumption that a fractional
part can be omitted if it is 0. PHP can never guess in what
system/application or communication the \Time\Instant is involved
and should never guess its precision.

=========
Comment 8
=========
The RFC states:

> Extensions may want to adjust their API to take Time\Instant
> in addition to an int representing a Unix timestamp or an
> object implementing DateTimeInterface.

With regard to the `DateTimeInterface`, I want to share that this
interface is an internal interface and can't be implemented by
user-space classes. See also issue #23543 at
https://github.com/php/php-src/issues/23543

To clarify, this does not work:

```php
<?php

class MyTime implements DateTimeInterface
{
}

// Fatal error: DateTimeInterface can't be implemented by user classes
?>
```

===============
End of comments
===============

Kind regards,
Mirco Babin

---

## #132728 — Morgan — 2026-09-30T19:10:26+00:00

URL: https://externals.io/message/132588#132728 · In reply to: #132723

> =========
> Comment 2
> =========
> The RFC states:
> 
> > […]
> 
> Why is there no explicit or implicit timezone attached? The RFC reads
> to me like there is an implicit timezone attached, namely the UTC
> timezone. Especially the `toIso8601DateTimeString()` function which
> always returns the 'Z' timezone identifier seems to imply an implicit
> UTC timezone?
> 
I think I can answer that one. It's because for display purposes some 
consistent way of labelling Instants is required so that they can be 
displayed. Using an ISO8601 string just makes that label human-readable; 
the UTC timezone is not an intrinsic property of the Instant but of the 
labelling (nor are the labels themselves, for that matter). Instants 
would still be a thing and people would be able to say that two events 
occurred "at the same time" even if the International Meridian 
Conference had never happened.

(I mentioned earlier during the Duration discussion that time arithmetic 
is a one-dimensional real affine space. Such a space can be formalised 
as a set of points and a space of free vectors (and a way to add points 
and vectors together). Here, Durations provide the vectors and Instants 
provide the points.)

> 
> I think *precision* should somehow be an explicit part of \Time\Instant
> class. How precise is the \Time\Instant?

Well, then it's not an _instant_, is it? It's a combination of an 
instant ("now") and a duration ("and the subsequent sixty seconds").

---

## #132729 — tim@bastelstu.be — 2026-09-30T19:48:51+00:00

URL: https://externals.io/message/132588#132729 · In reply to: #132723

Hi


> =========
> Prologue
> =========
> 
> Well, I do have 8 comments on the Request For Comments (RFC).
> This is a lengthy post, be prepared for a long reading time.

Thank you! I'm fully prepared for lengthy emails and am happy to answer 
any clarifying questions to make sure we're all on the same page with 
regard to what is being proposed. Your email is also nicely structured, 
which makes it easy to work through it.

> =========
> Comment 1
> =========
> Is \Time\Instant meant to be immutable? If so, please state that in
> the RFC.

Yes. This was already implied since the stub specifies that it's a 
`readonly` class, but I've just adjusted the RFC text to explicitly 
include the word “immutable”.

> =========
> Comment 2
> =========
> The RFC states:
> 
> > […]
> 
> Why is there no explicit or implicit timezone attached? The RFC reads
> to me like there is an implicit timezone attached, namely the UTC
> timezone. Especially the `toIso8601DateTimeString()` function which
> always returns the 'Z' timezone identifier seems to imply an implicit
> UTC timezone?

Timezones are a concept to translate a point in time (“Instant”) into 
date and time as shown on a clock. Both 2026-09-30T20:13:30+02:00 and 
2026-09-30T18:13:30+00:00 refer to the same point in time. The point in 
time itself does not have a timezone. The ISO-8601 getter chooses to 
represent the point in time with the UTC / Zulu timezone, because 
specifying an offset is required for the “date and time” representation 
to be unambiguous. It would be equally valid for it to select a random 
offset each time you use it. Using UTC / a zero offset is just a 
pragmatic choice for best interoperability.

> =========
> Comment 3
> =========
> Why is it called \Time\Instant? I find \Time\UtcInstant a better name,
> which embeds the timeline unit used.
> 
> \Time\UtcInstant leaves room for future different timeline Instants
> like:
> - \Time\TaiInstant (International Atomic Time)
> - \Time\Ut1Instant (Universal Time)
> - \Time\TtInstant (Terrestrial Time)

UTC, TAI and the others are just different projections of a “point on 
the timeline of the universe” and the `Instant` class is largely 
agnostic to them. It differs from a perfect model of the timeline of the 
universe in that leap seconds are ignored (see my reply to Andreas 
https://news-web.php.net/php.internals/132600), since that is what the 
computing industry converged on. Nevertheless, this brings us back to 
comment (2): The differences between UTC, TAI and the others concern the 
*clock* time. The point on the timeline of the universe remains the 
same.

And of course `Time\Instant` is just the ergonomic name, matching the 
precedent set in Java (`java.time.Instant`) and JavaScript 
(`Temporal.Instant`).

> =========
> Comment 4
> =========
> The \Time\Clock interface conflicts with PSR-20 Clock interface, see
> https://www.php-fig.org/psr/psr-20/ . A class can never implement both
> interfaces at the same time. This will hinder adoption.

The RFC acknowledges that. Writing an adapter is easy, particularly 
since the addition of the `DateTimeImmutable::toInstant()` method to the 
proposal.

> Consider renaming the `function `now()`: \Time\Instant` function to
> `function nowAsInstant(): \Time\Instant`.

`now()` is the obvious name for the method. Using something else would 
mean that the proposed API would still suffer from a decision made for 
compatibility after everyone has migrated to it and PSR-20 is long 
forgotten. The horizon we are planning with is *at least* the next 15 
years, but we're hoping that the API holds up for even longer.

For the same reason the compatibility layer with `DateTimeImmutable` is 
explicitly added to the *old API* so that it is possible to deprecate 
and remove the old API without affecting the new one.

> =========
> Comment 5
> =========
> The RFC introduces a SystemClock class:
> 
> ```php
> <?php
> 
> final readonly class SystemClock implements \Time\Clock
> {
>     public function __construct() {}
> 
>     /**
>      * The current instant, at the resolution offered by the platform
>      * clock,
>      * which is generally coarser than nanoseconds.
>      *
>      * Returned values are not guaranteed to be monotonically
>      * increasing across calls.
>      */
>     public function `now()`: \Time\Instant {}
> }
> 
> ?>
> ```
> 
> Why is SystemClock not a Singleton? Can there be multiple different
> system clocks in practice? I believe a System Clock, with the emphasis
> on "System" is a System Wide clock. This clock is not bound to PHP,
> but to all processes running on the system, including Apache,
> shell-scripts, NGINX and others.

Conceptually there is only one `SystemClock` and internally each 
`SystemClock` object accesses the same clock source provided by the 
operating system. But you are making a good point here: Replacing the 
constructor with a static `::get()` method or similar would make that 
explicit and would also allow for reducing memory usage when 
`SystemClock` objects are obtained at different places in the code 
(instead of being pulled from a dependency injection container). I'll 
put this on my list to discuss with Derick (and am happy to receive 
naming suggestions for such a static getter).

> The RFC also states a FrozenClock for testing purposes. Well this

The `FrozenClock` is *not* part of the RFC. It is provided in the 
non-normative part of the RFC as an example to showcase how the `Clock` 
interface can be useful for testing purposes. Whether or not a 
`FrozenClock` will be added to PHP itself is to be decided as part of a 
future RFC (by different authors, as indicated in my email from 
yesterday).

> pattern is not always going to work. Especially when an application
> (the main program) uses Composer libraries and wants to freeze time
> for each and everyone, including the `vendor` directory. Because not
> every library in the `vendor` directory uses SystemClock. They all
> use `time()`, because that is currently the standard way to obtain
> the System Clock. Time freezing must involve the `time()` function!

It is debatable whether `time()` is the standard way to access the 
system clock. It lacks support for fractional seconds and has terrible 
ergonomics due to returning a bare integer. It is certainly still in 
common use, but I'd argue the current best practice is a 
`DateTimeImmutable` object, ideally one you obtained from a PSR-20 
clock.

> I think `SystemClock` should be removed from this RFC, it deserves
> a seperate RFC. That RFC should also explore a frozen `time()`
> function. Meaning the output of `time()` can be frozen recursively.
> Because of this probably the \Time\Clock interface should also
> be moved to that new RFC.

The point of the new date and time API is to completely supersede the 
existing date and time API with a proper API design matching best 
practices. Superseding the existing API includes the `time()` function - 
which I would say is already a legacy API as of *today*, since 
`DateTimeImmutable` does everything `time()` does and it does it better 
(except maybe for brevity).

> =========
> Comment 6
> =========
> Why does \Time\Instant not have a named constructor
> `public function fromSystemClock(): \Time\Instant` ?
> 
> Why all the complexity of constructing a \Time\SystemClock and
> calling `now()`? The System Clock is a Singleton and is always
> available, as the `time()` function shows.

See https://news-web.php.net/php.internals/132594. “Injecting” a clock 
would be the correct solution. If `SystemClock` was made a singleton 
with a static getter as mentioned above (while still implementing the 
interface), this would allow for:

     SystemClock::get()->now()

for simple use cases and one-off scripts, which would be even shorter 
than your proposed:

     Instant::fromSystemClock()

> =========
> Comment 7
> =========
> The RFC states:
> 
> > […]
> 
> I want to bring something else to the table. What if one wants *less*
> precision? What if one does not want seconds, milliseconds,
> microseconds, nanoseconds? How is that going to fit into the
> type system?

The `Instant` represents a point in time as precisely as possible. If 
for some reason you need less precision, you can adjust it using the 
`->add()` and `->sub()` methods as desired. Please also see 
https://news-web.php.net/php.internals/132621 for a possible future 
scope `->truncateTo()` method, but …

> As a practical example, take a public transportation coach. The coach
> has a schedule which is expressed in *minutes*, never in *seconds*. The
> same argument, only *minutes* precision, goes for flight departures
> and arrivals. Also ferries express their times in *minutes*.

… using an Instant to represent a public transportation schedule is the 
wrong abstraction: Public transportation works on “date and time” as 
shown on a calendar and a clock and only becomes meaningful once you 
involve timezones. This is particularly important when a DST changeover 
happens or your jurisdiction changes timezone rules: Now the point on 
the timeline of the universe where your bus departs is different, but 
the time shown on your wristwatch has remained the same.

> =========
> Comment 8
> =========
> The RFC states:
> 
> > […]
> 
> With regard to the `DateTimeInterface`, I want to share that this
> interface is an internal interface and can't be implemented by
> user-space classes. See also issue #23543 at
> https://github.com/php/php-src/issues/23543
> 
> To clarify, this does not work:
> 
> ```php
> <?php
> 
> class MyTime implements DateTimeInterface
> {
> }
> 
> // Fatal error: DateTimeInterface can't be implemented by user classes
> ?>
> ```

That is an accurate observation, but not relevant to the quoted part. I 
think there might be a misunderstanding: What the quote is saying is 
that if there is a function `foo(DateTimeInterface $when)` it should be 
adjusted to `foo(DateTimeInterface|Instant $when)` so that it is 
possible to use it with the new API without needing to first convert the 
`Instant` into a `DateTimeImmutable`.

Best regards
Tim Düsterhus

---

## #132730 — tim@bastelstu.be — 2026-09-30T19:52:44+00:00

URL: https://externals.io/message/132588#132730 · In reply to: #132728

Hi


> I think I can answer that one. […]

Yes, thank you! That matches what I just sent, just using different 
words.

> > […]
> 
> Well, then it's not an _instant_, is it? It's a combination of an 
> instant ("now") and a duration ("and the subsequent sixty seconds").

Indeed. That's the uncertainty information that I mentioned in 
https://news-web.php.net/php.internals/132698. As you say, it can be 
representing by an Instant + Duration indicating the amount of 
uncertainty.

Best regards
Tim Düsterhus

---

## #132753 — Mirco Babin — 2026-10-01T15:22:10+00:00

URL: https://externals.io/message/132588#132753 · In reply to: #132729

Hello Tim Düsterhus,

> > […]

Reply to Wed, 30 Sep 2026 19:48:51 +0000

> > […]

>Timezones are a concept to translate a point in time (“Instant”) into
>date and time as shown on a clock. Both 2026-09-30T20:13:30+02:00 and
>2026-09-30T18:13:30+00:00 refer to the same point in time. The point in
>time itself does not have a timezone. The ISO-8601 getter chooses to
>represent the point in time with the UTC / Zulu timezone, because
>specifying an offset is required for the “date and time” representation
>to be unambiguous. It would be equally valid for it to select a random
>offset each time you use it. Using UTC / a zero offset is just a
>pragmatic choice for best interoperability.

Is this unique point on the timelime of the universe concept somewhere
defined? For example in an IETF-RFC, academic paper or somewhere else?
Because it seems to me that timeline of the universe must have some
definition somewhere? The RFC does not have any reference to a formal
definition?

> > […]

>The RFC acknowledges that. Writing an adapter is easy, particularly
>since the addition of the `DateTimeImmutable::toInstant()` method to the
>proposal.

I have demonstrated it is impossible to write an adapter. Given the
constraint that only the PSR-20 MyClock class can be changed, call-sites
must not be adjusted. Also the purpose of a PSR-20 Clock is to never
call `new DateTimeImmutable()` or `time()` anymore, so the assumption there
are `new DateTimeImmutable()` calls that can be adapted is incorrect.

> > […]

>`now()` is the obvious name for the method. Using something else would
>mean that the proposed API would still suffer from a decision made for
>compatibility after everyone has migrated to it and PSR-20 is long
>forgotten. The horizon we are planning with is *at least* the next 15
>years, but we're hoping that the API holds up for even longer.

This is a strange point of view. Why would PSR-20 be forgotten? Is it
a goal to deprecate/forget PSR-20? And why is this not mentioned in
the RFC? And what would the duration be of the forget timeline?

`time()` is also an obvious name for the method. And it would not
conflict with PSR-20.

```php

SystemClock::get()->time();

```

> > […]


> > […]
>
>The `FrozenClock` is *not* part of the RFC. It is provided in the
>non-normative part of the RFC as an example to showcase how the `Clock`
>interface can be useful for testing purposes. Whether or not a
>`FrozenClock` will be added to PHP itself is to be decided as part of a
>future RFC (by different authors, as indicated in my email from
>yesterday).

That is surprising. How can a SystemClock be designed without
exploring the freezing of time? If the SystemClock is wrongly
designed in this RFC, and hinders the unexplored, unknown FrozenTime,
"*at least* the next 15 years" there will be an misdesign.

I really think Time\Clock interface, SystemClock, FrozenTime,
DateTimeImmutable freezing and `time()` freezing must be one RFC,
that designs them very well. And don't forget the very popular Carbon
library in this picture. This design should not be split between
2 RFC's and different authors.

> > […]

>If `SystemClock` was made a singleton
>with a static getter as mentioned above (while still implementing the
>interface), this would allow for:
>
>     SystemClock::get()->now()
>
>for simple use cases and one-off scripts, which would be even shorter
>than your proposed:
>
>     Instant::fromSystemClock()

If it becomes `SystemClock::get()->time()` both variants have 26
characters to type. But IDE autocompletion has to parse 3 parts in
`SystemClock::get()->time()` and only 2 parts in
`Instant::fromSystemClock()`.

If it is not too much trouble I would add them both, because it
increases Developer Experience.

Kind regards,
Mirco Babin

---

## #132754 — Ilia — 2026-10-01T15:40:24+00:00

URL: https://externals.io/message/132588#132754 · In reply to: #132588

> following Time\Duration in PHP 8.6, Derick and I created an RFC for
> Time\Instant and Time\Clock as the next part of the new date and time
> API:
>
> https://wiki.php.net/rfc/time_instant_class


Hi Tim,

Broadly in favor. The timezone-less design and keeping the compat layer
on the old API are the right calls. Three things I'd like pinned down
before a vote:

1. toIso8601DateTimeString() output width. Omitting the fraction only
when it is zero makes the output format depend on the value. A consumer
that can't parse fractions passes tests with whole-second fixtures, then
fails on almost every SystemClock value in production, so the interop
benefit doesn't hold. It also breaks string ordering:
"2026-09-29T16:42:45Z" sorts after "2026-09-29T16:42:45.500000000Z", and
people do store these in VARCHAR columns and ORDER BY them. Always
emitting 9 digits gives fixed width, chronological string order for
years 0000 to 9999, and the explicit precision you were after.

2. The accepted grammar of fromIso8601DateTimeString(). "May not support
all legal formats, extendable by a PR" means the accepted set gets
decided in code review rather than by the vote. I'd like the RFC to
guarantee RFC 3339 date-time (plus the expanded years the getter emits)
and state the outcome for: more than 9 fractional digits, comma decimal
sign, lowercase t/z, space separator, -00:00, 24:00:00 and 23:59:60. On
the last one, java.time parses 23:59:60 as 23:59:59 rather than
rejecting it, and RFC 3339 explicitly permits :60. Rejecting is
defensible, but it should be written down.

3. `json_encode()`. With no public properties, json_encode($instant)
yields {}. Duration and DateTimeImmutable both encode to something
meaningful today, so a silent {} is a trap for any API response carrying
a timestamp. Either implement JsonSerializable returning the ISO-8601
string, or state that {} is intentional.

On the exceptions open issue: splitting TimeException into subclasses
later is BC-safe, since catch (TimeException) keeps working, so I don't
think it needs to block this RFC.

Ilia Alshanetsky
Technologist, CTO, Entrepreneur
E: ilia@ilia.ws
T: @iliaa
B: http://ilia.ws

---

Next page: https://externals.io/message/132588.md?page=2
