Hi

Am 2026-06-22 17:11, schrieb ignace nyamagana butera:
I concur with Marc remarks especially if we want to add a divmod like
method this simple example shows the issue one would run into with the
current constraints.

 $duration = Duration::fromHours(3)->negate();

$factor = Duration::fromHours(1);
[$count, $remainder] = $duration->divmod($factor);
// using BCMath implementation for the example !
//[-3, Duration::fromSeconds(0)] is returned in the tuple

Duration::sum(
$factor->multiplyBy($count), // with the current constraints this will throw
    $remainder,
);

I would personally find [3, Duration::fromSeconds(0)] (i.e. ignoring the sign) to be a reasonable reply to the question “how often can I fit this duration into the other duration”.

In fact the output of a `divmod()` would be very confusing when the divisor doesn't divide the dividend, since the result of the modulo operator is always positive (see also: https://stackoverflow.com/a/13683709):

$duration = Duration::fromMinutes(3 * 60 + 20)->negate(); // negative 3:20 hours
    $factor = Duration::fromMinutes(60); // 1 hour

    $duration->divmod($factor);
// [-4, Duration::fromMinutes(40)] = (-4 * 60 minutes) + 40 minutes = negative 3:20 hours

A `divrem()` (“remainder”) would be:

$duration = Duration::fromMinutes(3 * 60 + 20)->negate(); // negative 3:10 hours
    $factor = Duration::fromMinutes(60); // 1 hour

    $duration->divrem($factor);
// [-3, Duration::fromMinutes(20)->negate()] = (-3 * 60 minutes) - 20 minutes = negative 3:20 hours

In my opinion, implementing "Duration divided by Duration" as a remainder operation is the only reasonable choice here and “ignoring the sign” to avoid the entire “modulo vs remainder” discussion would be reasonable when the method is appropriately named.

Staying with the IEEE-754 comparison for the sign-magnitude representation, I could also imagine adding a “copysign” method matching the `copysign()` function (https://man7.org/linux/man-pages/man3/copysign.3.html).

The example would then be:

Duration::sum($factor->multiplyBy($count), $remainder)->copysign($duration);

If we feel that the “Duration divided by Duration” *should* be able to return negative values, then lifting the `>= 0` restriction of `multiplyBy()` would also easily be possible.

Best regards
Tim Düsterhus

Reply via email to