我正在做一些SQL选择查询,并希望将我的UTC日期时间列转换为本地时间,以便在我的查询结果中显示为本地时间。注意,我不希望通过代码进行这种转换,而是当我对我的数据库进行手动和随机SQL查询时。


当前回答

UNIX时间戳只是一个特定日期和UNIX纪元之间的秒数,

SELECT DATEDIFF(SECOND,{d '1970-01-01'},GETDATE()) //返回SQL server中的UNIX时间戳

你可以创建一个函数,使用Country Offset将本地日期时间转换为Unix UTC SQL server中的Unix时间戳函数

其他回答

这样就可以获得与夏令时同步的服务器时间

declare @dt datetime
set @dt = getutcdate() -- GMT equivalent

sysdatetimeoffset会考虑夏令时

select [InputTime] = @dt
       , [LocalTime2] = dateadd(mi, datediff(mi, sysdatetimeoffset(),getdate()), @dt) 

最简单的答案并不总是在底部,但这一次是,并且可以在上面的评论中看到。 使用您自己的“AT TIME ZONE”来捕获列/数据字段的TzOffset,而不是当前的SYSDATETIME。 在下面的数据中,2个查询,一个关于feb数据(DST是关闭的,在阿姆斯特丹的冬天)+1差异 第二次查询阿姆斯特丹4月份的数据,所以+2小时的差异。

    select top 2 month(receiveTimeUTC) as MonthInWinterOrSpring
   ,  receiveTimeUTC
   ,  CONVERT(datetime,  SWITCHOFFSET(CONVERT(datetimeoffset,  receiveTimeUTC),  DATENAME(TzOffset, SYSDATETIMEOFFSET()))) as LocalTimeWrongNoDST
   ,  CONVERT(datetime,  SWITCHOFFSET(CONVERT(datetimeoffset,  receiveTimeUTC),  DATENAME(TzOffset, receiveTimeUTC  AT TIME ZONE 'Central European Standard Time' ))) as LocalTimeWithDST
       from sensordetails order by id

    select top 2 month(receiveTimeUTC) as MonthInWinterOrSpring, receiveTimeUTC
,  CONVERT(datetime,  SWITCHOFFSET(CONVERT(datetimeoffset,  receiveTimeUTC),  DATENAME(TzOffset, SYSDATETIMEOFFSET()))) as LocalTimeWrongNoDST
,  CONVERT(datetime,  SWITCHOFFSET(CONVERT(datetimeoffset,  receiveTimeUTC),  DATENAME(TzOffset, receiveTimeUTC  AT TIME ZONE 'Central European Standard Time' ))) as LocalTimeWithDST
       from sensordetails order by id desc

结果:

所以这是一个T-SQL (SQL Server Answer),不需要函数的storedproc。

这可以在没有函数的情况下完成。下面的代码将把UTC时间转换为考虑夏令时的山地时间。相应地调整所有的-6和-7数字到您的时区(即对于EST,您将分别调整为-4和-5)

--Adjust a UTC value, in the example the UTC field is identified as UTC.Field, to account for daylight savings time when converting out of UTC to Mountain time.
CASE
    --When it's between March and November, it is summer time which is -6 from UTC
    WHEN MONTH ( UTC.Field ) > 3 AND MONTH ( UTC.Field ) < 11 
        THEN DATEADD ( HOUR , -6 , UTC.Field )
    --When its March and the day is greater than the 14, you know it's summer (-6)
    WHEN MONTH ( UTC.Field ) = 3
        AND DATEPART ( DAY , UTC.Field ) >= 14 
        THEN
            --However, if UTC is before 9am on that Sunday, then it's before 2am Mountain which means it's still Winter daylight time.
            CASE 
                WHEN DATEPART ( WEEKDAY , UTC.Field ) = 1 
                    AND UTC.Field < '9:00'
                    --Before 2am mountain time so it's winter, -7 hours for Winter daylight time
                    THEN DATEADD ( HOUR , -7 , UTC.Field )
                --Otherwise -6 because it'll be after 2am making it Summer daylight time
                ELSE DATEADD ( HOUR , -6 , UTC.Field )
            END
    WHEN MONTH ( UTC.Field ) = 3
        AND ( DATEPART ( WEEKDAY , UTC.Field ) + 7 ) <= DATEPART ( day , UTC.Field ) 
        THEN 
            --According to the date, it's moved onto Summer daylight, but we need to account for the hours leading up to 2am if it's Sunday
            CASE 
                WHEN DATEPART ( WEEKDAY , UTC.Field ) = 1 
                    AND UTC.Field < '9:00'
                    --Before 9am UTC is before 2am Mountain so it's winter Daylight, -7 hours
                    THEN DATEADD ( HOUR , -7 , UTC.Field )
                --Otherwise, it's summer daylight, -6 hours
                ELSE DATEADD ( HOUR , -6 , UTC.Field )
            END
    --When it's November and the weekday is greater than the calendar date, it's still Summer so -6 from the time
    WHEN MONTH ( UTC.Field ) = 11
        AND DATEPART ( WEEKDAY , UTC.Field ) > DATEPART ( DAY , UTC.Field ) 
        THEN DATEADD ( HOUR , -6 , UTC.Field )
    WHEN MONTH ( UTC.Field ) = 11
        AND DATEPART ( WEEKDAY , UTC.Field ) <= DATEPART ( DAY , UTC.Field ) 
            --If the weekday is less than or equal to the calendar day it's Winter daylight but we need to account for the hours leading up to 2am.
            CASE 
                WHEN DATEPART ( WEEKDAY , UTC.Field ) = 1 
                    AND UTC.Field < '8:00'
                    --If it's before 8am UTC and it's Sunday in the logic outlined, then it's still Summer daylight, -6 hours
                    THEN DATEADD ( HOUR , -6 , UTC.Field )
                --Otherwise, adjust for Winter daylight at -7
                ELSE DATEADD ( HOUR , -7 , UTC.Field )
            END
    --If the date doesn't fall into any of the above logic, it's Winter daylight, -7
    ELSE
        DATEADD ( HOUR , -7 , UTC.Field )
END

我发现这个函数比使用单独的表或循环的其他解决方案更快。这只是一个基本的case语句。考虑到4月到10月之间的所有月份都有-4小时的偏移(东部时间),我们只需要为边缘日添加更多的案例线。否则,偏移量为-5小时。

这是特定于从UTC到东部时间的转换,但可以根据需要添加其他时区功能。

USE [YourDatabaseName]
GO

/****** Object:  UserDefinedFunction [dbo].[ConvertUTCtoEastern]    Script Date: 11/2/2016 5:21:52 PM ******/
SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO


CREATE FUNCTION [dbo].[ConvertUTCtoEastern]
(
@dtStartDate DATETIME
)
RETURNS DATETIME
AS
BEGIN
DECLARE @Working DATETIME
DECLARE @Returned DATETIME

SET @Working = @dtStartDate
SET @Working = 
case when month(@Working) between 4 and 10 then dateadd(HH,-4,@Working) 
     when @Working between '2017-03-12' and '2017-11-05' then dateadd(HH,-4,@Working) 
     when @Working between '2016-03-13' and '2016-11-06' then dateadd(HH,-4,@Working) 
     when @Working between '2015-03-08' and '2015-11-01' then dateadd(HH,-4,@Working) 
     when @Working between '2014-03-09' and '2014-11-02' then dateadd(HH,-4,@Working) 
     when @Working between '2013-03-10' and '2013-11-03' then dateadd(HH,-4,@Working) 
     when @Working between '2012-03-11' and '2012-11-04' then dateadd(HH,-4,@Working) 
else dateadd(HH,-5,@Working) end

SET @Returned = @Working

RETURN @Returned

END


GO

UNIX时间戳只是一个特定日期和UNIX纪元之间的秒数,

SELECT DATEDIFF(SECOND,{d '1970-01-01'},GETDATE()) //返回SQL server中的UNIX时间戳

你可以创建一个函数,使用Country Offset将本地日期时间转换为Unix UTC SQL server中的Unix时间戳函数