1. 为什么日期格式化值得单独写一整篇
1.1 表面是格式化,实际是项目里的高频痛点
MySQL 的日期格式化,乍一听像个小学知识点:DATE_FORMAT(NOW(), '%Y-%m-%d') 一行代码的事。但你真去翻真实项目,会发现日期处理是最容易出幺蛾子的地方之一——时间不对、格式不对、索引失效、隐式转换、时区错乱,随便一个都能让你加班到深夜。
我自己带过不少项目,也帮别人排查过不少问题。这么说吧,凡是报表、订单、日志、统计相关的功能,八成以上的 SQL 问题都出在日期处理上。而且这些问题有个共性:不是语法不会,是细节没吃透。很多人写 WHERE create_time = '2024-01-15' 查不出数据,第一反应是骂 MySQL,其实是你没搞明白日期比较的真正机制。
这篇文章就是想把 MySQL 日期格式化这条线彻底捋一遍。从最基础的 DATE_FORMAT 格式符拆解,到日常开发里真正高频的场景——日期计算、反向解析、时间戳转换、按天分组统计,再到让我印象深刻的踩坑案例和排查思路,尽量做到一条龙讲透。适合谁看?刚接触 MySQL 的新手可以拿来当系统性的入门资料,写过几年 SQL 的老手也可以直接跳到第 4 章看踩坑部分,说不定能帮你省下半天查问题的时间。
1.2 一个反直觉的事实:格式化不只是"好看"
很多人觉得日期格式化就是为了让输出好看一点,比如把 2024-01-15 14:30:25 变成 2024/01/15。这确实是它的用途之一,但远不是全部。
在真实开发中,日期格式化更多时候是为了对齐数据粒度。比如你要统计每天的新增用户数,create_time 字段是精确到秒的 datetime,你直接 GROUP BY create_time 会发现每天被拆成了无数行。这时候必须靠格式化把粒度归一到"天"这个级别,才能聚合出有意义的结果。同样,分钟级别的趋势图要 GROUP BY DATE_FORMAT(create_time, '%Y-%m-%d %H:%i'),季度报表要用 %Y-%m 配合季度逻辑,这都是格式化在承担数据规整的职责。
再比如 STR_TO_DATE 这个反向函数,它是把字符串解析成日期,在数据迁移、ETL、导入导出场景里几乎天天用。很多从 Excel 或者别的库导入的数据,日期字段是五花八门的文本格式,不解析就没法参与日期运算。
理解了这一层,你就明白为什么 MySQL 要提供这么多日期函数和格式符了——格式化不是最后的展示层,它是数据处理链条上的关键一环。
1.3 这篇文章的写法约定
为了不绕弯子,先把本篇涉及的环境和约定说清楚:
- MySQL 版本:示例基于 5.7 和 8.0,这两个版本的日期函数行为基本一致,8.0 新增的窗口函数和 CTE 在本篇也会少量涉及。
- 涉及的核心函数:
NOW()、CURDATE()、DATE_FORMAT()、STR_TO_DATE()、DATE_ADD()、DATEDIFF()、UNIX_TIMESTAMP()、FROM_UNIXTIME()。 - 所有示例均可在 MySQL 命令行或 Navicat 中直接执行,不需要建表,方便你边看边试。
下面进入正题。先讲最核心的 DATE_FORMAT,把格式符彻底吃透,后面所有场景都建立在这个基础上。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. DATE_FORMAT:格式化主力军的完整拆解
2.1 基本语法和格式符速查表
DATE_FORMAT(date, format) 接受两个参数:第一个是日期/时间类型的值,可以是 datetime 字段、NOW() 的返回值,也可以是 '2024-01-15' 这种合法的日期字符串;第二个是格式串,由 % 开头的小写字母组成。
语法本身没什么门槛,真正的知识密度在格式符。我整理了一份在工作中真正用得上的速查表,建议直接截图保存:
| 格式符 | 含义 | 输出示例(以 2024-01-15 14:05:09 为例) |
|---|---|---|
%Y |
四位年份 | 2024 |
%y |
两位年份 | 24 |
%m |
两位月份(01-12) | 01 |
%c |
月份(1-12,不带前导零) | 1 |
%d |
两位日期(01-31) | 15 |
%e |
日期(1-31,不带前导零) | 15 |
%H |
24小时制(00-23) | 14 |
%h |
12小时制(01-12) | 02 |
%i |
分钟(00-59) | 05 |
%s |
秒(00-59) | 09 |
%p |
AM/PM | PM |
%W |
星期名全称(Sunday-Saturday) | Monday |
%a |
星期名缩写(Sun-Sat) | Mon |
%M |
月份名全称(January-December) | January |
%b |
月份名缩写(Jan-Dec) | Jan |
%j |
一年中的第几天(001-366) | 015 |
%w |
一周中的第几天(0=Sunday,6=Saturday) | 1 |
%T |
等于 %H:%i:%s |
14:05:09 |
几个容易混淆的点先强调一下:
%i是分钟,%m是月份,%s是秒。很多人把分钟写成%M,结果输出了一长串月份名,还以为是 MySQL 出 bug 了。实际上%M是月份的英文全称。%H和%h的区别是 24 小时制和 12 小时制。14点用%H输出14,用%h输出02,后面最好带上%p才能区分上午下午。%c和%e
