8

.NET TimeZoneInfo 类很棒,我认为它可以解决我在 SQL 2005 数据库中记录来自多个时区的数据的所有问题。

要将数据库中的 UTC 日期时间转换为任何其他时区,我只需使用 TimeZoneInfo.FindSystemTimeZoneById() 将时区转换为 TimeZoneInfo 类,然后调用 TimeZoneInfo.ConvertTimeFromUtc()。杰出的!我只是从 SQL .NET CLR 调用它!

但是...TimeZoneInfo 具有 MayLeakOnAbort 的主机保护属性。

当我使用 VS 2008 创建 SQL 函数或存储过程时,我什至看不到 system.TimeZoneInfo 类,没关系使用它。我还假设即使我可以以某种方式引用 TimeZoneInfo 类,如果我尝试在 SQL Sever 2005 中注册程序集,我可能会遇到某种安全异常。

帮助!有没有办法从 SQL Server 2005 访问 TimeZoneInfo 类及其所有财富?

注意:我刚刚在第一个答案之后添加了这个警告:

我们在世界各地都有站点。我们需要在数据库中存储本地时间和 UTC 时间,以应对可能需要在站点级别进行趋势分析的事件。一个趋势可能在一年内包含超过 52,000 个数据点,因此,为了提高效率,我不能只在数据库中以 UTC 格式存储时间并转换客户端上的每个数据点。因此,我需要能够在数据库中将任何时区的本地时间与 UTC 时间相互转换。

4

7 回答 7

3

我刚刚在 SQL 2008 数据库上完成了此操作。

首先,我必须将数据库设置为可信赖并验证所有者是否正确。

use [myDB]
go
alter database [myDB] set trustworthy on
go

exec sp_changedbowner 'sa'
go

接下来,我创建了一个 .NET 解决方案

Imports System
Imports System.Data
Imports System.Data.SqlClient
Imports System.Data.SqlTypes
Imports Microsoft.SqlServer.Server
Imports System.Collections.ObjectModel
Imports System.Runtime.InteropServices

Partial Public Class StoredProcedures
    <Microsoft.SqlServer.Server.SqlProcedure()> _
    Public Shared Sub sp_ConvertTime(ByVal UTCTime As DateTime, ByVal ZoneID As String, <Out()> ByRef Output As DateTime)
    Dim sp As SqlPipe = SqlContext.Pipe

    Dim ConvertedTime As DateTime
    Dim tzUTC = TimeZoneInfo.FindSystemTimeZoneById("UTC")
    Dim tzNew = TimeZoneInfo.FindSystemTimeZoneById(ZoneID)

    ConvertedTime = TimeZoneInfo.ConvertTime(UTCTime, tzUTC, tzNew)

    Output = ConvertedTime
    sp.Send(ConvertedTime)

    ConvertedTime = Nothing
    tzUTC = Nothing
    tzNew = Nothing
    sp = Nothing

End Sub
End Class

在部署之前,我将 Permission 级别设置为Unsafe

接下来,我将其部署出来,检查了输出窗口中的构建错误并更正了这些错误。

这是 SQL 测试

DECLARE @UTCTime datetime
DECLARE @ZoneID varchar(21)
DECLARE @NewTime datetime

SET @UTCTime = GETUTCDATE()
SET @ZoneID = 'Central Standard Time'

exec sp_ConvertTime @UTCTime, @ZoneID, @NewTime OUTPUT
select @NewTime AS NewTime
于 2012-09-25T16:02:00.763 回答
1

这是一个解决方案:

  1. 创建一个 CLR 存储过程或 UDF,它包装了 TimeZoneInfo 类的功能。遵循本指南: http: //www.codeproject.com/KB/cs/CLR_Stored_Procedure.aspx
  2. TimeZoneInfo 需要 .NET 3.5。但是,System.Core v3.5 在 Sql Server 2005 中不会通过验证。因此您必须为 System.Core 进行 CREATE ASSEMBLY。查看详细信息:http ://weblogs.asp.net/paulomorgado/archive/2009/06/13/playing-with-sql-server-clr-integration-part-iv-deploying-to-sql-server-2005.aspx

请注意,您需要将 System.Core 注册为 UNSAFE... 所以您的 DBA 可能会遇到问题。

此外,即使您正在部署到 Sql Server 2008(包括 .NET 3.5),您的自定义程序集也必须是 UNSAFE,因为它使用来自 TimeZoneInfo 的不安全方法:http: //social.msdn.microsoft.com/Forums/en /sqlnetfx/thread/d0515862-eb87-4a13-bab4-0e343983823a

我试过这个并收到一条关于 MayLeakOnAbort 的消息。

如果 UNSAFE 在你的环境中是可以的,你应该可以做到。

于 2010-03-18T21:53:33.740 回答
1

我遇到了同样的问题,因为我想在报告服务正在使用的查询中在本地和 UTC 之间进行转换。我经历了似乎与您正在经历的完全相同的斗争。我的解决方案...

我开始编写一个独立的应用程序,该应用程序通过 TimeZoneInfo 对象并将条目写入数据库中的 TimeZoneInfo 表。我存储了开始年和结束年之间每年的所有偏移量(包括夏令时偏移量)(这些是独立应用程序的参数)。

从这个表中,我可以创建一些 sql 函数,这些函数将采用 utc 或本地日期和时区,使用 TimeZoneInfo 查找表来获取一年中正确时间和时区的正确偏移量,并返回转换后的日期时间到 UTC 或本地。

不幸的是,我还没有完成。我必须创建一个 CLR 函数,该函数使用对 SQL Server 安全的库(与 TimeZoneInfo 对象不同)返回系统的当前时区。目前我无法访问我的代码,但我相信我使用了 TimeZone 对象。

http://msdn.microsoft.com/en-us/library/system.timezone_members.aspx

总而言之,我有一个 CLR 函数,它返回系统的时区,该应用程序生成了一个包含 DLS 特定信息的时区查找表,其中包含一系列年份。我用一个存储过程来完成这一切,该过程包含一个时区和一个要转换的日期,并且从那以后它一直运行良好。

我知道这是一项巨大的工作,要做一些看起来很简单的事情,但它以安全的方式完成了工作。

于 2009-03-25T20:31:41.910 回答
1

我不知道您是否可以从 SQL 访问 TimeZoneInfo 类,但通常认为在数据库中坚持使用 UTC 是一种好习惯,客户端将转换为本地时间。

因此,每次写入数据库时​​,都会从本地时间转换为 UTC,每次从数据库中读取时,都会将 UTC 转换为本地时间。

编辑:根据我对问题的理解,我仍然推荐的解决方案是:

1) 将日期以 UTC 格式存储在数据库中。2) 在客户端计算本地时间。

2 可以通过多种方式完成。推荐的方法是在 DataColumn 类 (*) 中将 DateTimeMode 设置为 Local(或 Utc)。如果您需要本地时间的报告,请使用 Local,如果您需要 UTC,请使用 UTC。

(*) 请注意 Visual Studio 中的设计器存在问题,请参阅博客文章:http ://bethmassi.blogspot.com/2006/01/serializing-data-across-time-zones-in.html ,错误报告:http ://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=96118

于 2009-03-05T12:58:51.950 回答
0

您在 Channel9 上查看过这篇文章吗?似乎可以在 CLR 函数中执行您正在寻找的操作……尽管我认为您不会获得想要访问的所有好东西……但这是一个开始。

http://channel9.msdn.com/playground/Sandbox/139123/

该线程上的一张海报提到的问题是,由于 p/invoke,它是一个不安全的程序集。

于 2009-08-22T06:40:01.330 回答
0

我们一直在寻找这个,但一直无法找到一个好的方法来做到这一点。如果我记得不久前看过它,我认为那是在 SQL 2008 中要添加的东西的列表中。

于 2009-03-05T15:35:53.053 回答
0

在与同样的问题斗争多年后,我终于决定为SQL Server Time Zone Support构建一个解决方案。该项目使用标准 IANA 时区,如此处所列

例如:

SELECT Tzdb.UtcToLocal('2015-07-01 00:00:00', 'America/Los_Angeles')

我意识到这并不是所要求的,但我认为它同样可以很好地解决问题

于 2015-04-03T06:04:02.247 回答