☰
MySQL日期转换实战:STR_TO_DATE与DATE_FORMAT详解
2026/10/14 4:41:12 网站建设 项目流程

MySQL里做字符串日期格式转换,我相信后端开发的朋友都不陌生。需求无非就是这么几种:前端传过来一个"20240506"或者"2024/05/06"这种字符串,要落库到DATE或者DATETIME字段;或者反过来,查出日期字段但要按"2024年05月06日"这种格式展示;再就是日志表、导入表里那些五花八门的字符串日期要做清洗。这篇就把STR_TO_DATE、DATE_FORMAT、CAST这类函数一次说透,配合我实际踩过的坑,帮你少走弯路。不管你是刚接触SQL的新人,还是写了好几年业务的老手,只要跟MySQL日期处理打过照面,这篇都值得花几分钟看完。

我最早接触这个需求时,第一反应是拿DATE_FORMAT去硬转字符串,结果报错报得一头雾水。后来才搞明白,DATE_FORMAT是给日期类型做格式化输出的,你拿字符串往里塞,MySQL根本不知道你要干嘛。所以核心要先搞清楚一件事:字符串转日期用STR_TO_DATE,日期转字符串用DATE_FORMAT,方向反了就一定出问题。

1. 字符串日期转换的适用场景与转换失败的根因

1.1 哪些业务场景必须做格式转换

先梳理一下平时最常见的几种需求,看看格式转换到底都出现在哪里。

第一类是数据导入和清洗。比如你从Excel、CSV里导数据,Excel里显示的日期可能是"2024-5-6"这种,但到了文件里就变成了"2024/5/6"或者"05/06/2024"。这种数据倒进MySQL临时表的时候,大概率是VARCHAR类型,想跟业务表里的DATE字段做关联或者直接插入,就必须先把字符串转成真正的日期类型。

第二类是接口对接。前后端联调的时候,前端高频传参格式包括"20240506"、"2024-05-06 12:30:00"、"2024年5月6日"这些。后端拿到这种字符串,如果直接拿去做WHERE条件跟DATETIME字段比较,隐式转换的规则很可能会让你吃亏。比如"20240506"这个字符串跟DATETIME字段比较时,MySQL会尝试把字段值转成字符串去比,索引可能就废了。更稳妥的做法是先在代码里用STRING_TO_DATE或者STR_TO_DATE显式转成日期。

第三类是报表和展示需求。公司领导要看月度报表,日期需要显示成"2024年05月",或者图表要按周汇总,需要提取"第几周"这种信息。这种就是DATE_FORMAT的主场。

1.2 转换失败的头号原因:格式说明符不匹配

我相信每个人都遇到过这种报错:Incorrect datetime value: '2024-05-06' for function str_to_date。这个报错看起来很直接,但背后的逻辑值得说一下。

STR_TO_DATE的原理,是拿着你给的格式说明符,去解析字符串的每一个部分。如果字符串里的分隔符、数字位数、年月日顺序跟格式说明符对不上,MySQL就傻眼了。它不会自动去猜你要干什么,所有格式都要你对齐。"2024/05/06"跟'%Y-%m-%d'就是配不上,必须写'%Y/%m/%d'。

这个很好记的类比是:你把一个写着"16:30"的纸条给一个只看"下午4点半"格式的人,他肯定看不懂。STR_TO_DATE也是一样,格式说明符就是那个"翻译规则",规则不对就报错。

2. STR_TO_DATE:字符串转日期的核心操作

2.1 函数语法与格式说明符速查

STR_TO_DATE的基本语法是:

STR_TO_DATE(str, format)

第一个参数是字符串,第二个参数是格式说明符。它返回的结果是DATE、DATETIME或者TIME类型的值。如果字符串或者格式不合法,返回NULL,当然某些严格模式下会直接报错。

我整理了一份最常用的格式说明符对照表,建议收藏:

格式符含义示例
%Y四位数年份2024
%y两位数年份24
%m两位数月份(01-12)05
%c月份数字(1-12,不带前导零)5
%d两位数字日(01-31)06
%e数字日(1-31,不带前导零)6
%H24小时制小时(00-23)14
%h12小时制小时(01-12)02
%i分钟(00-59)30
%s秒(00-59)45
%f微秒(000000-999999)123456
%W星期名(Sunday-Saturday)Sunday
%a缩写星期名(Sun-Sat)Sun
%M月份名(January-December)May
%b缩写月份名(Jan-Dec)May
%pAM或PMAM
%T时间(24小时制,HH:MM:SS)14:30:45
%j一年中的第几天(001-366)127

2.2 实操案例:常见非标准格式处理

直接看例子,使用STR_TO_DATE把各种字符串搞成标准日期。

标准化日期直接转

SELECT STR_TO_DATE('2024-05-06', '%Y-%m-%d'); -- 结果:2024-05-06

斜杠格式

SELECT STR_TO_DATE('2024/05/06', '%Y/%m/%d'); -- 结果:2024-05-06

带时间的完整字符串

SELECT STR_TO_DATE('2024-05-06 14:30:45', '%Y-%m-%d %H:%i:%s'); -- 结果:2024-05-06 14:30:45

日月年格式(欧洲常用,但你没见过不代表没有)

SELECT STR_TO_DATE('06/05/2024', '%d/%m/%Y'); -- 结果:2024-05-06(注意,这是5月6日,不是6月5日)

这里有个隐藏坑,就是%Y和%y的区别。%Y是四位的2024,%y是两位的24。你如果用%y去解析'2024',会得到类似'2020'或者'2024'吗?实际结果是,STR_TO_DATE('2024', '%y')会返回2020年?不是,它会把24解析成2024,但这里的规则依赖于MySQL的年份转换逻辑。反正你记住,四位年份就用%Y,两位年份才用%y,别混用。

带中文或英文月份的格式

SELECT STR_TO_DATE('2024年5月6日', '%Y年%c月%e日'); -- 结果:2024-05-06
SELECT STR_TO_DATE('May 6, 2024', '%M %e, %Y'); -- 结果:2024-05-06

很多人在第一个中文例子这里被绕晕,因为字符串里带了"年月日"这些中文,就担心MySQL不认识。其实没关系,格式说明符跟字符串是一一对应的。字符串有"年",格式符里也要写"年"字,MySQL会把它当普通字符跳过。

2.3 特殊场景:纯数字字符串的转换

上面都是带分隔符的,还有一种纯数字格式特别常见,比如"20240506"这种。

SELECT STR_TO_DATE('20240506', '%Y%m%d'); -- 结果:2024-05-06

注意,这种写法要求字符串位数严格对应。如果传入的是'202456'这种六位数,你写'%Y%m%d',解析完年份就占掉四位,月份跟着两位,剩下的就没了,返回NULL。所以处理之前最好先用LENGTH或者正则校验一下长度。

还有更复杂的带微秒:

SELECT STR_TO_DATE('2024-05-06 14:30:45.123456', '%Y-%m-%d %H:%i:%s.%f'); -- 结果:2024-05-06 14:30:45.123456

MySQL的DATETIME默认精度是0位小数,想存微秒要把字段类型改成DATETIME(6),这个容易忽略。

3. DATE_FORMAT:反向操作的利器

3.1 语法与格式化输出原理

DATE_FORMAT是STR_TO_DATE的反向操作,输入一个日期类型的值,按你给的格式说明符输出成字符串。

DATE_FORMAT(date, format)

它的参数是日期类型,不是字符串。所以拿字符串直接传给DATE_FORMAT,虽然MySQL会做隐式转换,但千万别依赖这个行为,老老实实把字符串先转成日期,再格式化。这也是我强调的方向感问题。

3.2 业务中高频使用的格式组合

标准日期转中文格式

SELECT DATE_FORMAT('2024-05-06', '%Y年%m月%d日'); -- 结果:2024年05月06日

月份和日不带前导零

SELECT DATE_FORMAT('2024-05-06', '%Y年%c月%e日'); -- 结果:2024年5月6日

注意%m和%c的区别。%m是两位数,05;%c是一位数,5。报表标题里一般用%c好看一些。

时间戳字段转时分秒

SELECT DATE_FORMAT(NOW(), '%H:%i:%s'); -- 结果类似:14:30:45

日期+星期组合

SELECT DATE_FORMAT(NOW(), '%Y-%m-%d %W'); -- 结果类似:2024-05-06 Monday

按月份-日期的排序需求

比如按月份名字排序,直接用MONTH函数排序会跟字符串排序不一样,可以这样:

SELECT DATE_FORMAT(date_col, '%m') AS month_num, DATE_FORMAT(date_col, '%M') AS month_name FROM orders GROUP BY month_num, month_name ORDER BY month_num;

不过这种写法其实用MONTH(date_col)更直接。这里只是给你看DATE_FORMAT的灵活性。

3.3 日期格式化在报表周统计中的实战

还有一个非常高频率的用法,就是按天、周、月做分组统计。按天分组很简单,GROUP BY DATE(date_col),按周GROUP BY WEEK(date_col),按月GROUP BY DATE_FORMAT(date_col, '%Y-%m')。

SELECT DATE_FORMAT(create_time, '%Y-%m') AS month, COUNT(*) AS order_count, SUM(amount) AS total_amount FROM orders WHERE create_time >= '2024-01-01' GROUP BY DATE_FORMAT(create_time, '%Y-%m') ORDER BY month;

这里有个MySQL的SQL模式坑。在ONLY_FULL_GROUP_BY模式下,你SELECT的字段必须出现在GROUP BY里。所以month这个别名可以在ORDER BY里用,但GROUP BY里如果写别名,有些版本可能不认,最好写完整的DATE_FORMAT表达式。上面的SQL就是写的完整表达式。

另一个坑是GROUP BY别名的问题。MySQL允许GROUP BY后面跟SELECT里的别名,但如果你在GROUP BY用了别名,又同时用了WHERE,顺序就要注意。WHERE是在分组之前过滤的,所以上面的SQL用WHERE create_time >= '2024-01-01'没问题,但不能用HAVING替代WHERE去过滤create_time,因为HAVING是在分组之后过滤的,性能差很多。

4. 隐式转换的坑:CAST与CONVERT的正确位置

4.1 MySQL的隐式转换规则

MySQL有个特性:当字符串跟日期类型比较时,它会尝试把字符串转成日期做比较。这个特性是好是坏,完全取决于你的字符串格式。

SELECT * FROM orders WHERE create_time = '2024-05-06';

这条你直接用,大概率没问题。MySQL会隐式把字符串转成DATE类型去匹配。但是如果create_time是DATETIME,字段里存的是'2024-05-06 14:30:45',你写'2024-05-06'去等值匹配,实际上是匹配不到的,因为DATETIME的比较是精确到秒的。隐含转出来的是'2024-05-06 00:00:00',跟'2024-05-06 14:30:45'怎么会相等。所以很多人写等值查询查不到数据,怀疑数据丢了,实际上就是这个原因。

正确姿势是用范围查询:

SELECT * FROM orders WHERE create_time >= '2024-05-06' AND create_time < '2024-05-07';

4.2 隐式转换导致索引失效的经典案例

字符串跟日期比较还会有另一个问题,就是索引失效。举一个实际案例。

假设有订单表orders,create_time上有索引。你用下面两种方式查询:

-- 方式A:字符串直接比较 SELECT * FROM orders WHERE create_time > '2024-05-06'; -- 方式B:隐式转换 SELECT * FROM orders WHERE create_time > '20240506';

方式A里'2024-05-06'会隐式转成日期,索引还能用。方式B里'20240506'如果跟create_time比较,MySQL会怎么处理?你可能觉得它也会转成日期,实际执行计划很可能走全表扫描。原因是MySQL在优化阶段把'20240506'跟日期字段比较时,无法直接确定转换规则能走索引,尤其在字符串格式不一致的时候,干脆放弃索引。用EXPLAIN看一下就能验证。

所以最稳的做法是先用STR_TO_DATE把字符串转好再用:

SELECT * FROM orders WHERE create_time > STR_TO_DATE('20240506', '%Y%m%d');

4.3 CAST和CONVERT的边界

CAST和CONVERT也可以做字符串跟日期之间的转换,语法是:

CAST('2024-05-06' AS DATE) CONVERT('2024-05-06', DATE)

但跟STR_TO_DATE相比,CAST和CONVERT能识别的基本是MySQL默认的'YYYY-MM-DD'格式。如果你拿'2024/05/06'去CAST,结果是NULL,不会报错,但你会莫名丢数据。

我用一个对比给你看清楚:

输入STR_TO_DATE('2024/05/06', '%Y/%m/%d')CAST('2024/05/06' AS DATE)
结果2024-05-06(正常)NULL(失败)
原理按指定格式解析只认默认格式

所以CAST和CONVERT适合那种数据源已经很规范的场景,STR_TO_DATE适合需要自定义格式的场景。日常开发里,但凡字符串格式可能不标准,一律用STR_TO_DATE。

另外,CAST还可以转成DATETIME或者TIME:

SELECT CAST('2024-05-06 14:30:45' AS DATETIME); SELECT CAST('14:30:45' AS TIME);

这些用法在日常ETL里用得挺多。但记住,CAST无法处理非标准格式,这是硬伤。

5. 时间戳与日期的相互转换

5.1 UNIX_TIMESTAMP与FROM_UNIXTIME的一对互相转换

除了字符串跟日期之间的转换,开发中还经常会碰到Unix时间戳跟日期的互相转换。电商订单表经常存create_time是INT类型的时间戳,查出来要显示成日期,就要用FROM_UNIXTIME。

SELECT FROM_UNIXTIME(1714977045); -- 结果:2024-05-06 06:30:45(取决于时区)

反向操作:

SELECT UNIX_TIMESTAMP('2024-05-06 14:30:45'); -- 结果:1714996845(取决于时区)

这里有个大坑,就是时区问题。FROM_UNIXTIME转出来的时间,跟你MySQL会话的时区有关。如果你的MySQL时区设置的是UTC,那么时间戳1714977045转出来就是UTC时间,跟北京时间差了8小时。很多时候你以为数据错了,实际上是时区没配好。

检查当前时区:

SELECT @@global.time_zone, @@session.time_zone;

一般生产库都建议把时区设置成系统时区或者'Asia/Shanghai',否则时间数据乱套。修改方式:

SET time_zone = '+08:00';

这个修改只对当前会话有效。要让全局生效,改配置文件里的default-time-zone,然后重启。

5.2 字符串日期转时间戳的两种姿势

字符串日期转时间戳,有两种写法:

-- 方式一:先用STR_TO_DATE转成日期,再转时间戳 SELECT UNIX_TIMESTAMP(STR_TO_DATE('2024-05-06', '%Y-%m-%d')); -- 方式二:直接拿字符串给UNIX_TIMESTAMP SELECT UNIX_TIMESTAMP('2024-05-06');

方式二看起来更简短,但它的前提是字符串格式能被MySQL隐式识别。你传'20240506'进去,UNIX_TIMESTAMP返回NULL。所以标准做法还是方式一,先STR_TO_DATE保证格式可控。

顺带说一个实践:如果你只想要当前时间的时间戳,直接用UNIX_TIMESTAMP(NOW()),不要自己拼字符串再转,多此一举还可能踩格式坑。

6. 常见问题与排查技巧实录

6.1 报错与异常结果速查表

我整理了一张问题速查表,都是平时答疑群里高频出现的问题:

场景现象原因解决方式
STR_TO_DATE返回NULL插入数据变成NULL格式说明符跟字符串不匹配用参数逐一比对字符串和格式
DATE_FORMAT拿字符串当参数结果异常或NULL字符串没先转日期先STR_TO_DATE再DATE_FORMAT
等值查询查不到数据WHERE create_time = '2024-05-06'查不到DATETIME字段精确到秒改用范围查询区分边界
24小时制写成%I时间解析错乱%I是12小时制24小时制用%H
月份格式%m写成%M解析成英文月份名字%M是月份名%m才是数字月份
CAST('2024/05/06' AS DATE)为NULL转换失败CAST只认默认格式用STR_TO_DATE指定%Y/%m/%d
GROUP BY日期列报ONLY_FULL_GROUP_BY错误分组不通过SELECT的字段没有都在GROUP BY里GROUP BY写完整表达式
时间戳转换后差了8小时数据时区不对会话时区是UTC设置time_zone='+08:00'
月份用%c查出来有前导零001这种%j是一年中的第几天月份用%m或%c

6.2 排查日期转换问题的方法论

遇到日期转换问题,千万别一个个去猜。我通常按这个顺序排查。

先看字符串长什么样。print出来,数一数位数,确认每个位置是什么。如果你连字符串格式都说不清楚,后面的格式写对了也没用。再确认你要转成什么类型,是DATE精确到天,还是DATETIME精确到秒。第三步写一个单独的SELECT验证,不要直接放到INSERT或者UPDATE里,不然报错了也不知道是哪个字段的问题:

SELECT STR_TO_DATE('你的字符串', '你的格式') AS test_result;

如果这个SELECT返回NULL,先别怀疑函数有问题,格式化字符串跟输入字符串不匹配的可能性最大。把字符串和格式符放在一起:

SELECT STR_TO_DATE('2024-05-06', '%Y-%m-%d') AS result1, STR_TO_DATE('2024/05/06', '%Y/%m/%d') AS result2, STR_TO_DATE('20240506', '%Y%m%d') AS result3;

多写几个可能方案,做横向对比,一眼就知道哪个格式才是对的。这比盲查文档高效得多。

还有一个隐蔽问题:字符串里的空格和不可见字符。有时候从外部系统拿到的数据,表面上看起来是'2024-05-06',但实际上末尾带了一个回车符或者空格,STR_TO_DATE就会返回NULL。处理办法是转换前先TRIM一下:

SELECT STR_TO_DATE(TRIM(' 2024-05-06 '), '%Y-%m-%d');

更隐蔽的是全角空格。Excel导入的数据偶尔会有这种,TRIM都去不掉。这时候用HEX函数看字节内容,然后REPLACE掉:

SELECT HEX('2024-05-06');

比如你发现字符串里其实是'2024-05-06 ',末位有个A0(不换行空格),那就:

SELECT STR_TO_DATE(REPLACE('2024-05-06 ', CHAR(160), ''), '%Y-%m-%d');

6.3 字符串日期比较的时间边界陷阱

还有一个很值得说的陷阱,就是日期边界。很多新手查某天数据的时候会用:

SELECT * FROM orders WHERE DATE(create_time) = '2024-05-06';

这样写在功能上看着没错,但DATE(create_time)对create_time字段做了函数处理,create_time上的索引就废了。数据量小无所谓,数据量一大这SQL能慢到你怀疑人生。正确写法是范围查询:

SELECT * FROM orders WHERE create_time >= '2024-05-06 00:00:00' AND create_time < '2024-05-07 00:00:00';

这个例子虽然不是直接的字符串日期格式转换,但在日常业务里是伴随问题。我把这个案例拿来说是想提醒你,做日期转换的时候,时刻想着索引能不能用上。转换本身很简单,但转换背后牵扯的查询性能问题才是真正考验人的地方。

另外,时间边界还有一个特殊场景,就是跨年和跨月。比如你要查"上个月"的数据,最好不要写死日期,而是用动态计算:

SELECT * FROM orders WHERE create_time >= DATE_FORMAT(CURDATE() - INTERVAL 1 MONTH, '%Y-%m-01') AND create_time < DATE_FORMAT(CURDATE(), '%Y-%m-01');

这里用了DATE_FORMAT把当前日期格式化到月初,用INTERVAL做月份加减,既不用关心天数,也不容易出错。这也是日期转换函数的活学活用。

7. 函数组合的进阶玩法与数据清洗案例

7.1 一个典型的导入数据清洗过程

假设你要从外部系统导订单数据,源数据里的日期字段长这样:'2024-05-06 14:30:45'和'2024-05-06 14:30'混着出现,还有的是'20240506143045'。要把它们全部统一成标准DATETIME插入目标表,该怎么做?

分情况处理:

SELECT CASE WHEN create_time_str LIKE '____-__-__ __:__:__' THEN STR_TO_DATE(create_time_str, '%Y-%m-%d %H:%i:%s') WHEN create_time_str LIKE '____-__-__ __:__' THEN STR_TO_DATE(create_time_str, '%Y-%m-%d %H:%i') WHEN create_time_str REGEXP '^[0-9]{14}$' THEN STR_TO_DATE(create_time_str, '%Y%m%d%H%i%s') ELSE NULL END AS parsed_time FROM raw_orders;

这套逻辑的核心是先用LIKE或REGEXP做粗筛,再按不同的格式去解析。实际导入数据时,这种多格式混合是最恶心的。更保险的做法是先跑这个SELECT,把能解析出来的样本都看一遍,确认格式分类没错,再正式做INSERT:

INSERT INTO orders(create_time) SELECT CASE WHEN create_time_str LIKE '____-__-__ __:__:__' THEN STR_TO_DATE(create_time_str, '%Y-%m-%d %H:%i:%s') WHEN create_time_str REGEXP '^[0-9]{14}$' THEN STR_TO_DATE(create_time_str, '%Y%m%d%H%i%s') ELSE NULL END FROM raw_orders WHERE create_time_str IS NOT NULL;

这个WHERE过滤很重要,不然NULL值也会被插进表里。如果你想把解析失败的记录单独排查出来,加个HAVING或者用一个标记字段:

SELECT create_time_str, CASE WHEN parsed_time IS NULL THEN '解析失败' ELSE 'OK' END AS parse_status FROM ( SELECT create_time_str, CASE WHEN create_time_str LIKE '____-__-__ __:__:__' THEN STR_TO_DATE(create_time_str, '%Y-%m-%d %H:%i:%s') WHEN create_time_str REGEXP '^[0-9]{14}$' THEN STR_TO_DATE(create_time_str, '%Y%m%d%H%i%s') ELSE NULL END AS parsed_time FROM raw_orders ) t WHERE parsed_time IS NULL;

这样你就能把所有解析失败的数据捞出来,回头检查源文件是不是有脏数据。

7.2 格式化与聚合组合的报表实践

除了数据清洗,格式化组合最常见的场景还是日报周报统计。比如统计订单表里每周的销售情况,要显示周数和销售额:

SELECT DATE_FORMAT(create_time, '%x年第%v周') AS week_label, COUNT(*) AS order_count, SUM(total_amount) AS sales_amount FROM orders WHERE create_time >= '2024-01-01' GROUP BY DATE_FORMAT(create_time, '%x年第%v周') ORDER BY MIN(create_time);

这里用了%x和%v,%x是周所在的年份,%v是周数(01-53),组合起来就能正确标识"第几周"。注意%v跟%V的区别,%v是周从周一开始算,%V是周从周日开始算。不同国家的周起始日不一样,统计口径要对齐。ORDER BY MIN(create_time)是为了按时间顺序排,不然按周名字符串排,'第10周'会排到'第2周'前面。

7.3 日期函数嵌套使用的坑

再补充一个嵌套使用的常见坑。有人会把STR_TO_DATE和DATE_FORMAT嵌套在一起:

SELECT DATE_FORMAT(STR_TO_DATE('2024-05-06', '%Y-%m-%d'), '%Y年%m月%d日');

这个写法没问题。但不要反过来,把DATE_FORMAT的结果再去传给STR_TO_DATE,多此一举:

-- 这种就绕了:把一个已经是字符串的结果又当字符串转 SELECT STR_TO_DATE(DATE_FORMAT(NOW(), '%Y-%m-%d'), '%Y-%m-%d');

结果虽然对,但根本没必要。NOW()本身是datetime,直接格式化输出就行。写SQL要追求可读性和效率,不是比谁嵌套得深。

根据我的经验,一个好的习惯是:先想清楚源数据的格式是什么,再想清楚目标字段的类型是什么,中间的桥就只有一个函数调用。格式转换的工作量不在写SQL那一行,而在你对源数据格式的判断上。

说到这,我分享一个自己之前踩过的坑:有一次清洗第三方平台导出的订单表,日期字段在Excel里显示的是"2024-05-06 14:30",但实际单元格格式里带着一个不可见的时间微秒部分,导出成CSV以后字符串就变成了"2024-05-06 14:30:00.123"。我当时按'%Y-%m-%d %H:%i'去解析,结果解析出来全是NULL。排查了半天,最后用HEX函数看到字符串末尾有".123",才定位到问题。从那以后,我处理外部数据源都会先跑一遍HEX,看看有没有不可见字符或者微秒尾巴,再决定格式串怎么写。

还有一次,某公司内部系统的日期格式是"2024/05/06(周一)"这种带着中文括号和星期的,一开始按'%Y/%m/%d(%a)'解析,MySQL死活不认%a跟中文的组合。后来改成先把括号切掉:

SELECT STR_TO_DATE( SUBSTRING_INDEX(SUBSTRING_INDEX('2024/05/06(周一)', '(', 1), '/', -1), '%Y/%m/%d' );

这里其实用了SUBSTRING_INDEX预处理,把"2024/05/06(周一)"先切成"2024/05/06",再转日期。遇到复杂的脏格式,别指望一个STR_TO_DATE全搞定,先做字符串清洗,再做格式转换,分步走反而更稳。

最后补充一点,如果你用的是MySQL 8.0,新函数里没有专门改变日期格式的,但8.0对日期字符串的隐式转换行为做了更严格的校验。以前MySQL 5.7能容忍一些非法的日期值,8.0直接报错或者返回NULL。所以升级到8.0之后,以前能跑的SQL突然查到NULL,别慌,大概率是格式解析变得更严格了,用显式STR_TO_DATE重新写一遍就好。

字符串日期格式转换这件事,看着简单,真正用起来细节特别多。格式说明符记牢、方向别搞反、边界条件想清楚,你就能避开大部分坑。多写几个SELECT验证,多看看HEX和EXPLAIN,比啥都管用。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询