You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Laravel Carbon计算商品折扣剩余时分异常问题求助

解决Carbon计算折扣剩余时分出现负数的问题

看起来你遇到的核心问题是时间差的计算方向错误,以及条件判断逻辑的疏漏,导致出现了负数剩余时长。我来帮你拆解问题并给出正确的实现方式:

为什么会出现负数?

先看你提供的测试数据:

  • 商品创建时间:2020-05-26 23:40:15(莫斯科时区)
  • 当前时间:2020-05-30 18:51:23(莫斯科时区)

你的小时计算逻辑里有两个致命问题:

  1. 条件判断错误:你用if ($diff == 7)来触发小时通知,但$diff是天数差,此时实际天数差是3天左右,这个条件根本不会触发;只有当折扣超过7天的时候,$diff ==7才会成立,但此时diff_hours会大于168(一周的小时数),168 - diff_hours自然会得到负数。
  2. 时间差方向错误: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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.07 19:17:49