PHP连续跨月日期分月工作日数统计问题排查
问题分析
你的统计结果偶尔少1天,核心原因有两个:
- 日期解析歧义:直接用
strtotime()解析无分隔符的ddmmyyyy格式(如26102022)时,PHP可能无法正确识别日/月顺序,生成错误的时间戳。 - 时间戳循环的隐患:按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
相关产品推荐
相关产品推荐

