PHP项目工作日判断如何排除节假日计算日期

wen PHP项目 30

本文目录导读:

PHP项目工作日判断如何排除节假日计算日期

  1. 基础方案:手动配置节假日数组
  2. 使用API获取实时节假日数据
  3. 使用第三方扩展包
  4. 完整的生产环境方案
  5. 推荐方案与注意事项

在PHP项目中排除节假日计算工作日,通常需要结合法定节假日调休上班日来实现,以下是几种常见方案的实现思路和代码示例:

基础方案:手动配置节假日数组

<?php
class WorkDayCalculator {
    private $holidays = [];      // 法定节假日
    private $workdays = [];      // 调休上班日
    public function __construct() {
        // 配置2024年节假日(示例)
        $this->holidays = [
            '2024-01-01', // 元旦
            '2024-02-10', // 春节
            '2024-02-11',
            '2024-02-12',
            // ... 其他节假日
        ];
        // 配置2024年调休上班日
        $this->workdays = [
            '2024-02-04', // 春节调休
            '2024-02-18',
            // ... 其他调休
        ];
    }
    /**
     * 判断某天是否为工作日
     */
    public function isWorkDay($date) {
        $dateStr = date('Y-m-d', strtotime($date));
        $weekDay = date('N', strtotime($date)); // 1-7, 1=周一
        // 检查是否为节假日
        if (in_array($dateStr, $this->holidays)) {
            return false;
        }
        // 检查是否为调休上班日
        if (in_array($dateStr, $this->workdays)) {
            return true;
        }
        // 检查是否为周末(周六日)
        return !in_array($weekDay, [6, 7]); // 6=周六, 7=周日
    }
    /**
     * 计算N个工作日后的日期
     */
    public function addWorkDays($startDate, $days) {
        $currentDate = strtotime($startDate);
        $addedDays = 0;
        while ($addedDays < $days) {
            $currentDate = strtotime('+1 day', $currentDate);
            if ($this->isWorkDay($currentDate)) {
                $addedDays++;
            }
        }
        return date('Y-m-d', $currentDate);
    }
    /**
     * 计算两个日期之间的工作日天数
     */
    public function countWorkDays($startDate, $endDate) {
        $workDays = 0;
        $current = strtotime($startDate);
        $end = strtotime($endDate);
        while ($current <= $end) {
            if ($this->isWorkDay($current)) {
                $workDays++;
            }
            $current = strtotime('+1 day', $current);
        }
        return $workDays;
    }
}
// 使用示例
$calculator = new WorkDayCalculator();
echo $calculator->isWorkDay('2024-02-10'); // false (春节)
echo $calculator->isWorkDay('2024-02-04'); // true (调休上班)
echo $calculator->addWorkDays('2024-01-01', 10); // 计算10个工作日后的日期
?>

使用API获取实时节假日数据

<?php
class HolidayAPICalculator {
    /**
     * 从API获取年度节假日数据
     */
    public function fetchHolidays($year) {
        $url = "https://api.apihubs.cn/holiday/get?year={$year}&month=0&size=366";
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_TIMEOUT, 30);
        $response = curl_exec($ch);
        curl_close($ch);
        $data = json_decode($response, true);
        $holidays = [];
        $workdays = [];
        if (isset($data['data']['list'])) {
            foreach ($data['data']['list'] as $item) {
                if ($item['holiday'] === 1) {
                    $holidays[] = $item['date'];
                } else if ($item['holiday'] === 2) {
                    $workdays[] = $item['date'];
                }
            }
        }
        return ['holidays' => $holidays, 'workdays' => $workdays];
    }
    // 其他方法同第一种方案...
}
?>

使用第三方扩展包

Carbon + CarbonHolidays

<?php
require 'vendor/autoload.php';
use Carbon\Carbon;
use Carbon\CarbonInterval;
use Carbon\CarbonPeriod;
// 安装: composer require cmixin/holidays
class AdvancedWorkDayCalculator {
    /**
     * 使用Carbon扩展包计算工作日
     */
    public function addWorkDaysWithCarbon($startDate, $days, $country = 'CN') {
        $carbon = Carbon::parse($startDate);
        $added = 0;
        while ($added < $days) {
            $carbon->addDay();
            // 检查是否为工作日(结合节假日)
            if (!$carbon->isHoliday() && !$carbon->isWeekend()) {
                $added++;
            }
            // 如果是调休上班日
            if ($carbon->isWorkday()) {
                $added++;
            }
        }
        return $carbon->format('Y-m-d');
    }
}
?>

完整的生产环境方案

<?php
class ProductionWorkDayCalculator {
    private $holidayData = [];
    private $rawData = [];
    public function __construct() {
        // 从文件或数据库加载预计算的节假日数据
        $this->loadHolidayData();
    }
    /**
     * 从文件加载节假日数据
     */
    private function loadHolidayData() {
        $filePath = __DIR__ . '/holidays.json';
        if (file_exists($filePath)) {
            $this->rawData = json_decode(file_get_contents($filePath), true);
        }
        // 将数据转换为易用格式
        foreach ($this->rawData as $date => $info) {
            if ($info['type'] === 'holiday') {
                $this->holidayData['holidays'][] = $date;
            } else if ($info['type'] === 'workday') {
                $this->holidayData['workdays'][] = $date;
            }
        }
    }
    /**
     * 智能工作日计算(支持排除特定日期)
     */
    public function calculateWorkDays($startDate, $days, $excludeDates = []) {
        $current = strtotime($startDate);
        $count = 0;
        $result = [];
        while ($count < $days) {
            $current = strtotime('+1 day', $current);
            $dateStr = date('Y-m-d', $current);
            // 跳过排除日期
            if (in_array($dateStr, $excludeDates)) {
                continue;
            }
            // 判断是否为工作日
            if ($this->isWorkDay($dateStr)) {
                $count++;
                $result[] = $dateStr;
            }
        }
        return $result;
    }
    /**
     * 批量判断日期是否为工作日
     */
    public function batchCheckWorkDays(array $dates) {
        $results = [];
        foreach ($dates as $date) {
            $results[$date] = $this->isWorkDay($date);
        }
        return $results;
    }
    /**
     * 获取当前年份的所有节假日
     */
    public function getYearHolidays($year = null) {
        $year = $year ?: date('Y');
        $allHolidays = [];
        // 从内置数据或API获取
        $holidays = [
            // 固定节假日
            ['name' => '元旦', 'date' => "{$year}-01-01", 'days' => 1],
            ['name' => '春节', 'date' => $this->getLunarNewYear($year), 'days' => 7],
            ['name' => '清明节', 'date' => $this->getQingMing($year), 'days' => 3],
            ['name' => '劳动节', 'date' => "{$year}-05-01", 'days' => 5],
            ['name' => '端午节', 'date' => $this->getDragonBoat($year), 'days' => 3],
            ['name' => '中秋节', 'date' => $this->getMidAutumn($year), 'days' => 3],
            ['name' => '国庆节', 'date' => "{$year}-10-01", 'days' => 7],
        ];
        foreach ($holidays as $holiday) {
            $start = strtotime($holiday['date']);
            for ($i = 0; $i < $holiday['days']; $i++) {
                $allHolidays[] = date('Y-m-d', strtotime("+{$i} day", $start));
            }
        }
        return array_unique($allHolidays);
    }
    private function isWorkDay($dateStr) {
        $weekDay = date('N', strtotime($dateStr));
        $isWeekend = in_array($weekDay, [6, 7]); // 6=周六, 7=周日
        // 节假日数据库检查
        if (in_array($dateStr, $this->holidayData['holidays'] ?? [])) {
            return false;
        }
        // 调休上班日检查
        if (in_array($dateStr, $this->holidayData['workdays'] ?? [])) {
            return true;
        }
        // 默认规则:周一至周五为工作日
        return !$isWeekend;
    }
    // 农历日期计算方法(简化版)
    private function getLunarNewYear($year) {
        // 这里应该使用农历计算库
        return "{$year}-02-10"; // 示例值
    }
    private function getQingMing($year) {
        // 清明节通常是4月4日或5日
        return "{$year}-04-04"; // 示例值
    }
    private function getDragonBoat($year) {
        // 端午节通常是农历五月初五
        return "{$year}-06-10"; // 示例值
    }
    private function getMidAutumn($year) {
        // 中秋节通常是农历八月十五
        return "{$year}-09-17"; // 示例值
    }
}
// 使用示例
$calculator = new ProductionWorkDayCalculator();
// 计算从今天起10个工作日后的日期
$workDays = $calculator->calculateWorkDays(date('Y-m-d'), 10);
print_r($workDays);
// 批量检查日期
$dates = ['2024-02-10', '2024-02-11', '2024-02-12', '2024-02-13'];
$results = $calculator->batchCheckWorkDays($dates);
print_r($results);
?>

推荐方案与注意事项

推荐方案:

  1. 小型项目:手动配置节假日数组(方案1)
  2. 中大型项目:使用第三方API获取实时数据(方案2)
  3. 生产环境:结合本地缓存+API更新(方案4)

注意事项:

  1. 区域差异:不同国家/地区的节假日不同
  2. 更新时间:节假日数据需要每年更新
  3. 性能优化:对大量日期计算时,建议使用缓存
  4. 农历计算:中国节假日涉及农历,建议使用专业库

可以使用的PHP农历计算库:

# 安装农历计算库
composer require cmixin/holidays
composer require overtrue/chinese-calendar

可以选择根据项目需求选择合适的方案,对于大多数国内项目,建议使用方案4的完整实现。

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