2009-03-05 98 views
8

.NET TimeZoneInfo类很棒,我认为它会回答我在SQL 2005数据库中记录来自多个时区的数据时遇到的所有问题。从SQL 2005服务器访问TimeZoneInfo

要将数据库中的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时间和从UTC时间转换的能力。

+0

你实际存储在数据库中的是什么?您是否存储了这样的事实,即该数据是在'法国下午3点'录制的,或者您是否存储了在UTC时间下午2点录制的事实?如果是前者,则可以将本地时间偏移量存储在另一列中 – 2009-03-05 16:12:02

+0

我需要记录UTC和本地时间。网站报告通常需要在本地时间,全球范围的报告将以UTC时间请求。无论如何,我仍然需要在数据库级别确定本地偏移量或时间是什么!输入用户可能在任何时区。 – user74207 2009-03-05 23:57:45

回答

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

+0

谢谢M, 虽然不好。我需要在数据库中存储UTC和本地时间。 我们遍布世界各地。网站报告默认情况下需要在当地时间。一年的趋势可能是52,000个数据点。我无法在客户端上处理52,000个日期!我需要从UTC转换为本地数据库。 – user74207 2009-03-05 15:19:14

+0

当地时间在哪里?报告运行的当地时间,或收集数据的当地时间? – 2009-03-05 16:14:48

0

我们一直在寻找这一段时间,但一直没能找到一个好办法做到这一点。我认为这是SQL 2008中添加的事情的列表,如果我记得从前看过它的话。

1

我遇到了同样的问题,因为我想在报表服务正在使用的查询中在本地和UTC之间进行转换。我经历了与你正在经历的同样的挣扎。我的解决方案...

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

从这张表中,我可以创建一些sql函数,这些函数会以utc或本地和时区作为日期,使用TimeZoneInfo查找表获得适合年份和时区的正确偏移量,以及返回转换为UTC或本地的日期时间。

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

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

总之,我只好返回的系统时区,即产生了时区查找表与年份范围DLS特定信息的应用程序一个CLR函数。我使用一个存储过程来完成所有工作,这个存储过程包含了一个时区和一个转换日期,并且从那以后它的工作非常好。

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

0

你看过Channel9上的这篇文章吗?似乎在CLR功能中做你正在寻找的东西......虽然我不认为你会得到你想要访问的所有好东西......但这是一个开始。

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

问题,即在该线程的海报一个提到虽然是,它是因为在p的/调用一个不安全的组件。

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),您的自定义组件必须是不安全的,因为它使用不安全的方法从的TimeZoneInfo: http://social.msdn.microsoft.com/Forums/en/sqlnetfx/thread/d0515862-eb87-4a13-bab4-0e343983823a

我尝试这样做,得到了关于MayLeakOnAbort的消息。

如果在您的环境中UNSAFE没问题,您应该可以做到。

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 
0

同样的问题争取多年之后,我终于决定建立SQL Server Time Zone Support的解决方案。该项目使用标准IANA时区as listed here

例如:

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

我意识到这是不准确什么有人问,但我认为它会解决这个问题同样出色。