TIMESTAMPDIFF 是什么
TIMESTAMPDIFF(unit, start, end) 按指定单位算出两个时间点相差多少,由 MySQL 直接提供,返回整数、小数部分截断。PostgreSQL 没有同名函数,常规做法是先把两个时间戳相减得到 interval,再用 EXTRACT(EPOCH …) 换算成秒,最后除到目标单位。
基本信息
| MySQL 语法 | TIMESTAMPDIFF(unit, start, end),结果方向是 end 减 start |
|---|---|
| 支持单位 | SECOND、MINUTE、HOUR、DAY、WEEK、MONTH、QUARTER、YEAR |
| 返回值 | 整数,小数部分直接截断,不四舍五入 |
| 计数方式 | 按跨过的单位边界计数,不是简单按天数折算 |
| PostgreSQL | 用 EXTRACT(EPOCH FROM end - start) 换算,或直接相减得 interval |
| 参数顺序 | 写反会得到负数,报表里极易被忽略 |
MySQL 多种单位
MySQL 多种单位
SELECT TIMESTAMPDIFF(SECOND, start_at, end_at) AS secs, -- 相差秒数
TIMESTAMPDIFF(MINUTE, start_at, end_at) AS mins, -- 相差分钟
TIMESTAMPDIFF(HOUR, start_at, end_at) AS hours, -- 相差小时
TIMESTAMPDIFF(DAY, start_at, end_at) AS days -- 按日期边界计天
FROM tasks
WHERE end_at IS NOT NULL; -- 未完成任务没有终点时间,先过滤掉PostgreSQL 对照
PostgreSQL 对照
SELECT EXTRACT(EPOCH FROM (end_at - start_at))::bigint AS secs,
TRUNC(EXTRACT(EPOCH FROM (end_at - start_at)) / 60) AS mins,
(end_at::date - start_at::date) AS days
FROM tasks; -- date 相减直接得整数天数,timestamp 相减得到 interval两库对照
| 需求 | MySQL 8 | PostgreSQL |
|---|---|---|
| 相差秒 | TIMESTAMPDIFF(SECOND, a, b) | EXTRACT(EPOCH FROM b - a)::bigint |
| 相差天 | TIMESTAMPDIFF(DAY, a, b) | b::date - a::date |
| 相差月 | TIMESTAMPDIFF(MONTH, a, b) | 无内置等价,需按年月自行折算 |
| 小数秒 | 返回整数,小数被截断 | EPOCH 带小数,可按需保留 |
| 时长展示 | SEC_TO_TIME(secs) 转成时分秒 | interval 类型可直接输出 |
典型使用场景
- 统计工单处理时长、订单履约时长
- 会话超时判定:与上次活动时间相差超过 N 分钟
- 留存分析:注册到首次下单相隔多少天
- 按小时或按天分桶做 SLA 统计
- 把秒数换算成时长展示,用于监控看板
- 数据校验:出现负的时长说明时间字段写反或数据有误
- 限流与冷却判断:距离上次操作是否已经超过指定秒数
- 月度报表补齐:把秒级时长换算成小时数参与人均指标计算
TIMESTAMPDIFF 按“跨过的单位边界”计数:DAY 值等于两个日期的日期部分之差,HOUR 等于完整跨过的小时数。因此 MONTH 差值不等于天数除以 30,报表口径需要单独说明。
终点时间为 NULL 时整个表达式返回 NULL,不会报错也不会自动按当前时间计算:统计“进行中任务的已耗时”要先 COALESCE(end_at, NOW()),并说明口径。
参数顺序写反会得到负数而且不报错,聚合时正负相抵会把异常掩盖掉。写完后用一对已知时间验证符号,并在报表里对负值单独告警。