最稳妥方法是先用 strtotime() 将日期字符串转为时间戳并严格检查是否为 false,再用 time() 减得差值(秒),按区间 if/else 分段格式化为“x分钟前”等提示,全程使用 utc 时间戳、强制设置时区、文案可配置。

PHP 用 strtotime() 解析日期字符串再计算差值最稳妥
直接拿用户传来的字符串(比如 "2024-03-15 14:22:08" 或 "2 days ago")去算“几分钟前”,得先转成时间戳。别跳过这步——很多报错或结果为 false 都是因为 strtotime() 返回了 false,而你没检查。
-
strtotime()支持常见格式,但对中文、不规范空格、时区缩写(如"CST")容易失败,建议统一用 ISO 8601 格式输入 - 如果来源是数据库字段(如 MySQL 的
DATETIME),直接传给strtotime()没问题;但如果是用户自由输入,务必加=== false判断 - 注意 PHP 版本差异:7.3+ 对微秒支持更好,但
strtotime("now + 1.5 hours")这类写法在旧版本可能出错
用 time() 当前时间减去目标时间戳,再分段判断区间
“刚刚”“2分钟前”“3天前”这些提示不是靠魔法生成的,就是靠一个整数差值(单位:秒)做 if/else 分段。别试图用第三方库封装一层就以为省事了——逻辑一复杂,调试时反而更难定位哪段条件漏了。
- 常见区间划分:0–59 秒 → “刚刚”;60–3599 秒 → “X分钟前”;3600–86399 秒 → “X小时前”;86400–518399 秒(≤6天)→ “X天前”;超过 6 天就回退到标准格式
date('Y-m-d', $ts) - 别用
round($diff / 3600)算小时数,用floor($diff / 3600)更符合直觉(比如 1 小时 59 分还是显示“1小时前”,不是“2小时前”) - 注意夏令时切换日可能出现负差值(比如系统时区设为
America/New_York,而时间戳来自 UTC),建议全程用 UTC 时间戳做运算
中文提示里“天”“小时”“分钟”不能硬编码进函数,要可配置
上线后运营说“把‘分钟前’改成‘分前’”,或者要支持多语言,这时候如果所有字符串都写死在 if 分支里,改起来就是全文件搜索替换,还容易漏。
- 把提示文案抽成关联数组,比如:
$lang = ['second' => '秒前', 'minute' => '分钟前', 'hour' => '小时前', 'day' => '天前'] - 别用
str_replace()动态拼接,比如$num . $lang['minute'],避免数字和单位之间被插入空格或换行符 - 如果项目已用 gettext 或 Laravel 的
__(),优先走现有 i18n 流程,别另起一套
注意 date_default_timezone_set() 不生效导致本地测试正常、线上出错
本地开发环境默认时区可能是 Asia/Shanghai,但生产服务器可能是 UTC 或未设置。这时候 time() 和 strtotime() 返回的时间戳基准不一致,“5分钟前”可能变成“5小时后”。
立即学习“PHP免费学习笔记(深入)”;
- 上线前必须确认 php.ini 中
date.timezone已设,或代码开头强制调用date_default_timezone_set('Asia/Shanghai') - 不要依赖
getdate()或date('Y-m-d H:i:s')的输出来反推时区是否正确——它们只反映当前设置,不验证设置是否生效 - 最容易忽略的是 CLI 模式下时区可能和 Web 模式不同(比如 cron 脚本),建议在入口文件第一行就设好
真正麻烦的不是写不出这个函数,而是时间戳来源混杂(MySQL、Redis、API 返回、用户表单)、时区设置分散、还有缓存导致时间判断卡在旧值上——这些地方不动手查日志、打点输出,光看代码永远看不出问题。










