DATE_FORMAT是MySQL中用于格式化日期时间输出的函数,不修改数据本身;需注意格式符大小写敏感、NULL及非法日期处理、避免WHERE中使用导致全表扫描、与STR_TO_DATE配合实现字符串与日期互转、时区影响及lc_time_names配置。

DATE_FORMAT函数的基本用法和常见格式符
DATE_FORMAT 是 MySQL 中专门用于按指定模式格式化日期时间值的函数,它不修改数据本身,只控制查询输出的显示样式。核心是第二个参数——格式字符串,比如 %Y 表示 4 位年份,%m 是补零的月份数字(01–12),%d 是补零的日期(01–31)。注意大小写敏感:%y 是两位年份,%H 是 24 小时制小时,%h 或 %I 才是 12 小时制。
- 直接格式化当前时间:
SELECT DATE_FORMAT(NOW(), '%Y-%m-%d %H:%i:%s'); - 格式化表中字段:
SELECT DATE_FORMAT(created_at, '%b %e, %Y at %l:%i %p') FROM orders;(输出如 "Jun 5, 2024 at 3:22 PM") - 中文星期/月份需配合
SET lc_time_names = 'zh_CN';,否则%W、%M默认输出英文
处理 NULL 值和非法日期导致的空结果
如果传入 DATE_FORMAT 的第一个参数是 NULL,函数直接返回 NULL;但如果字段值是非法日期(如 '0000-00-00' 或乱序字符串),MySQL 可能静默转为空字符串或触发警告,尤其在严格 SQL 模式下会报错 Incorrect datetime value。
- 先用
IS_VALID_DATE()(MySQL 8.0.29+)或STR_TO_DATE()验证再格式化 - 稳妥做法是包裹
IFNULL()或COALESCE():例如COALESCE(DATE_FORMAT(birth_date, '%Y年%m月%d日'), '未知') - 避免对未加索引的表达式使用
DATE_FORMAT做 WHERE 条件(如WHERE DATE_FORMAT(updated_at, '%Y-%m') = '2024-06'),这会导致全表扫描
与 STR_TO_DATE 的双向配合场景
DATE_FORMAT 是“输出端”工具,而 STR_TO_DATE 是它的反向操作,常用于清洗导入的字符串日期。两者格式符基本一致,但语义相反:一个把日期转字符串,一个把字符串转日期。
- 导入 CSV 中形如
'2024/06/05 14:30'的字段:STR_TO_DATE('2024/06/05 14:30', '%Y/%m/%d %H:%i') - 导出时统一为 ISO 标准但去掉秒:
DATE_FORMAT(event_time, '%Y-%m-%dT%H:%i') - 注意:
STR_TO_DATE对格式不宽容,多一个空格或少一位数都会返回NULL;而DATE_FORMAT对合法日期输入几乎无容错需求
时区影响和隐式转换陷阱
DATE_FORMAT 本身不进行时区转换,它只是格式化传入的 datetime/timestamp 值。但如果你传的是 TIMESTAMP 类型字段,MySQL 会在读取时根据当前会话时区自动转成本地时间再格式化,这容易造成误解。
- 检查当前时区:
SELECT @@time_zone, @@session.time_zone; - 若需强制 UTC 输出:
DATE_FORMAT(CONVERT_TZ(created_at, @@session.time_zone, '+00:00'), '%Y-%m-%d %H:%i') - 别把字符串直接喂给
DATE_FORMAT,比如DATE_FORMAT('2024-06-05', '%Y年%m月')看似可行,实则依赖隐式转换,一旦字符串不符合默认格式(如带毫秒或时区偏移)就会失败
%w 和 %W 的区别,而是线上报表突然某天开始显示英文星期——大概率是某次部署重置了 lc_time_names,或者从另一台服务器导出数据时没同步时区配置。


















