PHP date('u') 永远输出零——datetime(6) 微秒精度静默丢失
某天在排查一个后台管理系统的数据问题时,发现批量写入的记录按 create_time 排序后顺序完全乱掉了。数据库字段类型是 datetime(6),本意是用微秒区分同一秒内的多条记录——但查库一看,所有时间戳清一色以 .000000 结尾。没有任何报错,代码跑得毫无违和感,数据就这样悄悄烂掉了。
现象
- MySQL 列类型
datetime(6),期待亚秒精度 - PHP 写入时使用
date('Y-m-d H:i:s.u')格式化当前时间 - 入库后所有记录的微秒部分均为
.000000 - 毫秒级批量操作中,多条记录
create_time完全相同,排序失去意义
根因
PHP 的 date() 函数接受的时间戳参数是 Unix integer(整数秒),本身不携带任何亚秒信息。格式符 u 在文档里确实列出来了,含义是"微秒"——但 date() 内部拿到整数秒后,微秒部分永远是零,所以输出永远是 000000。
这是 PHP 的设计行为,不是 bug,但文档的措辞非常容易让人误以为 date('u') 能返回当前时间的微秒。
与之相对,DateTime 对象在构造时(new DateTime())会从系统时钟抓取完整的微秒精度,保存在内部结构里;DateTime::format('u') 读取的正是这个内部值,因此能输出真实微秒。
echo date('Y-m-d H:i:s.u');
// 输出:2026-03-15 10:00:00.000000 ← 永远是零即便你的 MySQL 列是 datetime(6),写进去的也只有秒级精度。
没有 warning,没有 exception,数据静默截断。
正解
换用 DateTime::format(),它从对象内部读取微秒,而不是从整数时间戳里推算:
// 错误写法
$time = date('Y-m-d H:i:s.u');
// 正确写法
$time = (new \DateTime())->format('Y-m-d H:i:s.u');验证对比:
echo date('Y-m-d H:i:s.u');
// 2026-03-15 10:00:00.000000 ← 全零
echo (new \DateTime())->format('Y-m-d H:i:s.u');
// 2026-03-15 10:00:00.482351 ← 真实微秒如果项目里多处需要微秒时间戳,封装成静态 helper 最稳:
private static function now(): string
{
return (new \DateTime())->format('Y-m-d H:i:s.u');
}如果你持有的是一个 microtime(true) 浮点数,想从中取微秒,也不能走 date(),需要先转换为 DateTime:
$dt = \DateTime::createFromFormat('U.u', number_format(microtime(true), 6, '.', ''));
echo $dt->format('Y-m-d H:i:s.u');(new \DateTime())->format('Y-m-d H:i:s.u') 能输出真实微秒。
凡是需要写入 datetime(6) 列、或依赖亚秒精度排序的场景,一律用这个。
PHP 官方手册在 date() 的格式符表格里确实写了 u = Microseconds,但紧接着有一句小字:「Since PHP 5.2.2, this character is not yet implemented in the date() function itself(……在 date() 函数本身中尚未实现)」。很容易扫一眼就跳过。
一句话外卖
PHP
date()的时间戳是整数秒,格式符u在其中永远为零;需要微秒精度,必须用DateTime::format()。