本文目录导读:

PHP 工作日计算有多种实现方式,我来介绍几种常见且实用的方法:
简单循环计算(最常用)
<?php
/**
* 计算两个日期之间的工作日天数
* @param string $startDate 开始日期 Y-m-d
* @param string $endDate 结束日期 Y-m-d
* @return int 工作日天数
*/
function getWorkingDays($startDate, $endDate) {
$start = new DateTime($startDate);
$end = new DateTime($endDate);
$end->modify('+1 day'); // 包含结束日期
$workingDays = 0;
$period = new DatePeriod($start, new DateInterval('P1D'), $end);
foreach ($period as $date) {
$dayOfWeek = $date->format('N'); // 1(周一)到7(周日)
if ($dayOfWeek < 6) { // 周一至周五
$workingDays++;
}
}
return $workingDays;
}
// 使用示例
echo getWorkingDays('2024-01-01', '2024-01-31'); // 输出:23
?>
排除节假日
<?php
/**
* 计算工作日(排除节假日)
*/
class WorkingDaysCalculator {
private $holidays = [];
private $workdays = [];
/**
* 添加节假日
*/
public function addHoliday($date) {
$this->holidays[] = $date;
return $this;
}
/**
* 批量添加节假日
*/
public function addHolidays(array $dates) {
$this->holidays = array_merge($this->holidays, $dates);
return $this;
}
/**
* 添加补班日(周末上班)
*/
public function addWorkday($date) {
$this->workdays[] = $date;
return $this;
}
/**
* 计算工作日
*/
public function calculate($startDate, $endDate) {
$start = new DateTime($startDate);
$end = new DateTime($endDate);
$end->modify('+1 day');
$workingDays = 0;
$period = new DatePeriod($start, new DateInterval('P1D'), $end);
foreach ($period as $date) {
$dateStr = $date->format('Y-m-d');
$dayOfWeek = $date->format('N');
// 检查是否为补班日(周末上班)
if (in_array($dateStr, $this->workdays)) {
$workingDays++;
continue;
}
// 检查是否为节假日
if (in_array($dateStr, $this->holidays)) {
continue;
}
// 普通工作日判断
if ($dayOfWeek < 6) {
$workingDays++;
}
}
return $workingDays;
}
/**
* 获取某日期后的下一个工作日
*/
public function nextWorkingDay($date) {
$current = new DateTime($date);
while (true) {
$current->modify('+1 day');
$dateStr = $current->format('Y-m-d');
$dayOfWeek = $current->format('N');
// 跳过节假日和非周末补班
if (in_array($dateStr, $this->holidays)) {
continue;
}
if (in_array($dateStr, $this->workdays) || $dayOfWeek < 6) {
return $dateStr;
}
}
}
}
// 使用示例
$calculator = new WorkingDaysCalculator();
$calculator->addHolidays([
'2024-01-01', // 元旦
'2024-02-10', '2024-02-11', '2024-02-12', // 春节
'2024-04-04', // 清明节
'2024-05-01', // 劳动节
'2024-06-10', // 端午节
'2024-09-17', // 中秋节
'2024-10-01', // 国庆节
]);
echo $calculator->calculate('2024-01-01', '2024-01-31');
echo $calculator->nextWorkingDay('2024-01-05');
?>
高效数学计算(大数据量)
<?php
/**
* 高效计算工作日(适合大数据量)
*/
function getWorkingDaysFast($startDate, $endDate) {
$start = strtotime($startDate);
$end = strtotime($endDate);
if ($start > $end) {
return 0;
}
// 计算总天数
$totalDays = ceil(($end - $start + 86400) / 86400);
// 计算完整周数
$fullWeeks = floor($totalDays / 7);
$workingDays = $fullWeeks * 5;
// 计算剩余天数
$remainder = $totalDays % 7;
$startDay = date('N', $start);
// 处理剩余天数
for ($i = 0; $i < $remainder; $i++) {
$day = ($startDay + $i - 1) % 7 + 1;
if ($day < 6) {
$workingDays++;
}
}
return $workingDays;
}
// 使用示例
echo getWorkingDaysFast('2024-01-01', '2024-12-31'); // 全年工作日
?>
增加工作日
<?php
/**
* 在指定日期上增加工作日
*/
function addWorkingDays($startDate, $days) {
$date = new DateTime($startDate);
$added = 0;
while ($added < $days) {
$date->modify('+1 day');
if ($date->format('N') < 6) { // 周一至周五
$added++;
}
}
return $date->format('Y-m-d');
}
// 使用示例
echo addWorkingDays('2024-01-01', 10); // 从1月1日起加10个工作日
?>
使用第三方库 Carbon(推荐)
<?php
// 需要先安装 carbon: composer require nesbot/carbon
use Carbon\Carbon;
// 计算工作日
$start = Carbon::parse('2024-01-01');
$end = Carbon::parse('2024-01-31');
$workingDays = 0;
while ($start->lte($end)) {
if ($start->isWeekday()) {
$workingDays++;
}
$start->addDay();
}
echo $workingDays;
// 添加工作日
$date = Carbon::parse('2024-01-01');
$date->addWeekdays(10); // 加10个工作日
echo $date->format('Y-m-d');
?>
实用完整示例
<?php
/**
* 完整的工作日计算类(支持节假日配置)
*/
class WorkdayCalculator {
private $holidays = [];
private $workdays = [];
public function __construct($holidays = [], $workdays = []) {
$this->holidays = $holidays;
$this->workdays = $workdays;
}
public function isWorkday($date) {
$dateStr = is_string($date) ? $date : $date->format('Y-m-d');
$dayOfWeek = date('N', strtotime($dateStr));
// 补班日优先判断
if (in_array($dateStr, $this->workdays)) {
return true;
}
// 节假日判断
if (in_array($dateStr, $this->holidays)) {
return false;
}
// 正常工作日判断
return $dayOfWeek < 6;
}
public function countWorkdays($startDate, $endDate) {
$start = new DateTime($startDate);
$end = new DateTime($endDate);
$end->modify('+1 day');
$count = 0;
$period = new DatePeriod($start, new DateInterval('P1D'), $end);
foreach ($period as $date) {
if ($this->isWorkday($date)) {
$count++;
}
}
return $count;
}
public function getNextWorkday($date, $offset = 1) {
$current = new DateTime($date);
$found = 0;
while ($found < $offset) {
$current->modify('+1 day');
if ($this->isWorkday($current)) {
$found++;
}
}
return $current->format('Y-m-d');
}
public function getPreviousWorkday($date, $offset = 1) {
$current = new DateTime($date);
$found = 0;
while ($found < $offset) {
$current->modify('-1 day');
if ($this->isWorkday($current)) {
$found++;
}
}
return $current->format('Y-m-d');
}
}
// 使用示例
$calculator = new WorkdayCalculator(
// 节假日
['2024-01-01', '2024-02-10', '2024-05-01'],
// 补班日
['2024-02-04']
);
echo "2024年1月工作日:".$calculator->countWorkdays('2024-01-01', '2024-01-31')."\n";
echo "下一个工作日:".$calculator->getNextWorkday('2024-01-05')."\n";
echo "上一个工作日:".$calculator->getPreviousWorkday('2024-01-08')."\n";
?>
注意事项
- 节假日数据:法定节假日每年会变化,建议从配置文件或数据库获取
- 时区设置:确保服务器时区设置正确:
date_default_timezone_set('Asia/Shanghai') - 性能考虑:大数据量计算建议使用数学方法(方法三)
- 边界情况:注意起始日期和结束日期的包含关系
选择哪种方法取决于你的具体需求:
- 简单计算日期差:方法一
- 需要节假日配置:方法二、五
- 大规模计算:方法三
- 常用且完整:方法五(Carbon库)