HOUR()函数从时间值中提取0–23的小时数,支持DATETIME、TIMESTAMP、TIME类型,DATE或NULL输入返回NULL;PostgreSQL需用EXTRACT(HOUR FROM ...)替代;WHERE中对字段用HOUR()会导致索引失效。

MySQL 中 HOUR() 函数怎么用?
HOUR() 是 MySQL 里直接从时间值中提取小时(0–23)的内置函数,它不关心日期部分,只看时间戳或时间类型的时分秒。传入 DATETIME、TIMESTAMP 或 TIME 都能工作,但要注意:如果字段是 DATE 类型(比如 '2024-05-20'),HOUR() 会返回 NULL,因为没时间信息。
常见误用是拿它处理字符串,比如 HOUR('14:30:00')——这其实能运行,但依赖隐式转换;更稳妥的做法是先用 STR_TO_DATE() 显式转成时间类型再取小时:
HOUR(STR_TO_DATE('14:30:00', '%H:%i:%s')) -- 返回 14- 输入为
NULL时,结果一定是NULL,别指望它兜底 - 对
'2024-05-20 00:05:10'返回0,不是24;午夜就是 0 点 - 不支持时区自动偏移,
NOW()和UTC_TIMESTAMP()的小时可能差好几小时,得自己判断上下文
PostgreSQL 没有 HOUR(),该用什么替代?
PostgreSQL 不提供 HOUR() 函数,得靠 EXTRACT()。语法是 EXTRACT(HOUR FROM xxx),参数必须是 TIME、TIMESTAMP 或 TIMESTAMPTZ 类型。
容易踩的坑是字段类型不匹配。比如你查的是 created_at::DATE,再套 EXTRACT(HOUR FROM created_at::DATE) 会报错:ERROR: cannot extract hour from a date。必须保留时间部分:
EXTRACT(HOUR FROM created_at::TIMESTAMP) -- 正确
-
EXTRACT(HOUR FROM '2024-05-20 15:22:03'::TIMESTAMP)→15 - 对带时区的时间(
TIMESTAMPTZ),EXTRACT返回的是当前会话时区下的小时,不是 UTC 小时 - 如果要固定按 UTC 提取,先转时区:
EXTRACT(HOUR FROM created_at AT TIME ZONE 'UTC')
WHERE 条件里用 HOUR() 会导致索引失效吗?
会。只要在过滤条件里对时间字段做函数运算,比如 WHERE HOUR(created_at) = 14,MySQL 通常无法使用 created_at 上的 B-tree 索引,只能全表扫描。
真正高效的做法是把函数移到右边,让左边保持字段原样:
WHERE created_at >= '2024-05-20 14:00:00' AND created_at < '2024-05-20 15:00:00'
- 如果业务确实需要查“每天 14 点的数据”,建议建生成列 + 索引(MySQL 5.7+):
ALTER TABLE logs ADD COLUMN hour_of_day TINYINT AS (HOUR(created_at)) STORED;CREATE INDEX idx_hour ON logs(hour_of_day); - PostgreSQL 可以用函数索引:
CREATE INDEX idx_hour ON logs (EXTRACT(HOUR FROM created_at)); - 注意:函数索引对查询写法敏感,PostgreSQL 必须严格写成
EXTRACT(HOUR FROM created_at) = 14才能命中
跨数据库兼容写法难不难?
难。SQL 标准没规定 HOUR(),各数据库实现差异明显:MySQL 有 HOUR(),PostgreSQL 用 EXTRACT(),SQL Server 用 DATEPART(HOUR, ...),SQLite 用 strftime('%H', ...)。想写一次跑多库,基本得靠应用层适配或 ORM 抽象。
如果非要在纯 SQL 层妥协,可以考虑用字符串截取这种“笨办法”(仅限 ISO 格式时间):
SUBSTR(created_at, 12, 2) -- 假设 created_at 是 '2024-05-20 14:30:00' 这种格式
- 这招在 MySQL/PostgreSQL/SQLite 都能跑,但极度脆弱:字段格式一变就错,且返回的是字符串,不是数字
- 遇到
'2024-05-20T14:30:00Z'或毫秒级时间就完全失效 - 真正稳定的跨库方案,还是得接受不同方言,或者统一在应用代码里解析时间
函数本身很简单,但实际用起来,类型、索引、时区、兼容性这些点,比想象中更容易漏掉一个就出问题。

















