本文目录导读:

- 传统方式(老函数)的痛点
- 现代化方式:
DateTime类家族(PHP 5.2+) - 不可变对象:
DateTimeImmutable(PHP 5.5+) - 终极方便:第三方库 Carbon
- 总结:现在到底有多方便?
PHP 的日期时间处理在 PHP 5.2 之后开始变得非常方便,PHP 5.5+ 之后更是达到了“好用”的程度,如果你还在用 date()、strtotime()、time() 这些老函数,可能会觉得“还行”,但一旦你使用了 DateTime、DateInterval、DateTimeImmutable 以及 Carbon(第三方库),你会发现之前的操作简直是“刀耕火种”。
下面我分几个阶段来告诉你 PHP 日期时间处理的演进和现状,并重点说明“现在有多方便”。
传统方式(老函数)的痛点
// 老方式:操作字符串,容易出错
$today = date('Y-m-d');
$nextWeek = date('Y-m-d', strtotime('+1 week')); // 需要手动解析字符串
$diff = (strtotime('2024-01-10') - strtotime('2024-01-01')) / 86400; // 计算天数,且需手动除以86400
痛点:
strtotime解析字符串易因格式问题返回false。- 日期计算(加/减天数)需要手动转换时间戳,再格式化。
- 时区处理非常繁琐,需要
date_default_timezone_set。 - 比较两个日期需要转时间戳,代码可读性差。
现代化方式:DateTime 类家族(PHP 5.2+)
从 PHP 5.2 开始,官方引入了 DateTime、DateInterval、DateTimeZone 等类,日期时间处理变得面向对象、链式调用、清晰易懂。
示例 1:创建与格式化
$dt = new DateTime('2024-01-01 12:00:00');
echo $dt->format('Y-m-d H:i:s'); // 2024-01-01 12:00:00
示例 2:日期计算(+1周)
$dt = new DateTime('2024-01-01');
$dt->add(new DateInterval('P1W')); // P1W 表示“Period 1 Week”
echo $dt->format('Y-m-d'); // 2024-01-08
示例 3:计算两个日期的差
$start = new DateTime('2024-01-01');
$end = new DateTime('2024-01-10');
$diff = $start->diff($end);
echo $diff->days; // 9
// 也可以得到更详细的差值:$diff->y, $diff->m, $diff->d
示例 4:时区处理
$dt = new DateTime('now', new DateTimeZone('Asia/Shanghai'));
echo $dt->format('Y-m-d H:i:s'); // 上海时间
$dt->setTimezone(new DateTimeZone('America/New_York'));
echo $dt->format('Y-m-d H:i:s'); // 自动转换到纽约时间
相比传统函数,DateTime 类已经非常方便,没有歧义、没有字符串拼接、没有时间戳转换。
不可变对象:DateTimeImmutable(PHP 5.5+)
DateTime 对象是可变的,意味着 add()、modify() 会修改原对象,容易引起意外。
$dt = new DateTime('2024-01-01');
$dt->add(new DateInterval('P1D'));
// $dt 已经变成了 2024-01-02,原对象被修改。
DateTimeImmutable 解决了这个问题:
$dt = new DateTimeImmutable('2024-01-01');
$newDt = $dt->add(new DateInterval('P1D'));
// $dt 仍然是 2024-01-01
// $newDt 是 2024-01-02
非常推荐使用 DateTimeImmutable,特别是在函数参数传递或需要保持原始日期不变时。
终极方便:第三方库 Carbon
如果你觉得官方的 DateTime 还不够“语法糖”,Carbon(基于 DateTime 的扩展库)会让日期时间处理变得像魔法一样。
安装: composer require nesbot/carbon
示例对比:
| 功能 | 官方 DateTime | Carbon |
|---|---|---|
| 创建日期 | new DateTime('2024-01-01') |
Carbon::parse('2024-01-01') / Carbon::create(2024,1,1) |
| 明天 | $dt->add(new DateInterval('P1D')) |
Carbon::tomorrow() |
| 昨天 | 手动计算 | Carbon::yesterday() |
| 1周后 | $dt->add(new DateInterval('P1W')) |
$dt->addWeek() / now()->addWeek() |
| 判断是否周末 | 需要 format('w') |
$dt->isWeekend() |
| 人性化时间差 | 无 | $dt->diffForHumans() -> "3 hours ago" |
| 日期比较 | $dt1 > $dt2 可以,但需注意类型 |
$dt1->gt($dt2) / $dt1->eq($dt2) |
| 时区链式 | $dt->setTimezone(new DateTimeZone('...')) |
$dt->timezone('Asia/Shanghai') |
Carbon 示例:
use Carbon\Carbon;
// 创建
$dt = Carbon::parse('2024-01-01 12:00:00');
echo $dt->isoFormat('LL'); // January 1, 2024
// 相对时间
echo Carbon::now()->subDays(3)->diffForHumans(); // 3 days ago
// 日期判断
$dt = Carbon::now();
if ($dt->isWeekend()) {
echo 'Happy weekend!';
}
if ($dt->isFuture()) {
echo 'This is in the future';
}
Carbon 是目前 PHP 社区最流行的日期时间库,几乎成为了事实标准,如果你的项目可以使用 Composer,强烈推荐使用。
现在到底有多方便?
| 操作场景 | 老方式(手动计算) | 现代方式(DateTime) | 终极方式(Carbon) |
|---|---|---|---|
| 加1个月 | date('Y-m-d', strtotime('+1 month', strtotime($date))) |
$dt->add(new DateInterval('P1M')) |
$dt->addMonth() |
| 计算天数差 | (strtotime($d2)-strtotime($d1))/86400 |
$d1->diff($d2)->days |
$d1->diffInDays($d2) |
| 时区转换 | 改全局、手动加减 | $dt->setTimezone(new DateTimeZone(...)) |
$dt->timezone('...') |
| 人类可读 | 无 | 无 | $dt->diffForHumans() |
| 链式操作 | 不支持 | 支持(但对象可变) | 支持(且不可变) |
最终结论:
- PHP 5.2+ 以后,借助
DateTime/DateTimeImmutable,日期时间处理已经非常方便,不再需要手动处理时间戳。 - PHP 7+ 以后,结合 Carbon,日期处理达到了“优雅、直观、强大”的程度,几乎可以媲美 Python 的
datetime或 JavaScript 的moment.js。 - PHP 8.x),你可以完全抛弃
strtotime()和date()的复杂用法,享受现代化 API 带来的便利。
建议:
- 如果你的项目刚起步或可以使用 Composer,直接用 Carbon。
- 如果必须限制依赖(或者你觉得官方类够用),使用
DateTimeImmutable,并避免直接操作DateTime的可变实例。 - 永远不要再用
strtotime()进行日期计算(除非是非常简单的字符串解析),容易被日期格式和时区坑到。