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