优先用 date_format() 配合 DateTime 对象,而非 date();因 DateTime 支持时区切换、日期计算、格式解析等完整功能,而 date() 仅支持时间戳格式化且易出错。

date() 和 date_format() 用哪个?
直接说结论:优先用 date_format() 配合 DateTime 对象,而不是老式 date()。因为 date() 只能处理时间戳,无法处理时区切换、日期加减、格式解析等常见需求;而 DateTime 是面向对象的完整时间处理体系,可读性高、扩展性强、不易出错。
典型错误是把字符串直接塞进 date():
date('Y-m-d', '2024-05-20');——这会报 Warning: date() expects parameter 2 to be int, string given,因为第二个参数必须是整型时间戳。
-
date()仅适用于已知时间戳(如time()、strtotime()返回值)的简单格式化 -
DateTime支持从字符串构造(自动识别常见格式)、支持modify()、add()、diff()、setTimezone() - 跨时区场景下,
date()完全无解;DateTime可以轻松切换:$dt->setTimezone(new DateTimeZone('Asia/Shanghai'))
strtotime() 的坑在哪?
strtotime() 看似方便,但隐含大量歧义和兼容性问题。它依赖系统 locale 和内部解析规则,对模糊输入(如 "last Monday"、"next month")行为不一致,尤其在 PHP 7.3+ 和 8.x 中有细微差异。
常见翻车点:
立即学习“PHP免费学习笔记(深入)”;
-
strtotime('2024-02-30')不报错,返回2024-03-01(自动进位),但你可能想要报错提示输入非法 -
strtotime('01/02/2024')在 en_US 下是 Jan 2,但在 zh_CN 环境下可能被误判为 Feb 1(取决于date_default_timezone_set()和系统设置) - 无法指定输入格式,纯靠猜——遇到
"20240520"或"2024-5-20"就容易解析失败
替代方案更可控:
$dt = DateTime::createFromFormat('Y-m-d', '2024-05-20');
if (!$dt || $dt->format('Y-m-d') !== '2024-05-20') {
throw new InvalidArgumentException('Invalid date format');
}
时区设置为什么总失效?
根本原因:PHP 有两个独立的时区控制层——全局默认时区(date_default_timezone_set())和每个 DateTime 实例自带的时区(DateTimeZone)。只设前者,不代表所有 DateTime 对象都按此运行。
例如:
date_default_timezone_set('Asia/Shanghai');
$dt = new DateTime('2024-05-20'); // ✅ 此时按东八区解析
$dt2 = new DateTime('2024-05-20', new DateTimeZone('UTC')); // ❌ 此时按 UTC 解析,与上一行行为不同
- 新建
DateTime时不传第二个参数,才使用date_default_timezone_set()设置的值 - 数据库存的是 UTC 时间?那就统一用
new DateTime($db_time, new DateTimeZone('UTC'))构造,再转本地显示 - 避免混用:
date()函数永远只认全局时区,不会感知对象时区;所以不要拿date('c', $dt->getTimestamp())去“模拟”对象格式化
格式化输出要注意什么?
用 date_format() 或 DateTime::format() 时,字符含义和大小写敏感,且部分字符在不同 PHP 版本中行为有差异。
高频误写:
-
'Y-m-d H:i:s'✅ 正确(24小时制);'Y-m-d h:i:s'❌ 是 12 小时制,没 AM/PM 会显示 01~12,容易误导 -
'm'是补零月份(01~12),'n'是无补零(1~12);'d'和'j'同理 -
'U'输出 Unix 时间戳(秒级整数),但DateTime::getTimestamp()更明确,推荐后者 - 需要毫秒?PHP 原生不支持毫秒格式符,得手动拼:
$dt->format('Y-m-d H:i:s.') . sprintf('%03d', $dt->format('u') / 1000)
复杂格式建议封装成方法,而不是反复写长字符串——比如 ISO 8601 带毫秒的格式,一次写对,复用即可。











