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

PHP中计算排除节假日与周末的有效工作时长(秒级)实现咨询

PHP计算符合工作规则的时长实现思路与代码

核心思路拆解

要计算指定时间区间内符合「周一至周五9:00-17:00+排除指定节假日」的有效时长,可按以下步骤处理:

  1. 标准化时间格式:将输入的开始/结束时间转换为DateTime对象,统一处理时区(建议用业务时区避免偏差)。
  2. 定义规则常量:明确工作日范围(周一到周五,对应DateTime::format('N')返回1-5)、每日工作时长(9:00到17:00,共28800秒)、排除的节假日列表(转成Y-m-d格式的字符串数组)。
  3. 分场景计算时长:
    • 若开始/结束时间在同一天:直接判断当天是否为有效工作日,再计算当天内的有效时段差值。
    • 若跨多天:拆分三部分计算:开始当天的有效时长、中间完整天数的有效时长、结束当天的有效时长,最后求和。

代码实现

function calculateWorkDuration(string $startTime, string $endTime): int {
    // 定义规则
    $workStartHour = '09:00:00';
    $workEndHour = '17:00:00';
    $holidays = [
        '2023-08-15',
        '2023-11-01',
        '2023-11-11',
        '2023-12-25'
    ];
    $dailyWorkSeconds = 8 * 3600; // 9-17点共8小时

    // 转换为DateTime对象(假设输入为Y-m-d H:i:s格式,可根据实际调整createFromFormat参数)
    $start = new DateTime($startTime);
    $end = new DateTime($endTime);

    // 处理开始时间晚于结束时间的异常情况
    if ($start > $end) {
        return 0;
    }

    $totalSeconds = 0;

    // 情况1:开始和结束在同一天
    if ($start->format('Y-m-d') === $end->format('Y-m-d')) {
        $dateStr = $start->format('Y-m-d');
        // 判断是否为工作日且非节假日
        if ($start->format('N') >= 1 && $start->format('N') <=5 && !in_array($dateStr, $holidays)) {
            $workStart = new DateTime($dateStr . ' ' . $workStartHour);
            $workEnd = new DateTime($dateStr . ' ' . $workEndHour);

            // 确定实际计算的起始和结束点
            $actualStart = max($start, $workStart);
            $actualEnd = min($end, $workEnd);

            if ($actualStart < $actualEnd) {
                $totalSeconds = $actualEnd->getTimestamp() - $actualStart->getTimestamp();
            }
        }
        return $totalSeconds;
    }

    // 情况2:跨多天,先计算开始当天的有效时长
    $startDateStr = $start->format('Y-m-d');
    if ($start->format('N') >=1 && $start->format('N') <=5 && !in_array($startDateStr, $holidays)) {
        $workEnd = new DateTime($startDateStr . ' ' . $workEndHour);
        if ($start < $workEnd) {
            $actualStart = max($start, new DateTime($startDateStr . ' ' . $workStartHour));
            $totalSeconds += $workEnd->getTimestamp() - $actualStart->getTimestamp();
        }
    }

    // 计算结束当天的有效时长
    $endDateStr = $end->format('Y-m-d');
    if ($end->format('N') >=1 && $end->format('N') <=5 && !in_array($endDateStr, $holidays)) {
        $workStart = new DateTime($endDateStr . ' ' . $workStartHour);
        if ($end > $workStart) {
            $actualEnd = min($end, new DateTime($endDateStr . ' ' . $workEndHour));
            $totalSeconds += $actualEnd->getTimestamp() - $workStart->getTimestamp();
        }
    }

    // 计算中间完整天数的有效时长
    $currentDate = clone $start;
    $currentDate->modify('+1 day');
    while ($currentDate->format('Y-m-d') < $endDateStr) {
        $dateStr = $currentDate->format('Y-m-d');
        if ($currentDate->format('N') >=1 && $currentDate->format('N') <=5 && !in_array($dateStr, $holidays)) {
            $totalSeconds += $dailyWorkSeconds;
        }
        $currentDate->modify('+1 day');
    }

    return $totalSeconds;
}

// 测试示例:2023-10-28 07:00:00 到 2023-11-03 10:00:00
$duration = calculateWorkDuration('2023-10-28 07:00:00', '2023-11-03 10:00:00');
echo "有效时长(秒):" . $duration; // 输出90000(3天*8小时 + 1小时 = 25小时 = 90000秒)

关键细节说明

  • 时区处理:如果业务涉及跨时区,建议在创建DateTime对象时指定时区(如new DateTime($startTime, new DateTimeZone('Asia/Shanghai'))),避免时间偏差。
  • 节假日扩展:若节假日需要动态获取,可将$holidays数组替换为数据库查询或内部接口返回的结果。
  • 边界情况覆盖:代码处理了开始时间晚于结束时间、当天完全在工作时段外、节假日刚好在工作日等场景。

内容的提问来源于stack exchange,提问作者executable

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 00:36:14