You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C#对接SQL Server 2019使用DateTimeOffset时日期转换失败问题

问题根因

报错的核心原因是拼接SQL字符串传入日期+SQL Server会话日期格式不匹配,和.NET端的日期输出格式配置没有本质关联:

  • 你当前将DateTimeOffset值格式化为dd/MM/yyyy规则的字符串直接拼接进SQL,但当前SQL Server会话的DATEFORMAT配置为MDY(美式日期规则:月在前、日在后),当字符串中日字段值大于12时(比如23/06/2022,SQL Server会将首位的23识别为月份,超出1-12的合法月份范围直接抛出转换错误)。
  • 你手动互换日月位置后能执行,只是刚好匹配了MDY的解析规则,属于巧合,不是正确解法。后续遇到日字段值小于等于12的场景会出现隐蔽的逻辑错误:比如12/06/2022会被解析为6月12日,而非你预期的12月6日。
  • 另外你.NET端生成UTC时间的代码存在逻辑错误:通过new DateTime(utcNow.Year, utcNow.Month, utcNow.Day, 0, 0, 0)生成的DateTime类型为Unspecified,传入DateTimeOffset构造函数时会默认取当前系统的本地时区偏移,因此你生成的参数带+01:00偏移,并非你需要的UTC标准时间(UTC时间偏移应为+00:00)。
解决方案

1. 优先使用强类型参数化查询(唯一彻底规避格式问题的方案)

完全不要将日期值转为字符串拼接SQL,通过ADO.NET的强类型参数直接传DateTimeOffset类型值,驱动会自动完成类型映射,全程没有字符串解析环节,完全不受SQL Server区域、语言、日期格式配置影响。
.NET端正确实现代码:

// 修正UTC零点生成逻辑,指定偏移为0时区
DateTimeOffset utcNow = DateTimeOffset.UtcNow;
DateTimeOffset beginDate = new DateTimeOffset(utcNow.Year, utcNow.Month, utcNow.Day, 0, 0, 0, TimeSpan.Zero);
DateTimeOffset endDate = beginDate.AddDays(1); // 按实际查询区间计算结束时间

// 构造SQL参数,明确指定类型为DateTimeOffset
using var command = new SqlCommand(querySql, dbConnection);
command.Parameters.Add(new SqlParameter("@BeginDate", SqlDbType.DateTimeOffset) { Value = beginDate });
command.Parameters.Add(new SqlParameter("@EndDate", SqlDbType.DateTimeOffset) { Value = endDate });

对应SQL中的过滤条件改为参数占位,不要写硬编码字符串:

WHERE
    AttachedFile.RowNumber = 1 AND
    ExpirationDate >= @BeginDate AND ExpirationDate < @EndDate

2. 特殊场景必须硬编码日期字符串的处理方式

如果受场景限制必须在SQL中写日期常量,使用SQL Server全局兼容、不受区域配置影响的ISO 8601格式书写datetimeoffset值,格式规则为yyyy-MM-dd HH:mm:ss.fffffff zzz,示例:

ExpirationDate >= '2022-06-12 00:00:00.0000000 +00:00' 
AND ExpirationDate < '2022-06-13 00:00:00.0000000 +00:00'

该格式在任何SQL Server日期格式、语言配置下都能被正确解析,不会出现转换错误。

内容的提问来源于stack exchange,提问作者Andre Forte

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.01 22:21:36