在Microsoft SQL Server中,处理日期时间数据并将其转换为指定格式的字符串,是日常查询、报表导出以及系统间数据交换里非常基础的操作。MSSQL主要依赖CONVERT函数与SQL Server 2012之后引入的FORMAT函数来完成日期格式化,两者在用法、性能和兼容性上存在明显差异。

一、CONVERT函数与样式码
CONVERT是MSSQL传统的类型转换函数,语法为CONVERT(data_type, expression, style)。其中style是一个整数代码,决定了datetime如何转为字符串。这种方式不依赖.NET运行时,在所有MSSQL版本中都能使用,且在大数据量转换时性能通常优于FORMAT。
下面列出开发中最常接触的几种样式码。注意,带世纪数位(四位数年份)与不带世纪数位的样式输出差别很大,对接老旧系统时要特别确认。
-- 常用CONVERT日期格式示例 SELECT CONVERT(varchar(20), GETDATE(), 120) AS style_120; -- 2024-05-21 14:30:05 SELECT CONVERT(varchar(8), GETDATE(), 112) AS style_112; -- 20240521 SELECT CONVERT(varchar(10), GETDATE(), 101) AS style_101; -- 05/21/2024 美国格式 SELECT CONVERT(varchar(10), GETDATE(), 103) AS style_103; -- 21/05/2024 英国格式 SELECT CONVERT(varchar(30), GETDATE(), 126) AS style_126; -- 2024-05-21T14:30:05.123
从上面代码可以看出,样式120输出符合ISO8601基本日期时间格式,非常适合作为接口字段;样式112是无分隔符数字日期,常用于文件名或主键拼接;样式101与103则受区域习惯影响,跨国项目里容易引发歧义,不建议作为标准存储格式。
需要提醒的是,CONVERT目标类型若长度不够,字符串会被截断而不报错。例如用varchar(10)接样式120只会留下日期部分,时间被默默切掉,排查起来很隐蔽。
二、FORMAT函数的自由格式
从SQL Server 2012起,可以使用FORMAT函数基于.NET格式字符串输出日期。它写法直观,支持自定义如“yyyy年MM月dd日”这类中文格式,但底层调用CLR,批量处理时比CONVERT慢很多。
以下示例展示FORMAT的灵活写法,以及与CONVERT在结果上的对应:
-- FORMAT自定义日期格式 SELECT FORMAT(GETDATE(), 'yyyy-MM-dd HH:mm:ss') AS fmt_1; SELECT FORMAT(GETDATE(), 'yyyy年MM月dd日') AS fmt_2; SELECT FORMAT(GETDATE(), 'MM/dd/yy') AS fmt_3; -- 与CONVERT(120)等效 SELECT FORMAT(GETDATE(), 'yyyy-MM-dd HH:mm:ss') = CONVERT(varchar(19), GETDATE(), 120);
FORMAT的优势是格式串所见即所得,产品运营提需求说“要2024年05月21日这种”,直接写进去就行,不用查样式表。但在千万行报表里滥用FORMAT,会让存储过程时间翻倍,此时应改用CONVERT或在应用层格式化。
另外,FORMAT对区域参数culture支持很好,可以写FORMAT(GETDATE(),'d','zh-cn')拿到本地短日期,不过这同样有性能代价,低频查询才划算。
三、常见格式对照表
为方便查阅,将最常用格式整理成表。实际项目中,推荐接口统一用120或126,内部展示按用户区域选FORMAT。
| 用途 | CONVERT样式 | 示例输出 | 说明 |
|---|---|---|---|
| 接口标准 | 120 | 2024-05-21 14:30:05 | ODBC标准,无歧义 |
| 文件名 | 112 | 20240521 | 纯数字便于排序 |
| XML时间 | 126 | 2024-05-21T14:30:05 | 含ISO时间戳 |
| 美国报表 | 101 | 05/21/2024 | 月日年顺序 |
| 中文展示 | FORMAT | 2024年05月21日 | 需2012+ |
表中CONVERT样式码都是官方固定值,不要自己推算其他数字,未文档化的代码在不同版本可能表现不一致。遇到特殊历法或日文元号需求,要测试目标实例确认。
四、隐式转换与避坑
把格式化字符串再存回日期列时,MSSQL会做隐式转换。例如INSERT INTO t(d) VALUES('2024-05-21')通常成功,但'21/05/2024'在默认语言下会报转换失败。这要求写入前明确用CONVERT指定样式,而不是依赖数据库猜测。
下面的代码演示安全写法:
-- 安全将字符串转为日期 DECLARE @s varchar(10) = '21/05/2024'; SELECT CONVERT(datetime, @s, 103) AS safe_date; -- 错误示范:依赖隐式转换,可能报错 -- SELECT CAST(@s AS datetime);
还有一个坑是DATEFIRST设置会影响星期相关格式,跨语言库迁移时要检查@@DATEFIRST。整体来说,掌握CONVERT样式码加上少量FORMAT定制,就能覆盖MSSQL里九成以上的日期格式需求。