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是"不带前导零"版本。很多场景下,比如生成文件名、拼接导出文件名,带不带前导零会影响排序,这个细节后面会讲。
2.2 格式串拼接的实战技巧
格式串是自由拼接的,你可以在里面放任何分隔符,MySQL 会原样输出除了 % 格式符以外的字符。什么意思呢?%Y-%m-%d 输出 2024-01-15,%Y/%m/%d 输出 2024/01/15,%Y年%m月%d日 输出 2024年01月15日,都没问题。
这个特性让格式化的适用范围一下子广了很多。比如前端图表库(ECharts、Highcharts)对时间轴的格式要求是 2024-01-15 14:05 这种到分钟级别,你就可以直接在 SQL 里拼好:
sql复制SELECT DATE_FORMAT(create_time, '%Y-%m-%d %H:%i') AS time_bucket
FROM orders
ORDER BY time_bucket;
再比如生成每天的报表文件名:
sql复制SELECT CONCAT('report_', DATE_FORMAT(NOW(), '%Y%m%d'), '.csv');
-- 输出:report_20240115.csv
这种不带分隔符的格式串在文件命名里非常实用,因为文件名里有 / 会出问题,有 : 在 Windows 下也非法。
2.3 中文场景下的日期处理
虽然 MySQL 的 %W、%M 默认输出英文,但国内大部分业务要求的日报表、月报摘要里,日期部分往往想要"星期一""一月"这种中文效果。有几个思路:
思路一,最笨也最可控——用 CASE WHEN 映射。比如:
sql复制SELECT
CASE DAYOFWEEK(NOW())
WHEN 1 THEN '星期日'
WHEN 2 THEN '星期一'
WHEN 3 THEN '星期二'
WHEN 4 THEN '星期三'
WHEN 5 THEN '星期四'
WHEN 6 THEN '星期五'
ELSE '星期六'
END AS week_cn;
思路二,直接替换英文输出。DATE_FORMAT 输出的英文星期、月份是固定的,可以直接用 REPLACE 链式替换。这个方法在 SELECT 列表里会显得比较长,但胜在灵活。
思路三,利用 MySQL 的本地化设置。如果你的连接字符集和排序规则设置得当,部分版本能输出本地化的月份名,但这个行为在不同版本之间差异较大,不建议生产环境依赖它。
我自己实际项目中用得最多的是思路二的变体——在服务端代码(比如 Java 的时间格式化)里处理中文部分,SQL 只负责把日期取出来。不过如果是纯 SQL 统计报表,思路一最稳妥,毕竟 CASE WHEN 是标准 SQL,谁来了都挑不出毛病。
3. 开发中最离不开的几个日期处理场景
3.1 日期计算:DATE_ADD 与 DATEDIFF 的配合
聊完格式化,得说说日期的"动态"操作。业务需求里常遇到"查询最近 7 天""统计上个月""截止到三天前"这类的条件,核心就是 DATE_ADD 和 DATEDIFF。
DATE_ADD(date, INTERVAL expr unit) 的语法很直白,INTERVAL 后面跟数字和单位。支持的单位相当多:DAY、WEEK、MONTH、QUARTER、YEAR,甚至可以精确到 MINUTE、SECOND。数字用负数就代表往前推。
先看几个真实场景:
场景一:查询最近 7 天(含今天)的订单量。
sql复制SELECT DATE_FORMAT(create_time, '%Y-%m-%d') AS day, COUNT(*) AS cnt
FROM orders
WHERE create_time >= DATE_SUB(CURDATE(), INTERVAL 6 DAY)
GROUP BY DATE_FORMAT(create_time, '%Y-%m-%d')
ORDER BY day;
这里用到了 DATE_SUB,它和 DATE_ADD 的区别只是方向的默认值,其实等价于 DATE_ADD(date, INTERVAL -6 DAY)。用哪个看你的代码习惯,效果一样。
场景二:算两个日期之间相差几天。
sql复制SELECT DATEDIFF('2024-01-20', '2024-01-15');
-- 输出 5
-- 注意:第一个参数减去第二个参数
DATEDIFF 只关心日期部分,不关心时间部分。如果两个值是 datetime 类型,时间差异会直接忽略。比如 DATEDIFF('2024-01-15 23:59:59', '2024-01-15 00:00:00') 结果是 0,因为日期部分都是 1 月 15 日。
如果你需要精确到小时甚至分钟的差值,要用 TIMESTAMPDIFF:
sql复制SELECT TIMESTAMPDIFF(HOUR, '2024-01-15 10:00:00', '2024-01-15 14:30:00');
-- 输出 4
这个函数很好用,支持的单位包括 SECOND、MINUTE、HOUR、DAY、MONTH、YEAR,而且不会四舍五入,是直接截断。我在做订单超时未支付判断时,就经常配合 TIMESTAMPDIFF 使用。
3.2 反向解析:STR_TO_DATE 从文本到日期
STR_TO_DATE(str, format) 是 DATE_FORMAT 的反向操作,把符合特定格式的字符串变成日期类型。它在数据清洗、迁移、导入过程中的价值怎么强调都不过分。
典型的应用场景:外部系统导出的 CSV 里日期格式是 2024/01/15,MySQL 并不认这个字符串为日期。如果你直接拿它和 datetime 字段比较,结果大概率不对。这时候得先转成标准格式:
sql复制SELECT STR_TO_DATE('2024/01/15 14:05', '%Y/%m/%d %H:%i');
-- 输出:2024-01-15 14:05:00
格式串必须和输入字符串严格匹配。万一你的日期字符串里有中文,比如 2024年1月15日,格式串这么写:
sql复制SELECT STR_TO_DATE('2024年1月15日', '%Y年%c月%e日');
-- 输出:2024-01-15
这里有个关键点:%c 和 %e 能自动匹配一位数或两位数的月份/日期,所以带不带前导零都能解析。你不需要关心 1 还是 01,MySQL 都能处理。
STR_TO_DATE 结合 CASE WHEN 还能在导入时做数据质量检查。比如你判断一个字段能否解析为日期,解析失败会返回 NULL,你可以利用这个特性筛出脏数据:
sql复制SELECT
raw_date,
STR_TO_DATE(raw_date, '%Y-%m-%d') AS parsed_date
FROM import_temp
HAVING parsed_date IS NULL;
这个写法在 ETL 里是常规操作,能帮你快速定位到底哪些行的日期格式有问题,而不至于导入到一半才发现错误。
3.3 时间戳与日期的互相转换
如果你用的框架或者接口返回的是"时间戳"(Unix 时间戳,单位通常为秒),比如 1705306225,那么和 MySQL 的日期字段打交道时,就需要两个函数:FROM_UNIXTIME 和 UNIX_TIMESTAMP。
从时间戳转日期:
sql复制SELECT FROM_UNIXTIME(1705306225);
-- 输出:2024-01-15 14:10:25
FROM_UNIXTIME 还支持第二个参数做格式化,是 DATE_FORMAT 的一个快捷方式:
sql复制SELECT FROM_UNIXTIME(1705306225, '%Y-%m-%d');
-- 输出:2024-01-15
从日期转时间戳:
sql复制SELECT UNIX_TIMESTAMP('2024-01-15 14:10:25');
-- 输出:1705306225
这里有几个在实际开发中容易踩的坑,先提前说:
- 单位问题:Java 里
System.currentTimeMillis()返回的毫秒时间戳是 13 位,而 MySQL 的UNIX_TIMESTAMP默认按秒算。你如果把 13 位的毫秒值直接传给FROM_UNIXTIME,得到的时间会非常离谱,正确做法是先除以 1000。 - 时区问题:
FROM_UNIXTIME和UNIX_TIMESTAMP都受会话时区影响。后面第 4 章会有专门讨论。
3.4 按天/按周/按月分组统计的完整套路
这是报表开发里最经典的场景。我直接给出一套可复用的模板。
先按天统计:
sql复制SELECT
DATE_FORMAT(create_time, '%Y-%m-%d') AS day,
COUNT(*) AS order_cnt,
SUM(amount) AS total_amount
FROM orders
WHERE create_time >= '2024-01-01 00:00:00'
AND create_time < '2024-02-01 00:00:00'
GROUP BY DATE_FORMAT(create_time, '%Y-%m-%d')
ORDER BY day;
这段 SQL 的关键点是 WHERE 里用了范围比较而不是 DATE_FORMAT(create_time, '%Y-%m-%d') = '2024-01-01',原因是后者会导致 create_time 上的索引失效。这是 MySQL 优化器的行为——你一旦对索引列套函数,它就判断无法使用索引了。按天统计通常数据量大、时间范围大,索引失效会让整条 SQL 变成全表扫描。
按周统计。MySQL 里 YEARWEEK() 和 WEEK() 都能拿到周数,但要注意一周从周一开始还是从周日开始,国内业务一般用周一开始:
sql复制SELECT
YEARWEEK(create_time, 1) AS year_week,
MIN(DATE(create_time)) AS week_start,
COUNT(*) AS order_cnt
FROM orders
GROUP BY YEARWEEK(create_time, 1)
ORDER BY year_week;
第二个参数 1 代表"周一到周日"算一周,0 则是默认的周日到周六。这个参数如果不注意,统计出来的每周数据会和你脑子的"周"对不上——我见过有人因为没用 1,导致周一的数据被算到上一周,折腾了好几天。
按月统计:
sql复制SELECT
DATE_FORMAT(create_time, '%Y-%m') AS month,
COUNT(*) AS order_cnt,
SUM(amount) AS total_amount
FROM orders
GROUP BY DATE_FORMAT(create_time, '%Y-%m')
ORDER BY month;
这里有个非常隐蔽的需求点:按月的报表往往需要把"没有订单的月份"也补出来,但 GROUP BY 天然只返回有数据的行。如果业务要求每个月一行,哪怕当月为 0,就要在应用层补零,或者用一段递归/笛卡尔积的方式生成一个月份序列再左连接。这个逻辑如果写在 SQL 里会绕不少,我通常建议在 Java 的报表服务里做月份补全,SQL 只负责聚合,职责分离,代码也好维护。
4. 日期格式化实战踩坑记录
4.1 索引失效:在日期列上套函数的代价
这是我在项目里遇到最多、影响也最大的一个问题。直接看一个例子。
有个订单表 orders,数据量在千万级,create_time 上有索引。业务方有个筛选条件"查询某一天的所有订单",最容易写出来的 SQL 是这样的:
sql复制SELECT *
FROM orders
WHERE DATE_FORMAT(create_time, '%Y-%m-%d') = '2024-01-15';
这条 SQL 从写法上看没毛病,甚至觉得很直观:先把时间格式化到天,再拿去做等值比较。但问题在于,MySQL 对 create_time 列上的所有行都要先执行一次 DATE_FORMAT,才能和字符串 '2024-01-15' 比较。这意味着索引列上套了函数,索引直接失效,优化器只能全表扫描。
我接手过一个线上慢查询,就是这条 SQL,执行耗时从几十毫秒直接飙到几十秒,高峰期差点把数据库连接打满。排查过程不复杂:EXPLAIN 一看,type 是 ALL,key 是 NULL,妥妥的全表扫描。
修复方案有两种:
方案一,把等值比较改成范围查询:
sql复制SELECT *
FROM orders
WHERE create_time >= '2024-01-15 00:00:00'
AND create_time < '2024-01-16 00:00:00';
这样 create_time 没有套函数,索引就能正常走,查询计划里 type 会变成 range。效果立竿见影。
方案二,如果业务上确实需要"格式化到天"这种写法,可以考虑给 create_time 加一个生成列(MySQL 5.7+ 支持),专门存日期部分然后建索引:
sql复制ALTER TABLE orders
ADD COLUMN create_day DATE GENERATED ALWAYS AS (DATE(create_time)) STORED,
ADD INDEX idx_create_day (create_day);
这样在 WHERE 里直接 create_day = '2024-01-15',SQL 更好读,索引也能用。不过这个方案会增加存储成本,适合查询极其频繁、对性能要求又很高的场景,不是每张表都值得这么干。
我的建议是:90% 的场景用范围查询就够了,别为了 SQL 好看牺牲性能。这种优化技巧属于典型"小改动,大收益",排查一次,记住了,后面写 SQL 都会注意。
4.2 隐式类型转换:字符串和日期的混用
MySQL 里日期字段和字符串比较时,会发生隐式类型转换。听着像是数据库自动帮你处理了麻烦,实际上它经常是好心办坏事。
看个例子:
sql复制SELECT *
FROM orders
WHERE create_time = '2024-01-15';
你以为 MySQL 会把 '2024-01-15' 转成 2024-01-15 00:00:00 再比较。确实,如果 create_time 是 date 类型,这个结论成立。但很多表里 create_time 是 datetime 类型,存储的是 2024-01-15 14:30:25。你拿 '2024-01-15' 和 create_time 做等值比较,结果就是查不到任何数据——因为 '2024-01-15' 被转成 2024-01-15 00:00:00,而表里没有一条记录的时间精确等于这个值。
更麻烦的是反过来:如果 create_time 是 varchar 类型,却存着日期字符串(数据不规范的历史遗留),你拿日期函数去处理它,又会出各种诡异问题。比如 DATE_FORMAT(create_time, '%Y-%m-%d') 对 varchar 虽然能隐式转成日期,但如果里面有一条 '2024/01/15' 或者 '20240115',格式化出来的结果就不对,而且不给你任何报错。
我的经验是:能选对数据类型就别省那点事。建表时日期就用 date/datetime/timestamp,不要图省事存字符串。查询时养成 EXPLAIN 的习惯,看到 type 异常或者 Extra 里有 Using where 一查到底,很多隐性坑会提前浮出来。
4.3 时区配置不当导致的"阴间时间"
时区问题是最容易埋雷的,尤其在多语言、多机房部署的环境下。MySQL 的时区由 time_zone 系统变量控制,分两种:全局时区和会话时区。
看个典型场景。你在上海(东八区)的服务器上跑业务,MySQL 连接串里配置了 serverTimezone=Asia/Shanghai,看起来一切正常。但是,如果某个连接没有指定会话时区,MySQL 会使用全局配置,而全局配置可能是 SYSTEM——它读取的是操作系统时区。只要你那台机器时区设置不对,所有时间戳转换就全变了。
表现是什么?应用插入一条记录,create_time 用的是 NOW(),日志里显示插入时间是下午 3 点,查数据库却发现是晚上 7 点。或者反过来,FROM_UNIXTIME 转换出来的时间比实际少了 8 小时。
排查链路:
- 先看当前会话时区:
SELECT @@time_zone, @@global.time_zone, @@system_time_zone; - 如果
@@time_zone不是+08:00或者Asia/Shanghai,问题大概率在这。 - 查看连接串的
serverTimezone配置,确认 JDBC 驱动的行为。
修复方式,我建议直接在 MySQL 配置文件的 [mysqld] 段加:
ini复制default-time-zone = '+08:00'
或者启动参数里加 --default-time-zone='+08:00'。注意:'+08:00' 这种写法不依赖操作系统时区数据,最稳。如果你想用 Asia/Shanghai 这种命名时区,MySQL 需要加载时区表(mysql_tzinfo_to_sql),否则会报 Unknown or incorrect time zone 错误,很多新手在这里卡住过。
另外提醒一句:timestamp 类型在存储时会按会话时区转成 UTC,读取时再转回当前时区;而 datetime 类型不做这种转换,存什么就是什么。这个差异决定了你选哪种字段类型。如果你是跨时区业务,timestamp 更省心;如果只是国内单一业务区,datetime 也完全够用,反而少了时区转换的开销。
4.4 %i 与 %m、%H 与 %h:格式符混淆的经典案例
最后聊一个最不起眼但人人都可能犯的错误:格式符搞混。
我自己就经历过一次特别尴尬的事。当时写一个按小时统计的报表,SQL 是这么写的:
sql复制SELECT DATE_FORMAT(create_time, '%Y-%m-%d %M') AS hour_bucket, COUNT(*)
FROM orders
GROUP BY DATE_FORMAT(create_time, '%Y-%m-%d %M')
ORDER BY hour_bucket;
本意是输出 2024-01-15 14 这种格式,结果一跑,输出的是 2024-01-15 January,整张报表全乱了。原因就是我用了 %M——它是月份的英文全称,不是分钟。
正确的格式串应该是:
sql复制DATE_FORMAT(create_time, '%Y-%m-%d %H')
这类错误通常不会报错,所以特别隐蔽。关键是要记住格式符的分类:
- 时间相关:
%H(24小时)、%h(12小时)、%i(分钟)、%s(秒)、%p(AM/PM) - 日期相关:
%Y/%y(年份)、%m/%c(月份)、%d/%e(日期)、%W/%a(星期)、%M/%b(月份名)
我的记忆技巧是:%i 这个字母长得像分钟的最小单位,%m 是 month 的首字母,%M 是 Month 的大写首字母,所以它表示的是英文全称。这样区分 %m 和 %M、%i 和 %M 就不会错了。
4.5 格式化结果参与排序的小陷阱
还有一个排序上的坑,我觉得值得单独拉出来说。当你用 DATE_FORMAT 得到的是一个字符串,如果你格式串里用了 %Y-%m-%d 这种带前导零的格式,字符串排序和日期排序是一致的,没什么问题。但如果你用了"不带前导零"的格式,比如 %Y-%c-%e 输出 2024-1-15,那排序就完全不是你以为的时间顺序了。
举个真实例子。某次做导出文件,文件名里的日期是 2024-1-15 这种格式,结果文件按文件名排序后,2024-10-15 排在了 2024-2-15 前面,因为字符串比较时 '10' < '2'。
解决思路有两个层面:
- 如果你只需要排序,建议把格式化和排序拆开:
ORDER BY create_time,让 MySQL 按日期类型排序,SELECT里再输出格式化结果。SQL 里允许ORDER BY引用不在SELECT列表中的列。 - 如果因为历史原因,字段已经是字符串,那要确保格式串是
%Y-%m-%d这种固定宽度格式,或者干脆ORDER BY CAST(str_date AS DATE)。
这个坑在生成跨月、跨年报表时尤其容易踩。每次做新的报表需求,我都会在写出 SQL 后先看一眼 ORDER BY 用的字段到底是日期类型还是字符串,别等到前端图表排序乱套了再回来查。
5. 我在真实项目中沉淀的两条经验
前面把函数、场景、坑都过了一遍,最后说两个我在真实项目里沉淀出来的经验,属于那种手册里不会写、但实战中很有用的东西。
第一,给团队定一条规则:所有统计类 SQL 禁止用 DATE_FORMAT 直接套在索引列上做条件。不要指望每个人都能记住索引失效的原理,规则定死了,Code Review 的时候一搜一个准,比事后排查效率高得多。我在团队内部推行这条规则后,因为日期过滤导致的慢查询明显少了。很多人写 DATE_FORMAT(create_time, '%Y-%m-%d') = 'xxx' 只是为了图快,给他们一个替代写法模板,他们自然愿意改。
第二,日期处理尽量收口到少数几个函数和统一格式。一个项目里,如果每个人都有自己的日期格式偏好,今天 2024-01-15,明天 2024/1/15,后天 20240115,数据对接的时候全是坑。我会在项目的编码规范里固定一套约定:接口出参一律 yyyy-MM-dd HH:mm:ss,SQL 内部统一用 %Y-%m-%d %H:%i:%s,只有展示层才允许做额外的格式化。这样做的好处是,后续做数据迁移、报表聚合、跨部门联调时,省掉了很多不该有的沟通成本。
这两条经验看着简单,但实际操作中带来的收益非常直接——少加班,少背锅。MySQL 的日期格式化是个基础得不能再基础的知识点,但把基础打牢了,往上盖楼才不会歪。这篇的内容覆盖了我日常开发中用到的绝大部分场景,你如果工作中还有更刁钻的日期处理需求,欢迎在评论区一起讨论。
