4

我想在 SQL Server 2012 中实现时区转换。但是,TimeZoneInfo 标记有MayLeakOnAbort属性。当调用我定义的 SQL 函数(使用 TimeZoneInfo)时,这会导致运行时错误。

报错如下

System.Security.HostProtectionException:尝试执行 CLR 主机禁止的操作。

受保护的资源(仅在完全信任的情况下可用)是:所有

所需资源是:MayLeakOnAbort

文档提示我可以使用“SafeHandle”来解决此泄漏问题,但我不知道如何。

那么,如何在 SQLCLR 上下文中使用 TimeZoneInfo 类?

跟进:

我在该站点上发现了另一个问题,虽然它处理 SQL 2005,但规定了一个适用于 2012 的操作。但是,此解决方案的某些方面并不令人满意。

4

2 回答 2

6

更新的答案

我已经编写了我在原始答案中谈到的实用程序,您可以在此处找到

此外,从 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 中的datetimeor值,或使用具有任何偏移量的值。但是在应用层做所有时区之间的转换。这是我目前最好的建议。datetime2datetimeoffset

  • 将时区的所有数据复制到实际的 SQL 表中,并编写处理该数据的函数。这不是最好的主意,因为数据经常变化,所以表维护可能是一个挑战。此外,获得准确的功能,包括夏令时更改的所有规则,可能具有挑战性。我不知道有任何项目将这个捆绑得很好,很整洁,但如果有人是 - 请在评论中告诉我。

  • xp_regread直接从 Windows 注册表项启用和使用时区数据。将为您完成更新,但您在编写这些函数时仍然面临同样的挑战。并且启用注册表读取可能与启用不安全的 CLR 程序集一样存在安全风险。

我正在考虑的另一个想法是专门为 SQL Server编写IANA/Olson TZDB解析器和函数。这将类似于上面的选项 2,但以可维护的方式完成,并且使用 IANA 标准数据而不是 Windows 时区。也许有一天我会做到这一点,或者也许有人会打败我。同样,我不知道当前有任何这样做的项目,但如果有人知道,请在评论中告诉我。(完成 - 请参阅顶部的更新

关于SWITCHOFFSET-仅当您已经知道目标偏移量时才有效。这已经成功了一半,这可能也是为什么微软在文档datetimeoffset中仍然标记为“不知道夏令时”的原因。

于 2013-07-10T23:08:56.287 回答
1

我知道问题是如何在 SQLCLR 上下文中使用 TimeZoneInfo,但我想我只是补充一点,虽然 TimeZoneInfo 不受支持(正如@MattJohnson 优雅地写的那样),但 TimeZone 仍然可以使用,而无需使程序集不安全。

于 2014-05-08T23:22:56.243 回答