Hi
Am 2026-06-23 08:19, schrieb [email protected]:
What you feel unintuitive is just addition of two numbers in different
units "$seconds + $nanoseconds * 1_000_000_000", which for me feels
very natural.
No, what I feel is unintuitive is that the magnitude of the Duration
will because *smaller* when the magnitude of the nanosecond value
becomes *larger*. You could phrase it as “the representation of a single
value as two values with different signs is unintuitive”. The different
units are not the issue, the different sign is.
With the negative flag it's more complicated "($negative ? -1 : 1) *
$seconds + $nanoseconds * 1_000_000_000" to obtain the correct meaning.
This example snippet is incorrect. The correct version would be:
`($negative ? -1 : 1) * ($seconds + $nanoseconds * 1_000_000_000)` (with
parentheses). In fact this snippet includes the snippet you consider to
be “very natural”, it just makes the application of the sign explicit
and effectively applies it to both components (instead of one component
like Java does), which means that the magnitude of `$seconds` is a
correct lower bound for the magnitude of the entire Duration.
To give a specific example in Java
(https://www.programiz.com/online-compiler/1Iilpy8ncbwRS):
import java.time.Duration;
class Main {
public static void main(String[] args) {
Duration d = Duration.parse("PT-59.5S");
System.out.println(d.getSeconds());
System.out.println(d);
}
}
This will print:
-60
PT-59.5S
Just by looking at the “seconds” component it looks like the Duration is
at least 1 minute long. But it isn't, because if the second component is
negative, the larger the value of the nanosecond component is, the
shorter the duration will be.
In the RFC you say
Negative durations are represented by an explicit $negative property.
This makes it easy to deal with absolute values by just ignoring the
value of $negative.
That's just not true - you can't simply ignore the sign you have to
deal with it no matter what. it's changing your calculations, it'g
getting rejected on passing it to other functions.
On the same time the current API makes it harder to deal with negative
durations as they can not be constructed directly and are not allowed
as operator arguments.
The statement is correct, if you are interested in absolute values, you
have the magnitude right there and can ignore the `$negative` flag. But
to make it even easier, we added the `->absolute()` method that just
clears the sign. Simply replacing seconds by abs(seconds) in Java's
representation would *not* be correct. In fact the OpenJDK
implementation defers to a BigDecimal calculation to flip the sign,
which is not an option for PHP, because the minimal PHP build doesn't
include either GMP or bcmath.
I totally get the reasoning behind Rust's choice to make it fully
unsigned - no negative durations.
Thinking more about that I see only two cases for negative durations:
1. result of calculation
2. difference of two points in times with direction
If we agree on "negative durations are meaningless" then we can
disallow them (throw) and for the second case we calculate the
distance.
I would generally agree that negative durations are conceptionally
meaningless, but at the same think I consider it important that
calculating the difference between two Instants should make the
direction available as part of the same operation so that users don't
also have to compare the the Instants separately.
Similarly, negative Durations would enable the `Duration::sum()` method
suggested by Ignace, and would avoid making intermediate results
fallible. As an example:
$d = Duration::fromHours(1)->sub(Duration::fromSeconds(1)); // 59
minutes and 59 seconds
$d->sub(Duration::fromMinutes(60))->add(Duration::fromSeconds(30));
// subtract 59 minutes and 30 seconds
Representing a subtraction of 59 minutes and 30 seconds as a subtraction
of 60 minutes and an addition of 30 seconds would not reliably be
possible without negative Durations, which I would also consider to be
unexpected. Users would need to write:
$d->sub(Duration::fromMinutes(60)->sub(Duration::fromSeconds(30));
// subtract 59 minutes and 30 seconds
for it to work, which might not match their intuition of tackling the
problem.
Java does not have property hooks (as far as I know) but PHP now has.
That's very powerful and makes it possible to hide implementation
details without exposing everything as getters.
$duration->seconds // 0-59
$duration->totalSeconds
$duration->nanoseconds // 0 - 999_999_999
$duration->totalNanoseconds
$duration->milliseconds // 0 - 999
$duration->totalMilliseconds
// maybe later
$duration->picoseconds // 0 - 999_999_999_999
$duration->totalPicosecond
As a user you don't need to care that much of the internal
representation.
The currently proposed properties are intended to be used by the user
directly. That's why they are public.
Best regards
Tim Düsterhus