如何计算指定时间后的 5 个小时的时间,这段时间不能包含下班时间(18:00-09:00)

应用场景

产生订单后,客服需要在 5 个小时内及时处理,如果不处理订单就自动取消。但是 18:00 - 09:00 这段时间是下班时间,可以不处理。如何计算出正确的执行延迟队列的时间
5小时这个数字是自定义的,可以设置为任意数字(包含小数),所以可能包含跨两个夜晚的情况

示例

订单产生时间为 2023-10-08 15:00,那么正确的取消订单的时间为 2023-10-09 11:00

《L04 微信小程序从零到发布》
从小程序个人账户申请开始,带你一步步进行开发一个微信小程序,直到提交微信控制台上线发布。
《G01 Go 实战入门》
从零开始带你一步步开发一个 Go 博客项目,让你在最短的时间内学会使用 Go 进行编码。项目结构很大程度上参考了 Laravel。
讨论数量: 26

订单产生的时间你是知道的呀,然后你获取自定义的时间间隔(比如是5),用订单时间加上自定义时间,看 小时 的那里是否落在了 0-9 和 18-23,如果是的话,你再加15个小时,不就获得了需要延时执行的时间了吗? 订单产生时间为 2023-10-08 15:00,加5个小时为 2023-10-08 20:00,小时落在了 18-23 这个区间,所以在 2023-10-08 20:00 基础上加15个小时,得到 2023-10-09 11:00

6个月前 评论
IT学徒 6个月前
feng435263069 (楼主) 6个月前

就是个计算逻辑,你正常延时时间为5*3600=18000s。这个时候先计算当前时间是否大于当天18:00,是的话,直接第二天9点+18000即为关闭时间。如果当前时间小于18点,则用18点的时间戳-当前时间,如果结果大于18000,则表示5小时后,还不到下班时间,直接用当前时间+18000位关闭时间。如果小于18000,则结束时间为第二天9点+(18000-上一侧小于的那个值)。不知道理解的对不对

6个月前 评论
feng435263069 (楼主) 6个月前
helloStar (作者) 6个月前
feng435263069 (楼主) 6个月前

先计算订单的超时时间 = 订单开始时间 + 自定义时间 如果计算出来的时间 在18:00以后 则更正为真正的失效时间

如果订单在18:00 - 09:00之内 就分为两种情况 订单的超时时间 = 订单开始时间 + 自定义时间 假如超时时间还在下班时间之内那么更正失效时间为第二天的上班时间加上自定义的时间,如果超时时间在上班时间之外,自定义时间 - (超时时间-9:00)+09:00

6个月前 评论
Mutoulee

以下内容由chatGPT生成。

function calculateDeadline(DateTime $orderTime, $hours) {
    $workingStart = 9;  // 工作开始时间
    $workingEnd = 18;   // 工作结束时间
    $deadline = clone $orderTime;
    $deadline->add(new DateInterval('PT' . $hours . 'H'));

    // 如果订单在工作时间外创建,或者截止时间在工作时间外,需要进行调整
    if ($orderTime->format('H') < $workingStart || $orderTime->format('H') >= $workingEnd || $deadline->format('H') < $workingStart || $deadline->format('H') >= $workingEnd) {
        // 计算订单创建时间到当天工作结束的剩余时间
        $remainingHoursToday = $workingEnd - $orderTime->format('H');
        if ($remainingHoursToday < 0) {
            $remainingHoursToday = 0;
        }

        // 如果剩余时间小于所需时间,那么截止时间将在第二天的工作时间内
        if ($remainingHoursToday < $hours) {
            $hours -= $remainingHoursToday;
            $deadline = clone $orderTime;
            $deadline->setTime($workingStart, 0, 0);
            $deadline->add(new DateInterval('P1D'));  // 增加一天
            $deadline->add(new DateInterval('PT' . $hours . 'H'));
        } else {
            if ($deadline->format('H') >= $workingEnd) {
                $overHours = $deadline->format('H') - $workingEnd;
                $deadline->setTime($workingStart + $overHours, 0, 0);
                $deadline->add(new DateInterval('P1D'));  // 增加一天
            }
        }
    }

    return $deadline;
}

$orderTime = new DateTime();  // 假设现在就是订单生成的时间
$hours = 5;  // 客服需要在5小时内处理订单
$deadline = calculateDeadline($orderTime, $hours);
echo $deadline->format('Y-m-d H:i:s');  // 输出订单的截止时间
6个月前 评论

下班时间 和 处理时间都 从配置里获取 然后 创建订单或者是 支付完成的时候去算 客服处理有效期就行了

6个月前 评论

订单时间 与 下班时间 18:00 相差小时数 X 小于等于 指定时间间隔 N (这里为5), 取消订单时间为 09:00 加上 (N-X) 个小时 :flushed: 不知道行不行

6个月前 评论
Mr_Guo 6个月前

处理时间  =  5 * 3600
今日剩余时间  =  下班时间减订单产生时间  > 0?下单时间减订单产生时间:0
if(今日剩余时间 > 处理时间){
 取消订单时间  = 订单产生时间 + 处理时间
}
第二天剩余时间 = 处理时间减今日剩余时间
上班总时间 =18:00-9:00*3600
if(第二天剩余时间> 上班总时间){
天数 = 第二天剩余时间%上班总时间

间隔上班总时间=天数*上班总时间

取消订单时间=(今天+1+天数)的9:00+(第二天剩余时间-间隔上班总时间)
}
取消订单时间  = 第二天上班时间 + 第二天剩余时间
6个月前 评论
GDDD 6个月前
小猪蹄子 (作者) 6个月前
IT学徒 6个月前
小猪蹄子 (作者) 6个月前
小猪蹄子 (作者) 6个月前

初始化三个变量1.当前时钟初始值为订单时间2.处理剩余时间(题目中是5)3.累计时间,向前推进距离订单时间的小时数

三个方法1潜进器,当前时钟落在9-18点外,潜进至下个9点,时钟更新至9,累计时间增加(到9点的时差),剩余时间不变。2.探进器,时钟落在9-18点,探进至18点,如未探过18点,则剩余时间减至0,累计时间增加,如探过18点,剩余时间减少(到18点的距离),累计时间到18点,时钟至18点。3调度器,判断时钟在9-18内还是外,决定调用潜进器还是探进器,潜进器和探进器调用后都再次调用调度器,直到剩余时间为0,三个方法都不会再调用,执行完毕,此时订单时间加上累计时间即截止时间。

以节点向前推,哪些累加,哪些减少,就这么个思路,可以完善一下,比如时钟换成日期,理论上传入一个时间点,也可以计算当前剩余时间

6个月前 评论

也可用分配来解决 大概逻辑:

$order_at = Carnbon()->now();
        $cancel_time = 3600 * 5; //  把每秒算一个分配点

        while($cancel_time >= 0) {
            $time = 0; // 可用分配点 声明
            if ($order_at->isToday()) { // 如果是今天 则上班时间为当前
                $start_at = Carbon::now();
            }else{ // 否则上班时间为 第二天的9:00:00  因为循环 每次都会+1天
                $start_at = $order_at->addDay(1)->setTime(9,0,0);
            }

            // 求上班时间 到 下班时间可用的分配点 (下班时间 - 上班时间)
            $time = $order_at->clone()->setTime(18,0,0)->sub(
                $start_at
            )->toSec(); // clone是为了不影响$order_at对象 ps:函数我可能记错 肯定有这些方法
            if($cancel_time  > $time){
                $time = $cancel_time; // 时间足够了 不需要使用最大时间
            }

            $cancel_time -= $time;
            $start_at->addSeconds($time); // 增加秒数
            $order_at = $start_at;
        }
6个月前 评论
feng435263069 (楼主) 6个月前

1.正常工作日 2.周末(要考虑特色) 3.节假日

6个月前 评论
feng435263069 (楼主) 6个月前

不考虑周末节假日的情况

    public function getDealDate($hour)
    {
        $second = (int) $hour * 3600;

        $leftSeconds = Carbon::today()
            ->setHour(18)
            ->diffInSeconds(Carbon::now());

        if ($second < $leftSeconds) {
            return Carbon::now()
                ->addSeconds($second)
                ->toDateTimeString();
        }

        $second -= $leftSeconds+1;

        return  Carbon::tomorrow()
            ->addDays($second / (3600 * 9))
            ->addHours(9)
            ->addSeconds($second % (3600 * 9))
            ->toDateTimeString();
    }
6个月前 评论

一个 if 解决的事情,优雅不到哪里去。

6个月前 评论

我还以为是SQL呢,想想有点难度,结果是代码啊...这不是一个if的事情吗

6个月前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!