Re: [RFC] Duration class
| From: | Larry Garfield | Date: | Mon, 22 Jun 2026 18:08:29 +0000 |
| Subject: | Re: [RFC] Duration class | ||
| References: | 1 2 3 4 5 6 7 8 9 | Groups: | php.internals |
| Request: | Send a blank email to internals+get-131472@lists.php.net to get a copy of this message | ||
On Mon, Jun 22, 2026, at 12:25 PM, Tim Düsterhus wrote:
> 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
To be clear, I absolutely hate using a static method here. Even if we're just using methods
and not operators, $dur3 = $dur1->add($dur2) is the way to go.
--Larry Garfield