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

PHP连续跨月日期分月工作日数统计问题排查

问题分析

你的统计结果偶尔少1天,核心原因有两个:

  1. 日期解析歧义:直接用strtotime()解析无分隔符的ddmmyyyy格式(如26102022)时,PHP可能无法正确识别日/月顺序,生成错误的时间戳。
  2. 时间戳循环的隐患:按86400秒(1天)递增时间戳的方式,遇到夏令时切换等特殊日期时会导致日期计算偏差;同时月末时间戳默认的00:00:00时间部分,可能引发重复或遗漏统计。
解决方案

1. 正确解析ddmmyyyy格式日期

手动拆分字符串,转换为PHP能准确识别的Ymd格式,再生成DateTime对象(比时间戳更可靠):

// 处理起始日期 $start = '26102022'
$day = substr($start, 0, 2);
$month = substr($start, 2, 2);
$year = substr($start, 4, 4);
$startYmd = "$year$month$day"; // 得到 '20221026'
$startDateTime = DateTime::createFromFormat('Ymd', $startYmd);

// 处理结束日期 $end = '06112022'
$dayEnd = substr($end, 0, 2);
$monthEnd = substr($end, 2, 2);
$yearEnd = substr($end, 4, 4);
$endYmd = "$yearEnd$monthEnd$dayEnd"; // 得到 '20221106'
$endDateTime = DateTime::createFromFormat('Ymd', $endYmd);

2. 准确获取月末日期并转为Ymd格式

用DateTime类的modify()方法直接获取当月最后一天,格式化为Ymd:

// 获取起始日期所在月份的最后一天
$lastDayOfStartMonth = clone $startDateTime;
$lastDayOfStartMonth->modify('last day of this month');
$lastDayYmd = $lastDayOfStartMonth->format('Ymd'); // 得到 '20221031'

3. 重写工作日统计函数(规避时间戳问题)

改用DateTime对象循环,彻底避免时间戳的夏令时和解析误差:

public function workingDays($startYmd, $endYmd) {
    $start = DateTime::createFromFormat('Ymd', $startYmd);
    $end = DateTime::createFromFormat('Ymd', $endYmd);
    
    if (!$start || !$end) {
        return 0; // 日期格式错误时返回0
    }
    
    $workingDays = 0;
    $current = clone $start;
    
    while ($current <= $end) {
        // N表示周一到周日(1-7),仅统计1-5的工作日
        if ($current->format('N') <= 5) {
            $workingDays++;
        }
        $current->modify('+1 day');
    }
    
    return $workingDays;
}

4. 分月统计工作日

注意避免重复统计月末当天,第一个周期为起始日期到月末,第二个周期为月末次日到结束日期:

// 统计第一个月(10月)的工作日
$daysInFirstMonth = $this->workingDays($startYmd, $lastDayYmd);

// 获取月末次日的Ymd格式
$nextDayOfLastMonth = clone $lastDayOfStartMonth;
$nextDayOfLastMonth->modify('+1 day');
$nextDayYmd = $nextDayOfLastMonth->format('Ymd');

// 统计第二个月(11月)的工作日
$daysInSecondMonth = $this->workingDays($nextDayYmd, $endYmd);

// 总工作日数
$totalWorkingDays = $daysInFirstMonth + $daysInSecondMonth;
验证示例

以你的测试日期为例:

  • 10月26日到10月31日:工作日为4天(26日周三、27日周四、28日周五、31日周一)
  • 11月1日到11月6日:工作日为4天(1日周二、2日周三、3日周四、4日周五)
  • 总工作日:8天,与实际一致

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 17:36:31