使用WHERE查询日期需注意字段类型、时区和边界值:DATE类型可用BETWEEN,但DATETIME/TIMESTAMP需用created_at >= '2024-01-01' AND created_at < '2024-02-01'避免漏数据。

直接用 WHERE 配合日期比较操作符就能查,但时间字段类型、时区、边界值处理稍不注意就会漏数据或报错。
确认时间字段的数据类型和存储格式
MySQL 的 DATETIME、TIMESTAMP,PostgreSQL 的 TIMESTAMP WITH TIME ZONE,SQLite 的 TEXT(ISO8601 格式)——不同数据库对时间的解析逻辑差异很大。
- 如果字段是
DATE类型(只存年月日),用WHERE created_date BETWEEN '2024-01-01' AND '2024-01-31'没问题; - 如果是
DATETIME或带毫秒的TIMESTAMP,BETWEEN '2024-01-01' AND '2024-01-31'实际等价于BETWEEN '2024-01-01 00:00:00' AND '2024-01-31 00:00:00',会丢掉 31 号全天的数据; - 更安全的写法是:
created_at >= '2024-01-01' AND created_at (左闭右开,明确覆盖整月)。
处理时区导致的时间错位
服务器时区、数据库时区、应用层时区不一致时,'2024-01-01' 这个字符串可能被解释成 UTC、本地时间或会话时区时间,结果完全不对。
- PostgreSQL 中用
created_at AT TIME ZONE 'Asia/Shanghai'显式转换后再比较; - MySQL 8.0+ 可用
CONVERT_TZ(created_at, '+00:00', '+08:00'); - 更稳妥的做法是统一在应用层把查询时间转成数据库所在时区的
UTC时间再传入,避免依赖数据库配置。
索引是否生效?别让 DATE() 或 CAST() 搞崩性能
常见错误写法:WHERE DATE(created_at) = '2024-01-01' 或 WHERE YEAR(created_at) = 2024 —— 这会让数据库无法使用 created_at 字段上的索引,全表扫描。
- 正确方式始终让时间字段“裸露”在比较左侧:
created_at >= '2024-01-01' AND created_at ; - 如果必须按日期分组,先过滤再
GROUP BY DATE(created_at),而不是用函数包裹条件字段; - 检查执行计划:MySQL 用
EXPLAIN,PostgreSQL 用EXPLAIN ANALYZE,确认key或Index Scan是否命中索引。
最常被忽略的是隐式类型转换——比如把字符串 '2024-01-01' 和一个 INT 类型的时间戳字段比较,数据库可能默默转成 0 或报错。查之前先 DESCRIBE table_name 或 \d table_name 看清字段真实类型。

















