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

Reply via email to