本文目录导读:

在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)
- 中大型项目:使用第三方API获取实时数据(方案2)
- 生产环境:结合本地缓存+API更新(方案4)
注意事项:
- 区域差异:不同国家/地区的节假日不同
- 更新时间:节假日数据需要每年更新
- 性能优化:对大量日期计算时,建议使用缓存
- 农历计算:中国节假日涉及农历,建议使用专业库
可以使用的PHP农历计算库:
# 安装农历计算库 composer require cmixin/holidays composer require overtrue/chinese-calendar
可以选择根据项目需求选择合适的方案,对于大多数国内项目,建议使用方案4的完整实现。