TIMESTAMPDIFF(SECOND, start_time, end_time)是MySQL中计算秒数差的正确方法,返回整数结果,参数顺序为单位、起点、终点,start_time > end_time时结果为负。

MySQL 中用 TIMESTAMPDIFF 计算秒数差
MySQL 不支持直接用减法算两个 DATETIME 字段的秒数差(会得到奇怪的整数),必须用 TIMESTAMPDIFF。它能明确指定单位,避免隐式转换出错。
常见错误是写成 end_time - start_time 或误用 TIMEDIFF(后者返回的是时间间隔字符串,不是秒数)。
-
TIMESTAMPDIFF(SECOND, start_time, end_time)才是正确写法,注意参数顺序:单位、起点、终点 - 如果
start_time > end_time,结果为负数,需根据业务决定是否用ABS() - 字段类型必须是
DATETIME、TIMESTAMP或带日期的字符串,纯TIME类型可能截断日期部分导致偏差
PostgreSQL 里用减法配合 EXTRACT
PostgreSQL 允许直接对两个 TIMESTAMP 做减法,得到 INTERVAL,再用 EXTRACT(EPOCH FROM ...) 提取总秒数(含小数)。
别用 EXTRACT(SECOND FROM ...)——它只取区间里的“秒”部分(0–59),不是总秒数。
- 正确写法:
EXTRACT(EPOCH FROM (end_time - start_time)) - 结果是
DOUBLE PRECISION,若只要整数秒,套一层FLOOR()或ROUND() - 注意时区:两个字段最好同为
TIMESTAMP WITHOUT TIME ZONE,或都带时区且已对齐,否则差值可能受时区转换干扰
SQL Server 的 DATEDIFF 要小心精度陷阱
DATEDIFF(SECOND, start_time, end_time) 看似简单,但它只计算“边界秒数”,不考虑毫秒——比如 '2024-01-01 12:00:00.999' 到 '2024-01-01 12:00:01.000' 会返回 1,但 '2024-01-01 12:00:00.001' 到 '2024-01-01 12:00:00.999' 也返回 0。
- 如需包含毫秒的精确秒数,先转成毫秒差再除以 1000:
DATEDIFF(MILLISECOND, start_time, end_time) / 1000.0 -
DATEDIFF的第三个参数是“结束”,第二个是“开始”,顺序不能反,否则符号相反 - 如果字段是
DATETIME2,推荐用毫秒差方式,避免DATETIME类型固有的 3.33ms 舍入误差
跨数据库可移植的思路:转 Unix 时间戳
如果查询要兼容多种数据库,最稳的方式是把两个时间都转成 Unix 时间戳(秒数),再相减。各库都有对应函数,但名字和参数不同。
关键点不是“有没有函数”,而是“是否处理了时区”。比如 MySQL 的 UNIX_TIMESTAMP() 默认按会话时区转,而 PostgreSQL 的 EXTRACT(EPOCH FROM ...) 按 UTC 处理 TIMESTAMP WITH TIME ZONE。
- MySQL:
UNIX_TIMESTAMP(end_time) - UNIX_TIMESTAMP(start_time)(确保两字段时区一致) - PostgreSQL:
EXTRACT(EPOCH FROM end_time AT TIME ZONE 'UTC') - EXTRACT(EPOCH FROM start_time AT TIME ZONE 'UTC') - SQL Server:没有原生 Unix 时间戳函数,得用
DATEDIFF(SECOND, '1970-01-01', ...),但要注意datetime类型最小值是 1753 年,不能直接算 1970 年前的时间
真正容易被忽略的不是语法,而是时间字段是否带时区、数据库默认时区设置、以及历史数据里混用的时区标注方式——这些都会让同样的 SQL 在不同环境返回不同结果。











