按小时统计应优先使用 DATE_FORMAT(如 '%Y-%m-%d %H:00:00'),它支持跨天聚合、索引优化和时区可控;FROM_UNIXTIME 仅适用于 UNIX 时间戳转 DATETIME 后再格式化,需显式指定时区;HOUR 函数仅返回 0–23 数字,易导致跨天数据混淆,必须配合严格时间范围过滤。

FROM_UNIXTIME 和 HOUR 都能用于小时统计,但适用场景和行为差异很大——直接混用容易漏数据或分组错乱。
FROM_UNIXTIME 适合时间戳字段转为可读格式再截取小时
FROM_UNIXTIME 把整型时间戳(如 1712844000)转成 DATETIME,之后才能用 DATE_FORMAT 或嵌套函数提取结构化时间部分。
它不是“取小时”本身,而是为后续格式化铺路。
- 如果字段本身就是
DATETIME或TIMESTAMP类型,别用FROM_UNIXTIME包裹,会多一次无谓转换,还可能因时区隐式转换出错 - 真要用它,典型写法是:
DATE_FORMAT(FROM_UNIXTIME(timestamp_col), '%Y-%m-%d %H'),再GROUP BY - 注意:
FROM_UNIXTIME默认按系统时区解析,若业务跨时区,必须显式指定,例如FROM_UNIXTIME(timestamp_col, '+08:00')
HOUR 函数只返回 0–23 的数字,不能单独做分组依据
HOUR(create_time) 返回的是纯数字,比如 14,它不带日期信息。
这意味着:今天 14 点和明天 14 点会被归到同一组,跨天数据全混在一起。
- 仅适用于「只关心一天内每小时分布」的场景,且必须加严格时间范围过滤,例如:
WHERE create_time >= '2026-04-11 00:00:00' AND create_time < '2026-04-12 00:00:00' - 若漏掉
WHERE条件,统计结果完全不可信 - 它无法区分不同日期的同小时,也不支持排序对齐时间轴(比如想看 00→23 连续小时,得手动
ORDER BY HOUR(...),但缺小时不会补 0)
按小时统计真正稳妥的做法是用 DATE_FORMAT + 完整时间粒度
最常用、最不容易出错的方式是:
DATE_FORMAT(create_time, '%Y-%m-%d %H:00:00')
- 保留日期+小时精度,天然支持跨天、跨月聚合
- 输出格式统一,可直接用于展示或下游程序解析
- 支持索引(如果字段上有前缀索引或生成列索引)
- 若字段是 UNIX 时间戳,先转再格式化:
DATE_FORMAT(FROM_UNIXTIME(timestamp_col), '%Y-%m-%d %H:00:00')
示例:
SELECT DATE_FORMAT(create_time, '%Y-%m-%d %H:00:00') AS hour_slot, COUNT(*) AS cnt FROM logs WHERE create_time >= DATE_SUB(NOW(), INTERVAL 24 HOUR) GROUP BY hour_slot ORDER BY hour_slot;
关键点在于:不要为了“看起来简洁”而用 HOUR() 硬凑,也不要默认 FROM_UNIXTIME 无害——它的时区行为、NULL 处理、性能开销都得心里有数。真正要上线的统计逻辑,优先走 DATE_FORMAT 路线,清晰、可控、易维护。


















