EXTRACT(HOUR FROM timestamp)在PostgreSQL和标准SQL中用于提取小时整数,时区敏感且NULL安全;MySQL用HOUR(),SQLite用strftime('%H')并需转整型。

EXTRACT(HOUR FROM timestamp) 在 PostgreSQL 和标准 SQL 中怎么用
PostgreSQL、MySQL 8.0+(部分模式)、SQL Server(需兼容窗口)和大多数支持标准 SQL 的引擎都认 EXTRACT。它直接从时间戳中拆出指定字段,小时就是 HOUR。
注意:EXTRACT 返回的是整数(INTEGER),不是字符串,也不补零。比如 '2024-03-15 05:07:22' 提取出来是 5,不是 '05'。
- 写法统一:
SELECT EXTRACT(HOUR FROM created_at) AS hour_of_day FROM orders; - 时区敏感:如果
created_at是TIMESTAMP WITH TIME ZONE,EXTRACT按当前会话时区计算——不是原始存储时区,也不是 UTC,除非你显式AT TIME ZONE 'UTC' - NULL 安全:输入为
NULL时结果也是NULL,不用额外判断
DATE_PART('hour', timestamp) 是 PostgreSQL 专属写法
DATE_PART 是 PostgreSQL 特有的函数,功能和 EXTRACT 几乎一样,但语法更灵活些(支持字符串参数名),且在旧版本 PostgreSQL(如 9.6)里比 EXTRACT 更常用。
它和 EXTRACT 的行为差异极小,主要区别在细节:
- 参数名必须加单引号:
DATE_PART('hour', created_at),不能写hour不带引号 - 同样返回整数,不补零;同样受会话时区影响
- 支持更多非标准单位,比如
'epoch'、'microseconds',但提取小时没必要用这些 - 性能上和
EXTRACT无实质差别,选哪个纯看团队习惯或迁移需求
MySQL 和 SQLite 怎么办:别硬套 EXTRACT
MySQL 5.7 及更早版本根本不支持 EXTRACT 或 DATE_PART;MySQL 8.0+ 虽支持 EXTRACT,但默认行为可能和 PostgreSQL 不一致(比如对 TIMESTAMP 列不自动转时区)。SQLite 则完全没这两个函数。
实操建议:
- MySQL:用
HOUR(created_at)—— 这是 MySQL 原生函数,简单可靠,返回 0–23 整数 - SQLite:用
strftime('%H', created_at)—— 注意返回的是字符串'05',需要CAST(... AS INTEGER)才能当数字参与计算 - 跨数据库项目?别封装成统一函数,优先在应用层解析时间戳,或者用 ORM 的时间字段抽象(如 SQLAlchemy 的
extract方法会自动适配方言)
容易被忽略的时区陷阱和类型隐式转换
最常踩的坑不是函数写错,而是时间戳字段类型和时区理解偏差。
-
TIMESTAMP WITHOUT TIME ZONE字段:无论你用EXTRACT还是DATE_PART,都按“字面值”解析——'2024-01-01 14:00:00'就是 14 点,不考虑时区偏移 -
TIMESTAMP WITH TIME ZONE字段:存储时已转为 UTC,但EXTRACT默认按current_setting('timezone')显示,可能和业务预期不符。查前先确认:SHOW timezone; - 字符串直接传入:比如
EXTRACT(HOUR FROM '2024-01-01 10:30'),某些数据库会隐式转成本地时区时间戳,有些则报错或按 UTC 解析——务必显式 cast:EXTRACT(HOUR FROM '2024-01-01 10:30'::TIMESTAMP)
时区不是可选项,是前提条件。没确认字段类型和会话时区就写 EXTRACT,结果对了也可能是巧合。

















