PHP工作日计算怎么做

wen PHP项目 4

本文目录导读:

PHP工作日计算怎么做

  1. 方法一:简单循环计算(最常用)
  2. 方法二:排除节假日
  3. 方法三:高效数学计算(大数据量)
  4. 方法四:增加工作日
  5. 方法五:使用第三方库 Carbon(推荐)
  6. 实用完整示例
  7. 注意事项

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";
?>

注意事项

  1. 节假日数据:法定节假日每年会变化,建议从配置文件或数据库获取
  2. 时区设置:确保服务器时区设置正确:date_default_timezone_set('Asia/Shanghai')
  3. 性能考虑:大数据量计算建议使用数学方法(方法三)
  4. 边界情况:注意起始日期和结束日期的包含关系

选择哪种方法取决于你的具体需求:

  • 简单计算日期差:方法一
  • 需要节假日配置:方法二、五
  • 大规模计算:方法三
  • 常用且完整:方法五(Carbon库)

抱歉,评论功能暂时关闭!