在 C# 中将字符串解析为 DateTime 模仿 SQL 服务器 CAST/CONVERT 的行为
Parse string to DateTime in C# mimicking behavior of SQL Server CAST/CONVERT
我正在使用一个数据库,该数据库包含以各种不同格式存储为字符串的日期时间值。这些值是从不同的外部来源获得的,它们的格式不在我的控制范围内。可以枚举当前存储在数据库中的所有格式,但一些尚未见过的格式可能会在将来的某个时候出现。
过去,这些值使用 SQL 服务器的 CONVERT 函数解析为 SQL DATETIME,然后返回给 .NET 应用程序。现在应用程序正在接收字符串,解析必须在那里进行。
我最初使用 DateTime.Parse(),但失败了,因为它无法处理 SQL 服务器默认处理的某些格式(例如“yyyyMMdd”)。下一个方法是使用 DateTime.TryParseExact 重载,它采用各种格式的字符串数组。类似于:
var dateTimeString = "20210101";
var dateTimeFormatInfo = System.Threading.Thread.CurrentThread.CurrentCulture.DateTimeFormat;
var expectedDateTimeFormats = dateTimeFormatInfo.GetAllDateTimePatterns().ToList();
expectedDateTimeFormats.Add("yyyyMMdd");
DateTime.TryParseExact(dateTimeString, expectedDateTimeFormats.ToArray(), CultureInfo.InvariantCulture, DateTimeStyles.AllowWhiteSpaces, out var myDateTime);
除了它也不处理某些格式,例如“yyyy-mm-dd hh:mi:ss.mmm”,此方法有效,SQL 服务器默认处理。具有讽刺意味的是,DateTime.Parse().
也很好地处理了这个特定示例
是否有一种好的方法可以在 C# 中模仿 SQL 服务器的 CONVERT(DATETIME, val) 的行为,以尝试并成功地解析至少与转换的原始解决方案中处理的格式一样多的格式在数据库中完成了吗?
我认为包含列出的所有格式的 ParseExact 解决方案 here 可能有效,但我想知道是否有更好的方法。或者也许是一个更好的方法。
如果您可以控制数据库的模式,您可以创建视图或 Computed Column on the Table with the FORMAT()
function 以 C# 的 DateTime 可以轻松处理的标准化和单一一致的格式来格式化日期。
请注意,在某些情况下,FORMAT()
函数 的性能可能 低于其他本机 SQL 服务器函数。
更新: @jeroen-mostert 关于使用 SqlDateTime.Parse
的评论可能比我们最终使用的答案更好。
原回答:
以防将来对任何人有帮助,答案最终是使用 DateTime.TryParse() ,如果失败,则使用尚未支持的特殊格式调用 DateTime.TryParseExact()通过 TryParse().
从浏览源代码来看,Parse/TryParse 似乎对分隔符之类的东西更宽松,因此它甚至可以使用在枚举 dateTimeFormatInfo.GetAllDateTimePatterns() 时未显示的类似格式。我相信这解释了为什么 TryParseExact 似乎无法使用 TryParse 支持的格式,即使 TryParseExact 使用 DateTimeFormatInfo 对象提供的所有 DateTime 模式也是如此。
我还根据 Microsoft 文档中列出的 Date and Time Styles 验证了格式支持。不过,此解决方案并不支持 100%。这是设计使然,因为某些组合可能是不确定的,幸好我们局限于特定的文化。
正如评论中指出的那样,这不是一个完美的解决方案,但它在这里起到了作用。
我正在使用一个数据库,该数据库包含以各种不同格式存储为字符串的日期时间值。这些值是从不同的外部来源获得的,它们的格式不在我的控制范围内。可以枚举当前存储在数据库中的所有格式,但一些尚未见过的格式可能会在将来的某个时候出现。
过去,这些值使用 SQL 服务器的 CONVERT 函数解析为 SQL DATETIME,然后返回给 .NET 应用程序。现在应用程序正在接收字符串,解析必须在那里进行。
我最初使用 DateTime.Parse(),但失败了,因为它无法处理 SQL 服务器默认处理的某些格式(例如“yyyyMMdd”)。下一个方法是使用 DateTime.TryParseExact 重载,它采用各种格式的字符串数组。类似于:
var dateTimeString = "20210101";
var dateTimeFormatInfo = System.Threading.Thread.CurrentThread.CurrentCulture.DateTimeFormat;
var expectedDateTimeFormats = dateTimeFormatInfo.GetAllDateTimePatterns().ToList();
expectedDateTimeFormats.Add("yyyyMMdd");
DateTime.TryParseExact(dateTimeString, expectedDateTimeFormats.ToArray(), CultureInfo.InvariantCulture, DateTimeStyles.AllowWhiteSpaces, out var myDateTime);
除了它也不处理某些格式,例如“yyyy-mm-dd hh:mi:ss.mmm”,此方法有效,SQL 服务器默认处理。具有讽刺意味的是,DateTime.Parse().
也很好地处理了这个特定示例是否有一种好的方法可以在 C# 中模仿 SQL 服务器的 CONVERT(DATETIME, val) 的行为,以尝试并成功地解析至少与转换的原始解决方案中处理的格式一样多的格式在数据库中完成了吗?
我认为包含列出的所有格式的 ParseExact 解决方案 here 可能有效,但我想知道是否有更好的方法。或者也许是一个更好的方法。
如果您可以控制数据库的模式,您可以创建视图或 Computed Column on the Table with the FORMAT()
function 以 C# 的 DateTime 可以轻松处理的标准化和单一一致的格式来格式化日期。
请注意,在某些情况下,FORMAT()
函数 的性能可能 低于其他本机 SQL 服务器函数。
更新: @jeroen-mostert 关于使用 SqlDateTime.Parse
的评论可能比我们最终使用的答案更好。
原回答:
以防将来对任何人有帮助,答案最终是使用 DateTime.TryParse() ,如果失败,则使用尚未支持的特殊格式调用 DateTime.TryParseExact()通过 TryParse().
从浏览源代码来看,Parse/TryParse 似乎对分隔符之类的东西更宽松,因此它甚至可以使用在枚举 dateTimeFormatInfo.GetAllDateTimePatterns() 时未显示的类似格式。我相信这解释了为什么 TryParseExact 似乎无法使用 TryParse 支持的格式,即使 TryParseExact 使用 DateTimeFormatInfo 对象提供的所有 DateTime 模式也是如此。
我还根据 Microsoft 文档中列出的 Date and Time Styles 验证了格式支持。不过,此解决方案并不支持 100%。这是设计使然,因为某些组合可能是不确定的,幸好我们局限于特定的文化。
正如评论中指出的那样,这不是一个完美的解决方案,但它在这里起到了作用。