date_format返回null最常见原因是传入非法日期或null值;它对输入严格,遇'2023-02-30'、'abc'等无效值静默返回null,不报错,需用str_to_date或is_date验证合法性,并用ifnull/coalesce防空。

DATE_FORMAT 为什么返回 NULL?
最常见的情况是传入了非法日期或 NULL 值——DATE_FORMAT 对输入极其严格,遇到无效日期(比如 '2023-02-30'、'abc')直接返回 NULL,不会报错。检查前先用 IS DATE() 或 STR_TO_DATE() 验证原始值是否合法。
实操建议:
- 用
SELECT STR_TO_DATE('2023/13/01', '%Y/%m/%d')测试字符串能否转成有效日期;结果为NULL就说明格式或数值本身有问题 - 对可能为空的字段,加
IFNULL()或COALESCE()包裹,避免整个表达式被拖成NULL - 注意时区影响:如果字段是
DATETIME且存储的是 UTC 时间,但会话时区设为+08:00,DATE_FORMAT会按本地时区解释时间,导致日期偏移
常用格式符怎么选?
MySQL 的格式符不完全兼容 PHP 或 Python,比如没有 %f(微秒)、%z(时区缩写);且大小写敏感:%Y 是 4 位年份,%y 是 2 位;%m 是补零月份数,%c 是不补零的整数(1–12)。
高频组合示例:
- 中文标准日期:
DATE_FORMAT(NOW(), '%Y年%m月%d日 %H:%i:%s')→'2024年05月20日 14:30:45' - ISO 8601 格式(无空格,便于排序):
DATE_FORMAT(NOW(), '%Y-%m-%dT%H:%i:%s') - 只取年月:
DATE_FORMAT('2023-07-15', '%Y-%m')→'2023-07'(注意不是'%Y/%m',斜杠需加反斜杠转义或直接写) - 星期几中文名:
DATE_FORMAT('2024-01-01', '%W')→'Monday',MySQL 不支持中文 weekday 名,需用CASE WHEN映射
在 WHERE 条件里用 DATE_FORMAT 安全吗?
不安全。把列套进 DATE_FORMAT(col, ...) 会导致索引失效——MySQL 无法对函数结果使用普通 B+Tree 索引。哪怕 col 上有 INDEX(date_col),这条查询也会全表扫描:
SELECT * FROM orders WHERE DATE_FORMAT(created_at, '%Y-%m') = '2024-05';
正确做法是改用范围查询:
- 代替
DATE_FORMAT(created_at, '%Y-%m') = '2024-05',写成:created_at >= '2024-05-01' AND created_at - 如果必须按“年-月”聚合,优先在 SELECT 中用
DATE_FORMAT,WHERE 里仍走原生日期比较 - 对高频按年月查询的场景,可额外加生成列 + 索引:
ALTER TABLE orders ADD COLUMN ym CHAR(7) STORED AS (DATE_FORMAT(created_at, '%Y-%m'));CREATE INDEX idx_ym ON orders(ym);
DATE_FORMAT 和 STR_TO_DATE 是一对反向操作
DATE_FORMAT 把日期转字符串,STR_TO_DATE 把字符串转日期——它们共享同一套格式符,但方向相反。容易混淆的是:当字符串含多余字符(如 '2024-05-20 12:30:45.123'),STR_TO_DATE 默认只解析到匹配格式符的部分,后面截断;而 DATE_FORMAT 不会自动补全缺失字段(比如只给年月,%d 就是 00)。
典型误用:
-
STR_TO_DATE('2024-05', '%Y-%m')返回'2024-05-01'(默认日为 01),不是NULL -
DATE_FORMAT('2024-05', '%Y-%m-%d')返回'2024-05-00'(无效日期,但函数不报错) - 跨函数链式调用要小心:
DATE_FORMAT(STR_TO_DATE('2024/05/20', '%Y/%m/%d'), '%Y年%m月%d日')可行,但中间一步失败就全崩
真正难处理的是带非标准分隔符或模糊文本(如 “去年十月”、“下周三”),这些得靠应用层解析,MySQL 原生不支持。











