TIMEFROMPARTS仅接受5个整数参数(时、分、秒、纳秒、精度),不支持字符串输入;错误传入varchar会报错,需用TRY_CAST校验并转换,非法值返回NULL。

TIMEFROMPARTS 不能直接拼接字符串时间,必须传入整数参数
很多人看到函数名里有“FROM”就以为能从 '09:30:45' 这样的字符串解析,其实 TIMEFROMPARTS 是纯构造函数:它只接受 5 个整数参数(小时、分钟、秒、纳秒、精度),不接受字符串或日期类型。传错类型会直接报错:Argument data type varchar is invalid for argument 1 of timefromparts function。
常见错误写法:
SELECT TIMEFROMPARTS('09', '30', '45', 0, 7); -- ❌ 报错:varchar 不合法正确做法是先确保各字段是整数:
- 用
CAST或CONVERT显式转成INT(注意处理空值和非法字符) - 如果原始数据在表中是字符串列(如
hour_str),务必加ISNUMERIC()或TRY_CAST()做前置校验 - 纳秒参数不是“毫秒”,范围是 0–999999999;精度参数(第 5 个)仅控制返回值的小数位数(如 3 表示
hh:mm:ss.nnn),不影响计算
用 TRY_CAST + TIMEFROMPARTS 处理可能含脏数据的列
生产环境里,时间片段常来自用户输入或日志解析,存在空值、超范围值(如小时=25)、非数字字符。硬用 CAST 会中断整个查询。推荐组合 TRY_CAST 和 TIMEFROMPARTS:
SELECT
TIMEFROMPARTS(
TRY_CAST(hour_col AS INT),
TRY_CAST(minute_col AS INT),
TRY_CAST(second_col AS INT),
0,
3
) AS safe_time
FROM your_table;这样遇到无法转换的值,TIMEFROMPARTS 会返回 NULL 而非报错。但要注意:
-
TRY_CAST对空字符串返回NULL,对' '(空格)也返回NULL - 小时超出 0–23、分钟/秒超出 0–59 时,
TIMEFROMPARTS仍会报错,需额外用CASE过滤 - 如果想把非法时间统一转成默认值(如
'00:00:00'),得在外层再套一层ISNULL或CASE
精度参数(第 5 个)影响输出格式,但不改变实际值
这个参数只控制返回的 time 类型小数位长度,和存储无关。例如:
SELECT TIMEFROMPARTS(14, 30, 45, 123456789, 0), -- '14:30:45' TIMEFROMPARTS(14, 30, 45, 123456789, 3), -- '14:30:45.123' TIMEFROMPARTS(14, 30, 45, 123456789, 7); -- '14:30:45.1234568'
关键点:
- 纳秒值
123456789在精度为 3 时被截断为.123(毫秒级),不是四舍五入 - 精度最大支持 7,最小为 0;设为 7 时,纳秒部分会按微秒四舍五入(即保留 100ns 单位)
- 如果业务只要到秒,固定用
0,避免无谓的精度开销
替代方案:用 DATETIME2FROMPARTS 拼日期+时间再转 time
当只有时间片段但需要结合某一天做比较(比如查“今天 9:30 之后的订单”),直接拼 time 可能不够——因为 time 类型无法跨天运算。这时更稳妥的做法是先构造 datetime2,再转 time:
SELECT
CAST(
DATETIME2FROMPARTS(
YEAR(GETDATE()), MONTH(GETDATE()), DAY(GETDATE()),
9, 30, 0, 0, 0
) AS time
) AS today_0930;这种写法的好处:
- 绕过
TIMEFROMPARTS对非法时间值的严格校验(DATETIME2FROMPARTS同样严格,但组合更灵活) - 便于后续和
datetime2字段直接比较,不用担心隐式转换问题 - 如果原始数据含时区信息,
DATETIME2FROMPARTS更容易扩展为DATETIMEOFFSETFROMPARTS
真正麻烦的从来不是函数怎么写,而是你拿到的“小时”“分钟”字段到底干不干净——多一次 TRY_CAST,少半夜一次告警。

















