2011-11-04 84 views
3

我有以下查询,其计算今天的午夜值(UTC)的日期时间:获得今天的午夜时间为UTC

SELECT CONVERT(DATE,GETDATE())+(GETDATE()-GETUTCDATE()) 

结果:2011-11-03 19:00:00.000(对于GMT-5 2011年11月4日)

不仅如此,但有时,它返回值这样的:

2011-11-03 19:00:00.003 
2011-11-03 19:00:00.007 
2011-11-03 19:00:00.010 

...,这是错误的!

必须有更好的方法来做到这一点。

回答

3

我已经使用DATEADD和DATEDIFF溶液与GETDATE()和GETUTCDATE(),类似于原来的问题给出的例子回答了这个,但自那以后,我发现了datetimeoffset数据类型added in SQL Server 2008。这存储了日期时间以及时区偏移量。

您如何使用此类型取决于您是否要更改现有数据的数据类型。使用

SELECT CONVERT(datetime, SWITCHOFFSET(CONVERT(datetimeoffset, 
    CONVERT(date, GETDATE())), 
    DATENAME(TzOffset, SYSDATETIMEOFFSET()))) 

你也可以将任何UTC时间为本地时间:如果你不想改变什么,下面的语句将返回一个DateTime类型与午夜当地时间

SELECT CONVERT(datetime, SWITCHOFFSET(CONVERT(datetimeoffset, 
     @myutctime, 
     DATENAME(TzOffset, SYSDATETIMEOFFSET()))) 

只有使用SQL2008及更高版本才能使用datetimeoffset类型。如果您需要在2005年及以下时间进行此操作,则可以使用与原始问题类似的解决方案,但需要进行更改以解决事实:GETDATE() - GETUTCDATE()不是原子操作,并且可能涉及两个时间点之间的毫秒差被执行。

SELECT DATEADD(minute, 
    DATEDIFF(minute, GETUTCDATE(), GETDATE()), 
    CONVERT(datetime, CONVERT(date, GETDATE()))) 

这将需要GETDATE()GETUTCDATE()之间的分钟数,并将其添加到本地午夜时间。不幸的是,如果你给它一个日期,那么你必须从日期转换回日期时间,因为DATEADD不能在几分钟内工作。我建议将其包装到用户定义的函数中,以使其看起来不那么冗长,例如

CREATE FUNCTION dbo.MidnightASUTC(@dt as datetime) 
RETURNS datetime 
AS 
BEGIN 
    RETURN DATEADD(minute, 
     DATEDIFF(minute, GETUTCDATE(), GETDATE()), 
     CONVERT(datetime, CONVERT(date, @dt))) 
END 

SELECT dbo.MidnightAsUTC(GETDATE()) 
+0

您需要在调用DATEDIFF时调用GETDATE()和GETUTCDATE():'DATEDIFF(hour,GETUTCDATE(),GETDATE())'来获得正确的结果,但我尝试了大约100次运行,最少得到正确的时间。 –

+0

糟糕,我扭转了它。我也更改了使用DATEADD(分钟...)的答案,因为小时数方法不会处理与UTC时差1/2小时的国家/地区。 – Richard

+0

我想知道是否存在性能损失与你提出的UDF,它是有意义的,使它成为一个内联TVF,返回1行/ 1列结果的值? –

0

对于像你所描述的一个特定的情景(“今日午夜值(UTC)的日期时间”),方案方式是有道理的,但如果你需要把它扩大到一个不同的问题(今年夏天的UTC时间是什么时候?),您可能需要使用日历表(以解释夏时制等事情)。