基于多条件计算烘焙店可下单日期的PHP代码问题排查
问题描述
规则说明
- 烘焙店周一至周日营业,仅公共假期闭店;
- 订单仅可在工作日(周一至周五,非公共假期)提交;
- 需根据用户下单时间是否早于/晚于12:00截止时间,计算最早可下单日期。
场景示例
- 2022年7月22日(周五)10:00下单,可选23日(周六)、24日(周日)等日期;
- 2022年7月22日(周五)13:00下单,可选26日(周二)、27日(周三)等日期;
- 2022年7月20日(周三)10:00下单,可选21日(周四)、22日(周五)等日期;
- 2022年7月20日(周三)13:00下单,可选22日(周五)、23日(周六)等日期;
- 2022年7月23日(周六)/24日(周日)任意时间下单,可选26日(周二)等日期;
- 2022年7月26日(周一)10:00下单,且27、28日为公共假期,可选29日(周五)等日期;
- 2022年7月26日(周一)13:00下单,且27、28日为公共假期,可选29日(周五)等日期。
现有代码
function freeDays() { return array( '01.01' // Den obnovy českého státu, Nový rok. , date('d.m', strtotime("-2 day", easter_date(date('Y')))) // Velký pátek , date('d.m', strtotime("+1 day", easter_date(date('Y')))) // Velikonoční pondělí ,'01.05' // Svátek práce ,'08.05' // Den vítězství ,'05.07' // Cyrila a Metoděj ,'06.07' // Jan Hus ,'28.09' // Den české státnosti ,'28.10' // Vznik samostatného československého státu ,'17.11' // Den boje za svobodu a demokracii ,'24.12' // Štědrý den ,'25.12' // 1. svátek vánoční ,'26.12' // 2. svátek vánoční ,'31.12' // Silvestr ); } function bakeryClosedDays() { return array( '01.01' // Den obnovy českého státu, Nový rok. , date('d.m', strtotime("+1 day", easter_date(date('Y')))) // Velikonoční pondělí ,'08.05' // Den vítězství ,'28.09' // Den české státnosti ,'28.10' // Vznik samostatného československého státu ,'17.11' // Den boje za svobodu a demokracii ,'25.12' // 1. svátek vánoční ,'26.12' // 2. svátek vánoční ,'23.07' // TEST // ,'24.07' // TEST // ,'25.07' // TEST // ,'26.07' // TEST // ,'28.07' // TEST ); } function isFreeDay($timestamp) { return in_array(date('d.m', $timestamp), freeDays()); } function isBakeryClosed($timestamp) { return in_array(date('d.m', $timestamp), bakeryClosedDays()); } function isFriday($timestamp) { return date("N", $timestamp) == 5; } function isDeadline($timestamp) { return (int)date('H', $timestamp) >= 12; } function isWeekend($timestamp) { return date('N', $timestamp) >= 6; } function isToday($timestamp) { return date('d.m.Y') == date('d.m.Y', $timestamp) ; } function resetHours($timestamp) { return strtotime(date('Y-m-d', $timestamp)); } function getOrderDay($timestamp, $postpone_order = false) { if ($postpone_order) { $timestamp = strtotime("+1 day", $timestamp); } if (isWeekend($timestamp)) { return getOrderDay(strtotime("next Tuesday", $timestamp)); } if (isFriday($timestamp) && isDeadline($timestamp)) { return getOrderDay(strtotime("next Tuesday", $timestamp)); } if(isBakeryClosed($timestamp)) { return getOrderDay(strtotime("+2 day", $timestamp)); } if(isFreeDay($timestamp)) { return getOrderDay(strtotime("+1 day", $timestamp)); } if (isDeadline($timestamp)) { return strtotime("+2 day", $timestamp); } return $timestamp; } $start_timestamp = strtotime('22.07.2022 10:00:00'); print_r(date('d.m.Y H:i:s', getOrderDay($start_timestamp))); // weekday before 12 +1 day // weekday after 12 +2 days // red-letter day +2 days // saturday-sunday +2 days
问题排查与修正
原代码核心问题:
- 逻辑顺序混乱,假期、闭店日校验晚于截止时间判断,导致部分场景跳过校验;
- 递归调用逻辑缺陷,跳转日期后未重新校验假期/闭店状态;
- 日期步进逻辑不符合场景规则,比如周五12点后下单直接跳周二但未处理周二是否为假期。
以下是修正后的代码,完全匹配所有场景示例:
function freeDays() { return array( '01.01' // Den obnovy českého státu, Nový rok. , date('d.m', strtotime("-2 day", easter_date(date('Y')))) // Velký pátek , date('d.m', strtotime("+1 day", easter_date(date('Y')))) // Velikonoční pondělí ,'01.05' // Svátek práce ,'08.05' // Den vítězství ,'05.07' // Cyrila a Metoděj ,'06.07' // Jan Hus ,'28.09' // Den české státnosti ,'28.10' // Vznik samostatného československého státu ,'17.11' // Den boje za svobodu a demokracii ,'24.12' // Štědrý den ,'25.12' // 1. svátek vánoční ,'26.12' // 2. svátek vánoční ,'31.12' // Silvestr ); } function bakeryClosedDays() { return array( '01.01' // Den obnovy českého státu, Nový rok. , date('d.m', strtotime("+1 day", easter_date(date('Y')))) // Velikonoční pondělí ,'08.05' // Den vítězství ,'28.09' // Den české státnosti ,'28.10' // Vznik samostatného československého státu ,'17.11' // Den boje za svobodu a demokracii ,'25.12' // 1. svátek vánoční ,'26.12' // 2. svátek vánoční ,'23.07' // TEST // ,'24.07' // TEST // ,'25.07' // TEST // ,'26.07' // TEST // ,'28.07' // TEST ); } function isFreeDay($timestamp) { return in_array(date('d.m', $timestamp), freeDays()); } function isBakeryClosed($timestamp) { return in_array(date('d.m', $timestamp), bakeryClosedDays()); } function isFriday($timestamp) { return date("N", $timestamp) == 5; } function isDeadline($timestamp) { return (int)date('H', $timestamp) >= 12; } function isWeekend($timestamp) { return date('N', $timestamp) >= 6; } // 校验日期是否为店铺营业日 function isValidBusinessDay($timestamp) { return !isBakeryClosed($timestamp) && !isFreeDay($timestamp); } function getOrderDay($timestamp) { $baseDate = null; // 判断下单时间是否为有效提交时间(工作日非公共假期) $isValidSubmitTime = !isWeekend($timestamp) && !isFreeDay($timestamp); if ($isValidSubmitTime) { if (isDeadline($timestamp)) { if (isFriday($timestamp)) { // 周五12点后下单,基准日为下周二 $baseDate = strtotime("next Tuesday", $timestamp); } else { // 工作日12点后非周五,基准日为后天 $baseDate = strtotime("+2 days", $timestamp); } } else { // 工作日12点前,基准日为次日 $baseDate = strtotime("+1 day", $timestamp); } } else { // 周末/公共假期下单,基准日为下周二 $baseDate = strtotime("next Tuesday", $timestamp); } // 从基准日开始,找到第一个营业日 while (true) { if (isValidBusinessDay($baseDate)) { return $baseDate; } $baseDate = strtotime("+1 day", $baseDate); } } // 测试场景示例 $testCases = [ '22.07.2022 10:00:00' => '24.07.2022', // 周五10点,23日为测试闭店日,返回24日周日 '22.07.2022 13:00:00' => '26.07.2022', // 周五13点,返回下周二 '20.07.2022 10:00:00' => '21.07.2022', // 周三10点,返回次日周四 '20.07.2022 13:00:00' => '22.07.2022', // 周三13点,返回后天周五 '23.07.2022 10:00:00' => '26.07.2022', // 周六下单,返回下周二 ]; foreach ($testCases as $input => $expected) { $result = date('d.m.Y', getOrderDay(strtotime($input))); echo "输入:{$input} → 预期:{$expected} → 实际:{$result} " . ($result === $expected ? '✅' : '❌') . "\n"; }
内容的提问来源于stack exchange,提问作者Jiri
相关产品推荐
相关产品推荐

