应使用 timestampdiff 函数获取时间差整数值,单位须大写(如 second、hour),顺序为单位、起始时间、结束时间;避免直接减法、unix_timestamp 相减或 timediff 跨天误用。

用 TIMESTAMPDIFF 精确获取秒、分钟、小时等整数单位差值
直接用减法(如 end_time - start_time)在 MySQL 中对 DATETIME 无效——它会转成类似 20230101020304 的整数再相减,结果完全不可信。正确做法是用 TIMESTAMPDIFF,它能按指定单位返回整数差值。
常见单位包括:SECOND、MINUTE、HOUR、DAY、MONTH、YEAR。注意:单位大小写敏感,必须大写。
SELECT TIMESTAMPDIFF(HOUR, '2023-05-01 09:30:00', '2023-05-02 14:45:00'); -- 返回 29
- 第一个参数是单位,第二个是起始时间,第三个是结束时间——顺序反了会得负数
- 如果字段名是
created_at和updated_at,直接代入即可:TIMESTAMPDIFF(SECOND, created_at, updated_at) - 该函数自动处理跨月、闰年、时区(只要两个值同属一个时区或都是无时区
DATETIME)
用 TIMEDIFF 获取带符号的时间间隔字符串(仅限同日或短跨度)
TIMEDIFF 返回的是 TIME 类型字符串,形如 '48:15:22',适合展示“耗时 XX 小时 XX 分”,但只适用于两个时间在同一天内,或差值不超过约 838 小时(MySQL TIME 类型上限)。
SELECT TIMEDIFF('2023-05-01 14:20:00', '2023-05-01 09:05:30'); -- 返回 '05:14:30'
- 不能用于跨多天计算,比如
TIMEDIFF('2023-05-02 01:00:00', '2023-05-01 23:00:00')会返回'02:00:00'(错误地忽略了一整天) - 结果是字符串,无法直接参与数值运算;如需进一步计算,得先转成秒:
TIME_TO_SEC(TIMEDIFF(...)) - 若输入含日期部分,
TIMEDIFF仅比较时间部分,日期被静默丢弃
避免用 UNIX_TIMESTAMP 相减的隐性陷阱
有人习惯把 DATETIME 转成 Unix 时间戳再相减:UNIX_TIMESTAMP(end) - UNIX_TIMESTAMP(start)。这看似合理,但有三个实际风险:
- MySQL 的
UNIX_TIMESTAMP()在遇到NULL时返回NULL,整个表达式就失效,而TIMESTAMPDIFF同样返回NULL,但语义更清晰 - 如果列定义为
DATETIME但存了无效值(如'0000-00-00 00:00:00'),UNIX_TIMESTAMP返回0,导致差值严重失真 - 在使用
TZ_OFFSET或连接时区不一致的客户端时,UNIX_TIMESTAMP会按服务器时区解释输入,容易出错;TIMESTAMPDIFF则严格按字面值计算,不涉及时区转换
需要毫秒级精度?MySQL 5.6.4+ 支持微秒,但 TIMESTAMPDIFF 不支持微秒单位
MySQL 的 DATETIME(6) 可存微秒,但 TIMESTAMPDIFF 最小单位仍是 SECOND。若真要毫秒差,得手动提取:
SELECT TIMESTAMPDIFF(SECOND, t1, t2) * 1000 + MICROSECOND(t2) DIV 1000 - MICROSECOND(t1) DIV 1000 FROM (SELECT '2023-05-01 10:00:00.123456' t1, '2023-05-01 10:00:01.654321' t2) t;
-
MICROSECOND()返回 0–999999 的整数,除以 1000 得毫秒部分 - 注意:毫秒部分相减可能为负(如从
.002000到.001500),需结合秒级差值整体调整,上面写法仅适用于微秒部分不借位的场景 - 生产环境建议优先用秒级精度 + 应用层补毫秒,避免 SQL 层逻辑过重
真正容易被忽略的点是:TIMESTAMPDIFF 的单位参数必须大写且不可缩写,输成 hour 或 hrs 会报错;另外,它对 NULL 输入零容忍,任何一端为 NULL,结果就是 NULL,别指望它自动跳过或默认为 0。











