Laravel Carbon计算商品折扣剩余时分异常问题求助
解决Carbon计算折扣剩余时分出现负数的问题
看起来你遇到的核心问题是时间差的计算方向错误,以及条件判断逻辑的疏漏,导致出现了负数剩余时长。我来帮你拆解问题并给出正确的实现方式:
为什么会出现负数?
先看你提供的测试数据:
- 商品创建时间:
2020-05-26 23:40:15(莫斯科时区) - 当前时间:
2020-05-30 18:51:23(莫斯科时区)
你的小时计算逻辑里有两个致命问题:
- 条件判断错误:你用
if ($diff == 7)来触发小时通知,但$diff是天数差,此时实际天数差是3天左右,这个条件根本不会触发;只有当折扣超过7天的时候,$diff ==7才会成立,但此时diff_hours会大于168(一周的小时数),168 - diff_hours自然会得到负数。 - 时间差方向错误:
diffInHours默认返回两个时间的绝对差值,如果不指定时间先后顺序,当当前时间超过折扣到期时间时,已过去的时长会大于总时长,导致剩余时长为负。
正确的剩余时分计算方法
核心思路是:先算出折扣的到期时间(创建时间+7天),再直接计算当前时间到到期时间的正向差值,Carbon会自动处理时间先后逻辑,避免负数。
完整实现代码
// 1. 计算折扣到期时间(创建时间加7天) $expiresAt = $item->created_at->copy()->addDays(7); $realTime = Carbon::now(); // 2. 仅当折扣未到期时,计算剩余时长并发送通知 if ($realTime->lt($expiresAt)) { // 分别计算剩余的天、小时、分钟(按需组合显示) $remainingDays = $realTime->diffInDays($expiresAt); $remainingHours = $realTime->diffInHours($expiresAt) % 24; // 扣除整天数后的剩余小时 $remainingMinutes = $realTime->diffInMinutes($expiresAt) % 60; // 扣除整小时后的剩余分钟 // 组装多维度的剩余时间消息(支持俄语复数) $messageSegments = []; if ($remainingDays > 0) { $messageSegments[] = "{$remainingDays} " . Lang::choice('day|days|', $remainingDays, [], 'ru'); } if ($remainingHours > 0) { $messageSegments[] = "{$remainingHours} " . Lang::choice('hour|hours|', $remainingHours, [], 'ru'); } if ($remainingMinutes > 0) { $messageSegments[] = "{$remainingMinutes} " . Lang::choice('minute|minutes|', $remainingMinutes, [], 'ru'); } $message = 'Discount will be available for ' . implode(', ', $messageSegments); // 创建通知 Notify::create([ 'user_id' => $this->user->id, 'title' => 'Message', 'message' => $message, 'status' => '2', ]); }
针对你的测试数据验证
按你的测试时间计算,折扣到期时间是2020-06-02 23:40:15,当前时间到到期时间的剩余时长为:
- 3天、5小时、49分钟
代码会正确输出类似Discount will be available for 3 days, 5 hours, 49 minutes的消息,完全不会出现负数。
简化版(仅显示剩余小时)
如果不需要拆分天和分钟,只想直接显示剩余总小时数,可以用更简洁的写法:
$expiresAt = $item->created_at->copy()->addDays(7); $realTime = Carbon::now(); if ($realTime->lt($expiresAt)) { $remainingHours = $realTime->diffInHours($expiresAt); Notify::create([ 'user_id' => $this->user->id, 'title' => 'Message', 'message' => "Discount will be available {$remainingHours} " . Lang::choice('hour|hours|', $remainingHours, [], 'ru'), 'status' => '2', ]); }
此时你的测试数据会得到77 hours的正确结果,而非负数。
内容的提问来源于stack exchange,提问作者mouse_ua
相关产品推荐
相关产品推荐

