写接口日志时想给每条记录带上毫秒,方便对齐前后端时间线。同事随手写了个 date('H:i:s'),结果同一秒里的十条日志时间一模一样,排序全乱。
microtime 返回什么
microtime(true) 返回浮点秒,形如 1712345678.1234,小数部分就是微秒;microtime(false) 返回字符串,格式是 0.12345600 1712345678,空格前是小数秒,空格后是整秒。要毫秒用浮点那种最省事,注意 float 只有约 15 位有效数字,整数秒加小数刚好够用。
拿毫秒时间戳
$ms = (int) round(microtime(true) * 1000);
乘 1000 再取整就是 13 位毫秒时间戳。用 floor 还是 round 差别不大,日志里用 floor 更符合这一毫秒的直觉。别直接把浮点结果打印出来,会出现 1712345678123.4 这种带尾巴的数。
格式化成可读时间
$t = microtime(true);
$ms = sprintf('%03d', ($t - floor($t)) * 1000);
echo date('Y-m-d H:i:s', (int) $t) . '.' . $ms;
思路是把整数秒交给 date,小数部分单独补三位,%03d 保证 7 这样的值补成 007。时区要正确,脚本开头先 date_default_timezone_set 设成 Asia/Shanghai,否则时间会差 8 小时。
几点提醒
- 别用 date('u'):它输出微秒六位,混进毫秒字段会多出三位。
- 用 DateTime:$dt->format('v') 直接给三位毫秒,格式化更整齐。
- 性能:microtime 很轻,循环里调用不用心疼,但别在循环里反复 new DateTime。
- 精度上限:PHP 拿不到真正的纳秒,宣称微秒以下精度的都别信。