fix: carry numeric round/floor/ceil precision >= 60s into minute/hour/day

A numeric $precision passed to round()/floor()/ceil() is always resolved
to the "second" unit. Once the precision reaches or exceeds 60 (e.g.
round(3600) meaning "nearest hour"), the rounding stayed confined to the
second field (range 0-59) and never carried into minute/hour/day, unlike
the equivalent string form (round('hour')).

Re-target the unit to minute/hour/day once the numeric precision reaches
that unit's own span in seconds, rescaling the precision accordingly,
mirroring the existing week -> day re-targeting already in roundUnit().
Sub-minute numeric precisions are unaffected.
This commit is contained in:
dualfroz committed 2026-09-06 01:25:01 +02:00
1 parent 06596ca5df
commit 5192615f4e
2 files changed
+50

No files matched your search

+18
View File
@@ -70,6 +70,24 @@ trait Rounding
$precision *= $factor;
// A numeric precision is in seconds, so once it spans the next coarser
// unit it must be re-targeted there, like "week" -> "day" above.
if ($normalizedUnit === 'second' && (\is_int($precision) || \is_float($precision))) {
$secondsPerHour = static::MINUTES_PER_HOUR * static::SECONDS_PER_MINUTE;
$secondsPerDay = static::HOURS_PER_DAY * $secondsPerHour;
if ($precision >= $secondsPerDay) {
$normalizedUnit = 'day';
$precision /= $secondsPerDay;
} elseif ($precision >= $secondsPerHour) {
$normalizedUnit = 'hour';
$precision /= $secondsPerHour;
} elseif ($precision >= static::SECONDS_PER_MINUTE) {
$normalizedUnit = 'minute';
$precision /= static::SECONDS_PER_MINUTE;
}
}
if (!isset($ranges[$normalizedUnit])) {
throw new UnknownUnitException($unit);
}