今天的午夜时间为UTC

时间:2011-11-04 13:33:03

标签: sql-server sql-server-2008 sql-server-2008-r2

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

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

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

不仅如此,有时还会返回以下值:

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

......,这是错误的!

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

2 个答案:

答案 0 :(得分:3)

我已经使用DATEADD和DATEDIFF与GETDATE()和GETUTCDATE()解决了这个问题,类似于原始问题中给出的示例,但从那时起我发现了datetimeoffset数据类型{{ 3}}。这会存储日期时间以及时区偏移量。

如何使用此类型取决于您是否要更改现有数据的数据类型。如果您不想更改任何内容,以下语句将返回当地时间午夜的日期时间类型:

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

您还可以使用以下方式将任何UTC时间转换为本地时间:

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

datetimeoffset类型仅适用于SQL2008及更高版本。如果您需要使用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())

答案 1 :(得分:0)

对于您所描述的特定场景(“今天的午夜值(UTC)作为日期时间”),程序化方法很有意义,但如果您需要将其扩展到另一个问题(午夜是什么时候)这个夏天的UTC?),您可能想要使用日历表(以解决夏令时等问题)。