日期格式化与解析
本节将全面讲解 PHP 中的日期时间格式化和解析,包括 DateTime::format()、DateTime::createFromFormat()、IntlDateFormatter(国际化格式化)以及自定义格式化方案。
前置知识
阅读本节前,建议先了解:DateTime 类、DateTimeZone 时区处理
format() 格式化
完整格式字符参考
php
<?php
declare(strict_types=1);
$dt = new DateTimeImmutable('2024-01-15 14:30:45.123456');
// === 年 ===
echo $dt->format('Y') . PHP_EOL; // 2024 (4位)
echo $dt->format('y') . PHP_EOL; // 24 (2位)
// === 月 ===
echo $dt->format('m') . PHP_EOL; // 01 (2位,前导零)
echo $dt->format('n') . PHP_EOL; // 1 (无前导零)
echo $dt->format('F') . PHP_EOL; // January (完整英文名)
echo $dt->format('M') . PHP_EOL; // Jan (缩写)
// === 日 ===
echo $dt->format('d') . PHP_EOL; // 15 (2位)
echo $dt->format('j') . PHP_EOL; // 15 (无前导零)
echo $dt->format('S') . PHP_EOL; // th (英文序数后缀)
echo $dt->format('z') . PHP_EOL; // 14 (年中第几天)
// === 时间 ===
echo $dt->format('H') . PHP_EOL; // 14 (24小时制)
echo $dt->format('h') . PHP_EOL; // 02 (12小时制)
echo $dt->format('g') . PHP_EOL; // 2 (12小时制,无零)
echo $dt->format('i') . PHP_EOL; // 30 (分钟)
echo $dt->format('s') . PHP_EOL; // 45 (秒)
echo $dt->format('u') . PHP_EOL; // 123456 (微秒)
echo $dt->format('v') . PHP_EOL; // 123 (毫秒, PHP 7.1+)
// === AM/PM ===
echo $dt->format('A') . PHP_EOL; // PM
echo $dt->format('a') . PHP_EOL; // pm
// === 时区 ===
echo $dt->format('e') . PHP_EOL; // Asia/Shanghai (时区标识符)
echo $dt->format('T') . PHP_EOL; // CST (时区缩写)
echo $dt->format('Z') . PHP_EOL; // 28800 (UTC 偏移秒)
echo $dt->format('P') . PHP_EOL; // +08:00 (UTC 偏移)
// === 周和日 ===
echo $dt->format('w') . PHP_EOL; // 1 (周几,0=周日)
echo $dt->format('N') . PHP_EOL; // 1 (ISO-8601,1=周一)
echo $dt->format('l') . PHP_EOL; // Monday (完整周几名)
echo $dt->format('D') . PHP_EOL; // Mon (缩写)
echo $dt->format('W') . PHP_EOL; // 03 (ISO 周数)
echo $dt->format('t') . PHP_EOL; // 31 (月份天数)
echo $dt->format('L') . PHP_EOL; // 0 (是否闰年)
// === 预定义格式 ===
echo $dt->format('c') . PHP_EOL; // ISO 8601
echo $dt->format('r') . PHP_EOL; // RFC 2822
echo $dt->format('U') . PHP_EOL; // Unix 时间戳日期函数
php
<?php
declare(strict_types=1);
// date() - 格式化时间戳
echo date('Y-m-d H:i:s') . PHP_EOL;
// strftime() - 已弃用(PHP 8.1+),使用 IntlDateFormatter 替代
// gmdate() - UTC 时间格式化
echo gmdate('Y-m-d H:i:s') . PHP_EOL;
// checkdate() - 验证日期有效性
var_dump(checkdate(2024, 2, 29)); // bool(false) 2024是闰年?不是
var_dump(checkdate(2024, 2, 29)); // 实际 2024 非闰年
var_dump(checkdate(2023, 2, 29)); // bool(false)
// getdate() - 获取日期详细信息
$info = getdate();
print_r($info);createFromFormat 解析
常见日期格式解析
php
<?php
declare(strict_types=1);
$formats = [
// 数据库日期时间格式
['Y-m-d H:i:s', '2024-01-15 14:30:00'],
['Y-m-d', '2024-01-15'],
// 中文格式
['Y年m月d日', '2024年1月15日'],
['Y年m月d日 H时i分', '2024年1月15日 14时30分'],
// 紧凑格式
['Ymd', '20240115'],
['YmdHis', '20240115143000'],
// 英文格式
['d/m/Y', '15/01/2024'],
['m/d/Y', '01/15/2024'],
['d M Y', '15 Jan 2024'],
['M j, Y', 'Jan 15, 2024'],
// ISO 格式
['Y-m-d\TH:i:sP', '2024-01-15T14:30:00+08:00'],
['Y-m-d\TH:i:s\Z', '2024-01-15T06:30:00Z'],
// 自定义格式
['Y.m.d', '2024.01.15'],
];
foreach ($formats as [$format, $string]) {
$dt = DateTimeImmutable::createFromFormat($format, $string);
if ($dt !== false) {
echo "'{$string}' => " . $dt->format('Y-m-d H:i:s') . PHP_EOL;
} else {
echo "'{$string}' => 解析失败" . PHP_EOL;
}
}带时区的解析
php
<?php
declare(strict_types=1);
// 解析时指定时区
$dt = DateTimeImmutable::createFromFormat(
'Y-m-d H:i:s',
'2024-01-15 14:30:00',
new DateTimeZone('America/New_York')
);
echo "纽约时间: " . $dt->format('Y-m-d H:i:s e') . PHP_EOL;
echo "UTC 时间: " . $dt->setTimezone(new DateTimeZone('UTC'))->format('Y-m-d H:i:s e') . PHP_EOL;解析错误处理
php
<?php
declare(strict_types=1);
// 获取解析错误
$result = DateTime::createFromFormat('Y-m-d', '2024-13-45');
if ($result === false) {
$errors = DateTime::getLastErrors();
echo "警告数量: " . $errors['warning_count'] . PHP_EOL;
echo "错误数量: " . $errors['error_count'] . PHP_EOL;
print_r($errors['warnings']);
print_r($errors['errors']);
}实战示例
日期工具类
php
<?php
declare(strict_types=1);
class DateFormatter
{
/**
* 格式化为中文日期
*/
public static function toChinese(DateTimeInterface $dt): string
{
$weekdays = ['日', '一', '二', '三', '四', '五', '六'];
$w = $weekdays[(int) $dt->format('w')];
return sprintf(
'%d年%d月%d日 星期%s %02d:%02d',
(int) $dt->format('Y'),
(int) $dt->format('m'),
(int) $dt->format('d'),
$w,
(int) $dt->format('H'),
(int) $dt->format('i')
);
}
/**
* 友好的时间显示
*/
public static function friendly(DateTimeInterface $dt): string
{
$now = new DateTimeImmutable();
$diff = $dt->diff($now);
if ($diff->days === 0) {
if ($diff->h === 0) {
if ($diff->i === 0) {
return '刚刚';
}
return $diff->i . ' 分钟前';
}
return $diff->h . ' 小时前';
}
if ($diff->days === 1) {
return '昨天 ' . $dt->format('H:i');
}
if ($diff->days < 7) {
return $diff->days . ' 天前';
}
if ($diff->days < 30) {
return (int) ($diff->days / 7) . ' 周前';
}
return $dt->format('Y-m-d');
}
/**
* 计算过期时间
*/
public static function expiresAt(int $minutes): string
{
$dt = new DateTimeImmutable();
$dt = $dt->add(new DateInterval("PT{$minutes}M"));
return $dt->format(DateTimeInterface::ATOM);
}
}
echo DateFormatter::toChinese(new DateTimeImmutable('2024-01-15 14:30:00'));
echo DateFormatter::friendly(new DateTimeImmutable('-2 hours'));
echo DateFormatter::friendly(new DateTimeImmutable('-3 days'));注意事项
format()区分大小写,注意Y/y、m/M的区别- 使用
createFromFormat解析不明确日期时注意时区 strftime()在 PHP 8.1 中已弃用
下一节
继续学习:HRTime 高精度计时