Carbon库forHumans函数的月份等价性与单位限制问题
解决Carbon库秒数转换的两个问题及配置方案
一、秒数转换结果不一致的核心原因
Carbon默认基于真实日历逻辑计算时长(比如月份天数随实际月份、闰年变化),而多数在线转换器用固定近似值(如1天=86400秒、1月=30天)硬算,两者逻辑不同自然结果有差异。比如2698447秒,Carbon会结合日历规则拆解,在线工具则直接做除法,结果必然不一致。
二、限制最大单位为days+自定义月份等价天数的方案
方案1:手动拆解计算(完全可控)
绕开Carbon的日历逻辑,直接按固定天数规则拆解秒数:
function formatSecondsToDays(int $seconds, int $daysPerMonth = 30): array { $secPerMin = 60; $secPerHour = 3600; $secPerDay = 86400; $totalDays = intdiv($seconds, $secPerDay); $remainingSec = $seconds % $secPerDay; $hours = intdiv($remainingSec, $secPerHour); $remainingSec %= $secPerHour; $minutes = intdiv($remainingSec, $secPerMin); $seconds = $remainingSec % $secPerMin; return [ 'days' => $totalDays, 'hours' => $hours, 'minutes' => $minutes, 'seconds' => $seconds, ]; } // 使用示例:转换2698447秒,按30天/月逻辑计算 $result = formatSecondsToDays(2698447); // 输出:days=31, hours=10, minutes=14, seconds=7
方案2:自定义Carbon Duration规则
如果要沿用Carbon API,可全局或局部修改单位换算逻辑,强制月份按固定天数计算,同时限制最大输出单位为days:
use Carbon\CarbonInterval; // 自定义单位映射,这里设置1月=30天,需31天则改31 CarbonInterval::setUnits([ 'second' => 1, 'minute' => 60, 'hour' => 3600, 'day' => 86400, 'month' => 86400 * 30, ]); // 创建时长并自动规整单位 $interval = CarbonInterval::seconds(2698447)->cascade(); // 格式化输出(仅保留days及以下单位) $formattedStr = $interval->format('%d days, %h hours, %i minutes, %s seconds'); // 或单独提取各单位值 $days = $interval->days; $hours = $interval->hours; $minutes = $interval->minutes; $seconds = $interval->seconds;
注意:全局修改单位会影响所有CarbonInterval实例,若仅局部需求,建议用完后调用CarbonInterval::resetUnits()恢复默认规则。
三、关于28/30天秒数的月份等价逻辑说明
Carbon默认的“月份”是真实日历月份,不是固定天数的近似值。比如28天可能被识别为1个月(对应平年2月),30天对应4/6/9/11月,这是基于真实日历的逻辑,而非固定30天=1月。如果要让28/30天秒数都按固定天数映射,直接用上述两种方案即可,完全忽略日历月份逻辑,只按固定天数拆解。
内容的提问来源于stack exchange,提问作者executable
相关产品推荐
相关产品推荐

