PHP date_isodate_set() 函数
date_isodate_set() 函数是 DateTime::setISODate() 的过程化别名,用于根据 ISO 8601 标准设置日期。它使用年、周数和星期几来设置 DateTime 对象的日期。
提示: ISO 8601 是国际标准化组织制定的日期和时间表示方法标准,广泛应用于商业和国际交流中。
语法
DateTime date_isodate_set ( DateTime $object , int $year , int $week [, int $day = 1 ] )
参数说明
| 参数 |
描述 |
必需 |
默认值 |
$object |
DateTime 对象,表示要修改的日期时间 |
是 |
- |
$year |
ISO 8601 年份 |
是 |
- |
$week |
ISO 周数(1-53) |
是 |
- |
$day |
星期几(1=周一,7=周日) |
否 |
1 |
返回值
- 返回修改后的 DateTime 对象
- 原始 DateTime 对象也会被修改
- 支持链式调用
ISO 8601 标准说明
ISO 8601 日期标准特点:
- 一周从星期一开始,星期日是一周的第七天
- 一年的第一周是包含该年第一个星期四的那一周
- 一年有52或53周
- 日期格式:YYYY-Www-D(如 2024-W11-1 表示2024年第11周星期一)
- 常用于欧洲国家、商业和国际交流
示例代码
示例 1:基本用法
<?php
// 创建 DateTime 对象
$date = date_create('2024-03-15 14:30:00');
echo "原始日期: " . date_format($date, 'Y-m-d H:i:s') . "<br>";
// 设置为2024年第11周星期一(ISO周)
date_isodate_set($date, 2024, 11, 1);
echo "修改后日期: " . date_format($date, 'Y-m-d H:i:s') . "<br>";
echo "ISO格式: " . date_format($date, 'Y-\WW-N') . "<br>";
echo "详细: " . date_format($date, 'Y年 第W周 星期N') . "<br>";
/*
输出:
原始日期: 2024-03-15 14:30:00
修改后日期: 2024-03-11 14:30:00
ISO格式: 2024-W11-1
详细: 2024年 第11周 星期1
*/
?>
示例 2:不同的星期几
<?php
// 显示2024年第11周的所有日子
$year = 2024;
$week = 11;
echo "{$year}年第{$week}周的每一天:<br><br>";
for ($day = 1; $day <= 7; $day++) {
$date = date_create();
date_isodate_set($date, $year, $week, $day);
$dayNames = [
1 => '星期一',
2 => '星期二',
3 => '星期三',
4 => '星期四',
5 => '星期五',
6 => '星期六',
7 => '星期日'
];
echo "星期{$day} ({$dayNames[$day]}): " .
date_format($date, 'Y-m-d l') .
" (ISO: " . date_format($date, 'Y-\WW-N') . ")<br>";
}
// 特殊示例:一年的最后一周
echo "<br>特殊示例 - 一年的最后一周:<br>";
$lastWeekDates = date_create();
date_isodate_set($lastWeekDates, 2024, 53, 1); // 2024年有53周
echo "2024年第53周星期一: " . date_format($lastWeekDates, 'Y-m-d') . "<br>";
// 验证:2025年第1周
$firstWeek2025 = date_create();
date_isodate_set($firstWeek2025, 2025, 1, 1);
echo "2025年第1周星期一: " . date_format($firstWeek2025, 'Y-m-d') . "<br>";
?>
示例 3:与普通日期函数对比
<?php
// 对比 ISO 周日期和普通日期设置
echo "ISO周日期与普通日期设置对比:<br><br>";
// 使用date_isodate_set设置ISO周日期
$date1 = date_create('2024-01-01');
date_isodate_set($date1, 2024, 11, 3); // 2024年第11周星期三
echo "ISO周设置 (2024-W11-3): " . date_format($date1, 'Y-m-d') . "<br>";
// 使用date_modify设置相同日期
$date2 = date_create('2024-01-01');
date_modify($date2, '2024-03-13');
echo "普通日期设置 (2024-03-13): " . date_format($date2, 'Y-m-d') . "<br><br>";
// 显示两种方法得到相同结果
echo "两个日期是否相同: " . ($date1 == $date2 ? '是' : '否') . "<br><br>";
// 计算周数差异
function getWeekDifference($startDate, $endDate) {
$start = date_create($startDate);
$end = date_create($endDate);
$startWeek = date_format($start, 'W');
$endWeek = date_format($end, 'W');
$startYear = date_format($start, 'Y');
$endYear = date_format($end, 'Y');
if ($startYear == $endYear) {
return $endWeek - $startWeek;
} else {
// 简化计算:实际应用需要考虑跨年
return "跨年计算,需要更复杂的逻辑";
}
}
// 测试周数计算
$dateA = '2024-03-01';
$dateB = '2024-03-31';
echo "从 {$dateA} 到 {$dateB} 的周数差: " . getWeekDifference($dateA, $dateB) . " 周";
?>
示例 4:实用场景 - 周报系统
<?php
// 实用场景:周报系统
class WeeklyReportSystem {
/**
* 获取指定年份和周数的日期范围
*/
public static function getWeekDateRange($year, $week) {
$startDate = date_create();
date_isodate_set($startDate, $year, $week, 1); // 周一
$endDate = clone $startDate;
date_add($endDate, date_interval_create_from_date_string('6 days')); // 周日
return [
'year' => $year,
'week' => $week,
'start' => date_format($startDate, 'Y-m-d'),
'end' => date_format($endDate, 'Y-m-d'),
'start_formatted' => date_format($startDate, 'Y年m月d日 (l)'),
'end_formatted' => date_format($endDate, 'Y年m月d日 (l)'),
'iso_format' => date_format($startDate, 'Y-\WW'),
];
}
/**
* 获取当前周信息
*/
public static function getCurrentWeekInfo() {
$now = date_create();
$year = date_format($now, 'o'); // ISO年份
$week = date_format($now, 'W'); // ISO周数
$day = date_format($now, 'N'); // ISO星期几(1-7)
return self::getWeekDateRange($year, $week);
}
/**
* 生成周报文件名
*/
public static function generateWeeklyReportName($year, $week, $department = '') {
$range = self::getWeekDateRange($year, $week);
$name = "周报_{$year}年第{$week}周_{$range['start']}-{$range['end']}";
if ($department) {
$name .= "_{$department}";
}
$name .= '.pdf';
return $name;
}
/**
* 获取未来N周的周信息
*/
public static function getFutureWeeks($weeksAhead = 4) {
$result = [];
$current = self::getCurrentWeekInfo();
for ($i = 0; $i < $weeksAhead; $i++) {
$year = $current['year'];
$week = $current['week'] + $i;
// 处理跨年
if ($week > 53) {
// 简化处理:实际应检查该年是否有53周
$week = $week - 53;
$year++;
}
$result[] = self::getWeekDateRange($year, $week);
}
return $result;
}
}
echo "周报系统演示:<br><br>";
// 当前周信息
$currentWeek = WeeklyReportSystem::getCurrentWeekInfo();
echo "<strong>当前周信息:</strong><br>";
echo "年份: {$currentWeek['year']}<br>";
echo "周数: {$currentWeek['week']}<br>";
echo "日期范围: {$currentWeek['start']} 至 {$currentWeek['end']}<br>";
echo "格式化: {$currentWeek['start_formatted']} - {$currentWeek['end_formatted']}<br>";
echo "ISO格式: {$currentWeek['iso_format']}<br><br>";
// 特定周信息
$specificWeek = WeeklyReportSystem::getWeekDateRange(2024, 11);
echo "<strong>2024年第11周信息:</strong><br>";
echo "日期范围: {$specificWeek['start']} 至 {$specificWeek['end']}<br><br>";
// 生成周报文件名
echo "<strong>周报文件名示例:</strong><br>";
echo WeeklyReportSystem::generateWeeklyReportName(2024, 11) . "<br>";
echo WeeklyReportSystem::generateWeeklyReportName(2024, 11, '技术部') . "<br><br>";
// 未来四周信息
echo "<strong>未来四周信息:</strong><br>";
$futureWeeks = WeeklyReportSystem::getFutureWeeks(4);
foreach ($futureWeeks as $weekInfo) {
echo "第{$weekInfo['week']}周: {$weekInfo['start']} - {$weekInfo['end']}<br>";
}
?>
示例 5:错误处理与边界情况
<?php
// 错误处理和边界情况示例
function safeSetIsoDate($date, $year, $week, $day = 1) {
// 验证参数有效性
if ($week < 1 || $week > 53) {
return "错误: 周数必须在1-53之间";
}
if ($day < 1 || $day > 7) {
return "错误: 星期几必须在1-7之间(1=周一,7=周日)";
}
// 检查该年是否有53周
if ($week == 53) {
$lastDayOfYear = date_create("{$year}-12-31");
$lastWeekOfYear = date_format($lastDayOfYear, 'W');
if ($lastWeekOfYear < 53) {
return "错误: {$year}年只有{$lastWeekOfYear}周";
}
}
// 执行设置
try {
$result = date_isodate_set($date, $year, $week, $day);
if ($result === false) {
return "错误: 设置ISO日期失败";
}
return [
'success' => true,
'date' => date_format($date, 'Y-m-d'),
'iso_format' => date_format($date, 'Y-\WW-N'),
'day_of_week' => date_format($date, 'l'),
'message' => "设置成功",
];
} catch (Exception $e) {
return "异常: " . $e->getMessage();
}
}
echo "错误处理与边界情况测试:<br><br>";
$testCases = [
['year' => 2024, 'week' => 11, 'day' => 3, 'desc' => '正常情况'],
['year' => 2024, 'week' => 53, 'day' => 1, 'desc' => '第53周(2024年有53周)'],
['year' => 2023, 'week' => 53, 'day' => 1, 'desc' => '第53周(2023年只有52周)'],
['year' => 2024, 'week' => 0, 'day' => 1, 'desc' => '周数过小'],
['year' => 2024, 'week' => 54, 'day' => 1, 'desc' => '周数过大'],
['year' => 2024, 'week' => 11, 'day' => 0, 'desc' => '星期几过小'],
['year' => 2024, 'week' => 11, 'day' => 8, 'desc' => '星期几过大'],
];
foreach ($testCases as $test) {
$date = date_create('2024-01-01');
$result = safeSetIsoDate($date, $test['year'], $test['week'], $test['day']);
echo "测试: {$test['desc']} (Y={$test['year']}, W={$test['week']}, D={$test['day']})<br>";
if (is_array($result) && $result['success']) {
echo "✅ 成功: {$result['date']} ({$result['iso_format']}, {$result['day_of_week']})<br>";
} else {
echo "❌ 失败: {$result}<br>";
}
echo "<br>";
}
// 显示不同年份的周数情况
echo "<strong>不同年份的周数统计:</strong><br>";
$years = [2020, 2021, 2022, 2023, 2024, 2025];
foreach ($years as $year) {
$lastDay = date_create("{$year}-12-31");
$weekCount = date_format($lastDay, 'W');
$isLeapYear = date('L', strtotime("{$year}-01-01")) ? '是' : '否';
echo "{$year}年: {$weekCount}周 (闰年: {$isLeapYear})<br>";
}
echo "<br>注意:一年有53周的条件是该年的1月1日是星期四,或者闰年时1月1日是星期三。";
?>
ISO 8601 周计算规则
| 规则 |
描述 |
示例 |
| 一周开始 |
每周从星期一开始 |
星期一 = 1,星期日 = 7 |
| 第一周定义 |
包含该年第一个星期四的那一周 |
2024年第一周从1月1日开始 |
| 最后一周 |
包含该年最后一个星期四的那一周 |
2024年最后一周是第53周 |
| 周数范围 |
一年有52或53周 |
平年通常52周,闰年可能53周 |
| 跨年日期 |
年初的几天可能属于上一年的最后一周 |
2024年1月1日属于2024年第1周 |
注意事项
重要提示:
- ISO周从星期一开始,星期日结束(与某些地区周日开始的习惯不同)
- 一年中的第一周是包含该年第一个星期四的那一周
- 一年可能有52或53周,取决于该年的第一天是星期几
- date_isodate_set() 会修改原始 DateTime 对象
- 星期参数的范围是1-7,1表示星期一,7表示星期日
- 周数参数的范围是1-53,但并非所有年份都有53周
- 时间部分(时、分、秒)保持不变
常见问题
| 方面 |
ISO 8601 周 |
普通周 |
| 每周开始 |
星期一 |
取决于地区(周日或周一) |
| 第一周定义 |
包含当年第一个星期四的周 |
1月1日所在的周 |
| 周数编号 |
1-52或53 |
可能从0或1开始 |
| 国际标准 |
是 |
否 |
| 应用场景 |
商业、国际交流、欧洲 |
日常使用 |
一年有53周的条件:
- 普通年份(非闰年)的1月1日是星期四
- 闰年的1月1日是星期三或星期四
PHP代码判断:
<?php
function has53Weeks($year) {
$lastDay = date_create("{$year}-12-31");
$weekNumber = date_format($lastDay, 'W');
return $weekNumber == 53;
}
$years = [2020, 2021, 2022, 2023, 2024, 2025];
foreach ($years as $year) {
echo "{$year}年有" . (has53Weeks($year) ? '53' : '52') . "周<br>";
}
?>
ISO周相关格式化字符
| 字符 |
描述 |
示例 |
o |
ISO 8601 年份 |
2024 |
W |
ISO 8601 周数(带前导零) |
01, 11, 52 |
N |
ISO 8601 星期几(1-7) |
1(周一)到 7(周日) |
Y-\WW-N |
完整ISO周格式 |
2024-W11-3 |
Y-\WW |
ISO周格式(无星期几) |
2024-W11 |
相关函数
| 函数 |
描述 |
DateTime::setISODate() |
面向对象的ISO周日期设置方法 |
date_create() |
创建DateTime对象 |
date_format() |
格式化DateTime对象 |
date('W') |
获取ISO周数 |
date('o') |
获取ISO年份 |
date('N') |
获取ISO星期几 |
strtotime() |
解析英文文本日期时间 |