.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时间。
答案 0 :(得分: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
在部署之前,我将权限级别设置为不安全。
接下来,我将其部署出来,检查了“输出”窗口中的“构建错误”并更正了这些错误。
这是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
答案 1 :(得分:1)
我不知道您是否可以从SQL访问TimeZoneInfo类,但通常认为在数据库中坚持使用UTC是很好的做法,客户端会在当地时间进行转换。
因此,每次写入数据库时,都会将本地时间转换为UTC,每次从数据库读取时,都会将UTC转换为本地时间。
编辑:根据我对问题的理解,我仍然建议的解决方案是:1)将日期以UTC格式存储在数据库中。 2)计算客户端的本地时间。
2可以通过多种方式完成。建议的方法是在DataColumn类(*)中将DateTimeMode设置为Local(或Utc)。如果您需要本地时间的报告,请使用本地,如果您需要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
答案 2 :(得分:1)
我遇到了同样的问题,因为我想在报告服务正在使用的查询中转换本地和UTC。我经历了与你正在经历的相同的挣扎。我的解决方案......
我开始编写一个独立的应用程序,它通过TimeZoneInfo对象并将条目写入我的数据库中的TimeZoneInfo表。我在开始年份和结束年份之间存储了每年的所有偏移量(包括夏令时偏移量)(这些是独立应用程序的参数)。
从这个表中,我可以创建一些sql函数,这些函数将在utc或local和timezone中取一个日期,使用TimeZoneInfo查找表来获得正确的年份和时区的偏移量,并返回日期时间转换为UTC或本地。
不幸的是,我还没有完成。我不得不创建一个CLR函数,该函数使用一个对SQL Server是安全的库(与TimeZoneInfo对象不同)返回系统的当前时区。我目前无法访问我的代码,但我相信我使用了TimeZone对象。
http://msdn.microsoft.com/en-us/library/system.timezone_members.aspx
总而言之,我有一个CLR函数返回系统的时区,这个应用程序生成一个时区查找表,其中包含多年的DLS特定信息。我用一个存储过程来完成所有这些操作,该存储过程包含一个时区和一个转换日期,并且从那以后它一直很好用。
我知道这是一项巨大的工作,可以做一些看起来非常简单的事情,但它以安全的方式完成了工作。
答案 3 :(得分:1)
这是一个解决方案:
请注意,您需要将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在您的环境中没问题,您应该可以这样做。
答案 4 :(得分:0)
我们一直在寻找这个,但一直没能找到一个好方法。我认为这是在SQL 2008中要添加的内容列表中,如果我记得从一段时间后再看到它。
答案 5 :(得分:0)
您是否在Channel9上查看了这篇文章?似乎在CLR功能中做你正在寻找的东西......虽然我认为你不会得到你想要访问的所有好东西......但这是一个开始。
http://channel9.msdn.com/playground/Sandbox/139123/
问题是该线程中的一个海报提到的是因为p / invoke它是一个不安全的程序集。
答案 6 :(得分:0)
经过多年的同样问题的斗争,我终于决定为SQL Server Time Zone Support建立一个解决方案。该项目使用标准的IANA时区as listed here。
例如:
SELECT Tzdb.UtcToLocal('2015-07-01 00:00:00', 'America/Los_Angeles')
我意识到这并不是完全所要求的内容,但我认为它同样可以很好地解决问题。