SQL Server 2016+ 支持 AT TIME ZONE,但仅适用于 DATETIMEOFFSET 类型,且需显式指定源时区;对无时区时间须先用 TODATETIMEOFFSET 构造,再链式转换,否则易因服务器时区或夏令时规则导致错误。

AT TIME ZONE 在 SQL Server 中是否可用?
不能直接用。SQL Server 2016+ 虽然支持 AT TIME ZONE,但它只作用于 DATETIMEOFFSET 类型,且要求输入值本身已带时区偏移(即必须是 DATETIMEOFFSET,不是 DATETIME2 或 SMALLDATETIME)。如果你传入的是无时区的 DATETIME2,SQL Server 会默认按当前服务器时区解释它,再转换——这在跨时区存储过程里极易出错。
常见错误现象:CONVERT(DATETIME2, '2024-05-01 10:00:00') AT TIME ZONE 'China Standard Time' AT TIME ZONE 'UTC' 看似合理,实际会先按服务器本地时区(比如东八区)把字符串转成 DATETIMEOFFSET,再转 UTC,结果可能多扣或少扣 8 小时。
- 务必先用
TODATETIMEOFFSET显式指定源时区,再用AT TIME ZONE转目标时区 - 不要依赖服务器
GETDATE()的时区上下文;存储过程可能被不同时区客户端调用,SYSDATETIMEOFFSET()才反映当前会话时区(但也不可靠,最好由调用方传入源时区) - 若源时间来自应用层(如用户提交的“北京时间下午3点”),应让应用明确传入时区名或 UTC 偏移(如
'Asia/Shanghai'或'+08:00'),而非靠数据库猜
如何安全地在存储过程中做「用户本地时间 → UTC → 目标时区」转换
典型场景:用户在东京下单,订单时间存为 UTC;客服在纽约查看时需显示为当地时间。关键在于三段分离:确认源时区、转 UTC、再转目标时区。
实操建议:
- 存储过程参数定义为
@local_time DATETIME2+@source_tz VARCHAR(50)(如'Tokyo Standard Time')+@target_tz VARCHAR(50)(如'Eastern Standard Time') - 第一步:用
TODATETIMEOFFSET(@local_time, @source_tz)构造带时区的时间值(注意:SQL Server 内置时区名必须用 Windows 时区名,不是 IANA 名;'Asia/Tokyo'会报错,得用'Tokyo Standard Time') - 第二步:链式调用
AT TIME ZONE先转 UTC,再转目标时区:TODATETIMEOFFSET(@local_time, @source_tz) AT TIME ZONE 'UTC' AT TIME ZONE @target_tz - 若需兼容 IANA 时区(如应用用的是
'Europe/London'),必须在应用层或 CLR 函数中映射,SQL Server 原生不识别
为什么有时 AT TIME ZONE 返回 NULL 或报错?
两个高频原因:时区名拼写错误、输入值为 NULL 或非法日期格式。
Windows 时区名大小写不敏感,但空格和连字符必须完全匹配。例如 'Pacific Standard Time' 正确,'pacific standard time' 或 'Pacific Standard' 都失败。错误信息通常是:The timezone parameter '<code>xxx' is not valid.
- 用系统视图
sys.time_zone_info查可用名:SELECT * FROM sys.time_zone_info WHERE name LIKE '%Beijing%'—— 结果是'China Standard Time',不是'Beijing Time' -
AT TIME ZONE对NULL输入返回NULL,不会报错;但若前一步TODATETIMEOFFSET的第二个参数是NULL,则整个表达式返回NULL,容易被忽略 - 性能影响:每次调用
AT TIME ZONE都触发时区规则查表(含夏令时逻辑),高频调用建议缓存常用时区转换结果,或提前在应用层完成
跨时区存储过程最易忽略的一点
时区转换不是纯数学偏移,而是基于历史规则的查表运算。SQL Server 的 sys.time_zone_info 包含自 1980 年以来的夏令时变更记录,但不包含更早年份(如 1975 年东京是否实行夏令时?它不认)。如果业务涉及历史数据(比如金融日志追溯到 1990 年前),AT TIME ZONE 可能给出错误结果,且无警告。
此时必须放弃 SQL Server 原生方案,改用应用层时区库(如 C# 的 TimeZoneInfo 或 Python 的 zoneinfo)预处理,再把确定的 DATETIMEOFFSET 传入存储过程。

















