更新的答案
我已经编写了我在原始答案中谈到的实用程序,您可以在此处找到。
此外,从 SQL Server 2016(和 Azure SQL 数据库)开始,您现在可以使用AT TIME ZONE
关键字在时区之间进行转换。
原始答案
不幸的是,在 SQL Server 中处理时区没有很好的解决方案。
我对您链接的问题以及这个问题进行了深入调查。没有内置的时区函数,TimeZoneInfo
在 SQLCLR 中的任何使用都需要将程序集注册为“不安全”。这通常是不希望的。
我还使用SQLCLR 的Noda Time进行了调查。您可以在本期中阅读相关内容。由于某些项目在内部缓存的方式,它还必须注册为“不安全”。
最终,对于任何一项,问题是无法在 SQLCLR 中缓存任何内容。您不能以线程安全的方式使用静态变量,也不能进行任何线程同步或使用ConcurrentDictionary
. SQL 希望完全控制程序集的线程模型。只有单线程一次性使用风格的代码才能在“安全”程序集中工作。我在这个问题中深入研究了这个问题: SQL CLR 中的多线程缓存
希望最终会有一个可以在 SQLCLR 中运行的 Noda Time 构建,但它将是一个不做任何缓存的特殊构建。所以它的执行速度不会那么快,但它会在安全的情况下完成工作。
TimeZoneInfo
不太可能改变。因此,除非 SQL Server 团队曾经正确地将时区函数直接引入 SQL Server(如 Oracle 和 Postgres 那样),否则您只有几个选择:
不要尝试在数据层中进行时区转换。使用UTC 中的datetime
or值,或使用具有任何偏移量的值。但是在应用层做所有时区之间的转换。这是我目前最好的建议。datetime2
datetimeoffset
将时区的所有数据复制到实际的 SQL 表中,并编写处理该数据的函数。这不是最好的主意,因为数据经常变化,所以表维护可能是一个挑战。此外,获得准确的功能,包括夏令时更改的所有规则,可能具有挑战性。我不知道有任何项目将这个捆绑得很好,很整洁,但如果有人是 - 请在评论中告诉我。
xp_regread
直接从 Windows 注册表项启用和使用时区数据。将为您完成更新,但您在编写这些函数时仍然面临同样的挑战。并且启用注册表读取可能与启用不安全的 CLR 程序集一样存在安全风险。
我正在考虑的另一个想法是专门为 SQL Server编写IANA/Olson TZDB解析器和函数。这将类似于上面的选项 2,但以可维护的方式完成,并且使用 IANA 标准数据而不是 Windows 时区。也许有一天我会做到这一点,或者也许有人会打败我。同样,我不知道当前有任何这样做的项目,但如果有人知道,请在评论中告诉我。(完成 - 请参阅顶部的更新)
关于SWITCHOFFSET
-仅当您已经知道目标偏移量时才有效。这已经成功了一半,这可能也是为什么微软在文档datetimeoffset
中仍然标记为“不知道夏令时”的原因。