将select语句中的Datetime列从UTC转换为本地时间


Answers:


322

您可以在SQL Server 2008或更高版本上执行以下操作:

SELECT CONVERT(datetime, 
               SWITCHOFFSET(CONVERT(datetimeoffset, 
                                    MyTable.UtcColumn), 
                            DATENAME(TzOffset, SYSDATETIMEOFFSET()))) 
       AS ColumnInLocalTime
FROM MyTable

您还可以执行以下操作:

SELECT DATEADD(mi, DATEDIFF(mi, GETUTCDATE(), GETDATE()), MyTable.UtcColumn) 
       AS ColumnInLocalTime
FROM MyTable

无论您做什么,都不要使用-减法日期,因为该操作不是原子操作,而且由于系统日期时间与本地日期时间在不同时间(即非原子方式)之间的竞争状况,您有时会得到不确定的结果。

请注意,此答案未考虑DST。如果要包括DST调整,请同时参阅以下SO问题:

如何在SQL Server中创建夏令时开始和结束功能


38
有没有办法使此帐户节省日光?
史蒂夫

15
我在这里看不到时区的名称,因此不正确。假设您可以通过算术转换为当地时间,真是个坏主意
JonnyRaa 2014年

7
@MichaelGoldshteyn如果您有一个时区偏移量,您仍然不知道时间在哪个逻辑时区中。时区是社会性的事情,政府可以在不同时间点对其进行更改。时区的偏移量在时间/历史记录的不同点可能不同(夏季时间是常见的时间)。您正在通过UTC当前的偏移量来偏移时间...进一步的一点是,这将提供服务器而不是客户端的时区,如果您在其他国家/地区托管,则可能会出现另一个问题。
JonnyRaa 2015年

4
@Niloofar一个简单的答案就是你不应该也不应该。日期时间应始终存储在UTC中(最好基于数据库服务器的时钟,而不是Web服务器,应用程序服务器的时钟,并且绝对不是客户端的时钟)。显示该日期时间是UI层的功能,它负责将日期时间转换为所需的格式(必要时包括时区)。
罗伯特·麦基

11
对于使用sql azure的任何人来说,这种方法将行不通,因为日期/时间函数都返回UTC,因此将GETDATE()与GETUTCDATE()进行比较不会给您任何帮助,并且您的结果与开始时相同。
Brian Surowiec

59

我没有发现这些示例中的任何一个有助于将存储为UTC的日期时间转换为指定时区中的日期时间(不是服务器的时区,因为Azure SQL数据库以UTC运行)。这就是我的处理方式。它不是很优雅,但是很简单,可以在不维护其他表的情况下为您提供正确的答案:

select CONVERT(datetime, SWITCHOFFSET(dateTimeField, DATEPART(TZOFFSET, 
dateTimeField AT TIME ZONE 'Eastern Standard Time')))

4
仅适用于2016,并使用系统注册表。但这是Azure的绝佳解决方案。
Dan Cundy

2
这项功能适用于存储在UTC的天蓝色时间,谢谢大家
Null 2017年

3
以下是可以用于时区的字符串列表:stackoverflow.com/a/7908482/631277
Matt Kemp

1
如果使用SQL 2016和AT TIME ZONE语法,考虑stackoverflow.com/a/44941536/112764你可以- 通过简单地串联多个多个转换一起at time zone <blah>秒。
NateJ

3
这也有点奇怪,但是一些非常基本的测试似乎也可以工作dateTimeField AT TIME ZONE 'UTC' AT TIME ZONE 'Eastern Standard Time'-只是链接AT TIME ZONE语句。(@NateJ上面已经提到了,我现在看到了)
David Mohundro

22

如果您说的是本地日期时间,Eastern Standard Time并且想要从UTC转换为该时间,则在Azure SQL和SQL Server 2016及更高版本中,可以执行以下操作:

SELECT YourUtcColumn AT TIME ZONE 'UTC' AT TIME ZONE 'Eastern Standard Time' AS
       LocalTime
FROM   YourTable

时区名称的完整列表可以在以下位置找到:

SELECT * FROM sys.time_zone_info 

是的,时区命名错误-尽管 Eastern Standard Time考虑到夏令时。


2
时区和偏移量也可以在以下SQL Server中找到:SELECT * FROM sys.time_zone_info
rayzinnz

21

如果您需要服务器位置以外的其他转换,则可以使用以下功能传递标准偏移量并考虑美国夏令时:

-- =============================================
-- Author:      Ron Smith
-- Create date: 2013-10-23
-- Description: Converts UTC to DST
--              based on passed Standard offset
-- =============================================
CREATE FUNCTION [dbo].[fn_UTC_to_DST]
(
    @UTC datetime,
    @StandardOffset int
)
RETURNS datetime
AS
BEGIN

    declare 
        @DST datetime,
        @SSM datetime, -- Second Sunday in March
        @FSN datetime  -- First Sunday in November

    -- get DST Range
    set @SSM = datename(year,@UTC) + '0314' 
    set @SSM = dateadd(hour,2,dateadd(day,datepart(dw,@SSM)*-1+1,@SSM))
    set @FSN = datename(year,@UTC) + '1107'
    set @FSN = dateadd(second,-1,dateadd(hour,2,dateadd(day,datepart(dw,@FSN)*-1+1,@FSN)))

    -- add an hour to @StandardOffset if @UTC is in DST range
    if @UTC between @SSM and @FSN
        set @StandardOffset = @StandardOffset + 1

    -- convert to DST
    set @DST = dateadd(hour,@StandardOffset,@UTC)

    -- return converted datetime
    return @DST

END

GO

2
罗恩·史密斯(Ron Smith),我知道这是一篇过时的文章,但我很好奇硬编码的“ 0314”和“ 1107”在DST范围内的含义。似乎是硬编码的日子,由于DTS而改变。为什么要硬编码为应算的日期,因为日期会根据行进的第二个星期日和11月的第一个星期日在日历上的位置而变化。硬编码的日子将使该编码从根本上有缺陷。
迈克”

2
好问题:)这些是三月的第二个星期日和十一月的第一个星期日的最大日期。以下各行将变量设置为实际日期。
罗恩·史密斯

8

利用新的SQL Server 2016机会:

CREATE FUNCTION ToLocalTime(@dtUtc datetime, @timezoneId nvarchar(256))
RETURNS datetime
AS BEGIN

return @dtUtc AT TIME ZONE 'UTC' AT TIME ZONE @timezoneId

/* -- second way, faster

return SWITCHOFFSET(@dtUtc , DATENAME(tz, @dtUtc AT TIME ZONE @timezoneId))

*/

/* -- third way

declare @dtLocal datetimeoffset
set @dtLocal = @dtUtc AT TIME ZONE @timezoneId
return dateadd(minute, DATEPART (TZoffset, @dtLocal), @dtUtc)

*/

END
GO

但是clr程序的运行速度提高了5倍:'-(

请注意,一个时区的偏移可以更改为冬季或夏季时间。例如

select cast('2017-02-08 09:00:00.000' as datetime) AT TIME ZONE 'Eastern Standard Time'
select cast('2017-08-08 09:00:00.000' as datetime) AT TIME ZONE 'Eastern Standard Time'

结果:

2017-02-08 09:00:00.000 -05:00
2017-08-08 09:00:00.000 -04:00

您不能只添加常量偏移量。


5

如果可以选择在数据库上启用CLR以及使用sql server的时区,则可以很轻松地用.Net编写。

public partial class UserDefinedFunctions
{
    [Microsoft.SqlServer.Server.SqlFunction]
    public static SqlDateTime fn_GetLocalFromUTC(SqlDateTime UTC)
    {
        if (UTC.IsNull)
            return UTC;

        return new SqlDateTime(UTC.Value.ToLocalTime());
    }
}

输入UTC日期时间值,然后显示相对于服务器的本地日期时间值。空值返回空值。


5

没有简单的方法可以以正确且通用的方式执行此操作。

首先必须了解,偏移量取决于相关日期,时区和夏令时。 GetDate()-GetUTCDate仅提供您今天在服务器的TZ处的偏移量,这无关紧要。

我只看到了两个可行的解决方案,并且进行了很多搜索。

1)一个自定义SQL函数,具有一些基础数据表,例如每个TZ的时区​​和DST规则。工作,但不是很优雅。我不拥有代码,因此无法发布。

编辑:这是此方法的示例 https://gist.github.com/drumsta/16b79cee6bc195cd89c8

2)将.net程序集添加到数据库中,.Net可以很容易地做到这一点。这工作得很好,但缺点是您需要在服务器级别配置多个参数,并且配置很容易损坏,例如,如果您还原数据库。我使用此方法,但由于我不拥有代码,因此无法发布。


4

这些都不对我有用,但是下面的这个对100%有效。希望这可以帮助其他尝试像我一样进行转换的人。

CREATE FUNCTION [dbo].[fn_UTC_to_EST]
(
    @UTC datetime,
    @StandardOffset int
)
RETURNS datetime
AS
BEGIN

declare 
    @DST datetime,
    @SSM datetime, -- Second Sunday in March
    @FSN datetime  -- First Sunday in November
-- get DST Range
set @SSM = DATEADD(dd,7 + (6-(DATEDIFF(dd,0,DATEADD(mm,(YEAR(GETDATE())-1900) * 12 + 2,0))%7)),DATEADD(mm,(YEAR(GETDATE())-1900) * 12 + 2,0))+'02:00:00' 
set @FSN = DATEADD(dd, (6-(DATEDIFF(dd,0,DATEADD(mm,(YEAR(GETDATE())-1900) * 12 + 10,0))%7)),DATEADD(mm,(YEAR(GETDATE())-1900) * 12 + 10,0)) +'02:00:00'

-- add an hour to @StandardOffset if @UTC is in DST range
if @UTC between @SSM and @FSN
    set @StandardOffset = @StandardOffset + 1

-- convert to DST
set @DST = dateadd(hour,@StandardOffset,@UTC)

-- return converted datetime
return @DST

END

1
这应该是公认的答案。我唯一要更改的是名称,因为它暗示着它是EST时间,而实际上是当地时间,并且StandardOffset作为参数传递。
格雷格·古姆

同意,最好的答案...但是我不必将偏移量作为参数传递,而是在函数体内添加了它:declare @StandardOffset int = datediff (hh, GETUTCDATE(), GETDATE())
Tom Warfield

遵循我之前的建议-如果您计算@StandardOffset,则无需进行DST校正。
汤姆·沃菲尔德

3

这是一个说明夏令时,UTC偏移量且未锁定到特定年份的版本。

---------------------------------------------------------------------------------------------------
--Name:     udfToLocalTime.sql
--Purpose:  To convert UTC to local US time accounting for DST
--Author:   Patrick Slesicki
--Date:     3/25/2014
--Notes:    Works on SQL Server 2008R2 and later, maybe SQL Server 2008 as well.
--          Good only for US States observing the Energy Policy Act of 2005.
--          Function doesn't apply for years prior to 2007.
--          Function assumes that the 1st day of the week is Sunday.
--Tests:        
--          SELECT dbo.udfToLocalTime('2014-03-09 9:00', DEFAULT)
--          SELECT dbo.udfToLocalTime('2014-03-09 10:00', DEFAULT)
--          SELECT dbo.udfToLocalTime('2014-11-02 8:00', DEFAULT)
--          SELECT dbo.udfToLocalTime('2014-11-02 9:00', DEFAULT)
---------------------------------------------------------------------------------------------------
ALTER FUNCTION udfToLocalTime
    (
    @UtcDateTime    AS DATETIME
    ,@UtcOffset     AS INT = -8 --PST
    )
RETURNS DATETIME
AS 
BEGIN
    DECLARE 
        @PstDateTime    AS DATETIME
        ,@Year          AS CHAR(4)
        ,@DstStart      AS DATETIME
        ,@DstEnd        AS DATETIME
        ,@Mar1          AS DATETIME
        ,@Nov1          AS DATETIME
        ,@MarTime       AS TIME
        ,@NovTime       AS TIME
        ,@Mar1Day       AS INT
        ,@Nov1Day       AS INT
        ,@MarDiff       AS INT
        ,@NovDiff       AS INT

    SELECT
        @Year       = YEAR(@UtcDateTime)
        ,@MarTime   = CONVERT(TIME, DATEADD(HOUR, -@UtcOffset, '1900-01-01 02:00'))
        ,@NovTime   = CONVERT(TIME, DATEADD(HOUR, -@UtcOffset - 1, '1900-01-01 02:00'))
        ,@Mar1      = CONVERT(CHAR(16), @Year + '-03-01 ' + CONVERT(CHAR(5), @MarTime), 126)
        ,@Nov1      = CONVERT(CHAR(16), @Year + '-11-01 ' + CONVERT(CHAR(5), @NovTime), 126)
        ,@Mar1Day   = DATEPART(WEEKDAY, @Mar1)
        ,@Nov1Day   = DATEPART(WEEKDAY, @Nov1)

    --Get number of days between Mar 1 and DST start date
    IF @Mar1Day = 1 SET @MarDiff = 7
    ELSE SET @MarDiff = 15 - @Mar1Day

    --Get number of days between Nov 1 and DST end date
    IF @Nov1Day = 1 SET @NovDiff = 0
    ELSE SET @NovDiff = 8 - @Nov1Day

    --Get DST start and end dates
    SELECT 
        @DstStart   = DATEADD(DAY, @MarDiff, @Mar1)
        ,@DstEnd    = DATEADD(DAY, @NovDiff, @Nov1)

    --Change UTC offset if @UtcDateTime is in DST Range
    IF @UtcDateTime >= @DstStart AND @UtcDateTime < @DstEnd SET @UtcOffset = @UtcOffset + 1

    --Get Conversion
    SET @PstDateTime = DATEADD(HOUR, @UtcOffset, @UtcDateTime)
    RETURN @PstDateTime
END
GO

3

我发现在有大量数据时,单功能功能方法太慢。因此,我通过加入可以计算时差的表函数来完成此操作。基本上是带时差的日期时间段。一年将是4行。所以表功能

dbo.fn_getTimeZoneOffsets('3/1/2007 7:00am', '11/5/2007 9:00am', 'EPT')

将返回此表:

startTime          endTime   offset  isHr2
3/1/07 7:00     3/11/07 6:59    -5    0
3/11/07 7:00    11/4/07 6:59    -4    0
11/4/07 7:00    11/4/07 7:59    -5    1
11/4/07 8:00    11/5/07 9:00    -5    0

它确实说明了夏时制。下面是有关其用法的示例,完整的博客文章在此处

select mt.startTime as startUTC, 
    dateadd(hh, tzStart.offset, mt.startTime) as startLocal, 
    tzStart.isHr2
from MyTable mt 
inner join dbo.fn_getTimeZoneOffsets(@startViewUTC, @endViewUTC, @timeZone)  tzStart
on mt.startTime between tzStart.startTime and tzStart.endTime

似乎没有以正确的方式考虑DST。不知道您是否假设只有美国存在并且DST规则永远不会改变。
vikjon0

@ vikjon0是的,我为此构建的项目只有美国时区。
JBrooks

2
 declare @mydate2 datetime
 set @mydate2=Getdate()
 select @mydate2 as mydate,
 dateadd(minute, datediff(minute,getdate(),@mydate2),getutcdate())

1

罗恩的答案有误。它使用当地时间2:00 AM(需要UTC等效时间)。我没有足够的声誉积分来评论罗恩的答案,所以下面显示了一个更正的版本:

-- =============================================
-- Author:      Ron Smith
-- Create date: 2013-10-23
-- Description: Converts UTC to DST
--              based on passed Standard offset
-- =============================================
CREATE FUNCTION [dbo].[fn_UTC_to_DST]
(
    @UTC datetime,
    @StandardOffset int
)
RETURNS datetime
AS
BEGIN

declare 
    @DST datetime,
    @SSM datetime, -- Second Sunday in March
    @FSN datetime  -- First Sunday in November
-- get DST Range
set @SSM = datename(year,@UTC) + '0314' 
set @SSM = dateadd(hour,2 - @StandardOffset,dateadd(day,datepart(dw,@SSM)*-1+1,@SSM))
set @FSN = datename(year,@UTC) + '1107'
set @FSN = dateadd(second,-1,dateadd(hour,2 - (@StandardOffset + 1),dateadd(day,datepart(dw,@FSN)*-1+1,@FSN)))

-- add an hour to @StandardOffset if @UTC is in DST range
if @UTC between @SSM and @FSN
    set @StandardOffset = @StandardOffset + 1

-- convert to DST
set @DST = dateadd(hour,@StandardOffset,@UTC)

-- return converted datetime
return @DST

END

这是一个功能,而不是错误:)美国大部分地区在夏令时开始于2:00 am en.wikipedia.org/wiki/Daylight_saving_time
罗恩·史密斯

@RonSmith是的,在当地时间凌晨2:00,我们必须将其转换为UTC以检测给定的UTC时间是否在DST范围内。
jlspublic


1

这很简单。对于Azure SQL Server,请尝试以下操作:

SELECT YourDateTimeColumn AT TIME ZONE 'Eastern Standard Time' FROM YourTable

对于本地SQL Server:

SELECT CONVERT(datetime2, SWITCHOFFSET(CONVERT(datetimeoffset, gETDATE()), DATENAME(TzOffset, gETDATE() AT TIME ZONE 'Eastern Standard Time'))) FROM YourTable

1
在夏时制期间(由于时区专门显示“东部标准时间”)会发生什么?
标记

1

对于Azure SQL和@@Version> = SQL Server 2016用户,以下是使用的简单功能AT TIME ZONE

CREATE FUNCTION [dbo].[Global_Convert_UTCTimeTo_LocalTime]
(
   @LocalTimeZone        VARCHAR(50),
   @UTCDateTime          DATETIME
)
RETURNS DATETIME
AS
BEGIN
   DECLARE @ConvertedDateTime DATETIME;

   SELECT @ConvertedDateTime = @UTCDateTime AT TIME ZONE 'UTC' AT TIME ZONE @LocalTimeZone
   RETURN @ConvertedDateTime

END
GO

有关@LocalTimeZone可以采用的值类型,请转到此链接或转到KEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones


0

作为警告-如果您要使用以下内容(请注意,以毫秒为单位,而不是分钟):

    SELECT DATEADD(ms, DATEDIFF(ms, GETUTCDATE(), GETDATE()), MyTable.UtcColumn) 
    AS ColumnInLocalTime
    FROM MyTable

请记住,DATEDIFF部分不会总是返回相同的数字。因此,请勿使用它来比较DateTimes到毫秒。


0

我发现此功能比使用单独的表或循环的其他解决方案要快。这只是一个基本的案例陈述。鉴于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

0

这应该能够通过DST获得服务器时间

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

sysdatetimeoffset将DST考虑在内

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

0

第一个功能:配置为意大利时区(+ 1,+ 2),切换日期:3月和10月的最后一个星期日,返回当前时区和datetime之间的时差作为参数。

Returns:
current timezone < parameter timezone ==> +1
current timezone > parameter timezone ==> -1
else 0

代码是:

CREATE FUNCTION [dbo].[UF_ADJUST_OFFSET]
(
    @dt_utc datetime2(7)
)
RETURNS INT
AS
BEGIN


declare @month int,
        @year int,
        @current_offset int,
        @offset_since int,
        @offset int,
        @yearmonth varchar(8),
        @changeoffsetdate datetime2(7)

declare @lastweek table(giorno datetime2(7))

select @current_offset = DATEDIFF(hh, GETUTCDATE(), GETDATE())

select @month = datepart(month, @dt_utc)

if @month < 3 or @month > 10 Begin Set @offset_since = 1 Goto JMP End

if @month > 3 and @month < 10 Begin Set @offset_since = 2 Goto JMP End

--If i'm here is march or october
select @year = datepart(yyyy, @dt_utc)

if @month = 3
Begin

Set @yearmonth = cast(@year as varchar) + '-03-'

Insert Into @lastweek Values(@yearmonth + '31 03:00:00.000000'),(@yearmonth + '30 03:00:00.000000'),(@yearmonth + '29 03:00:00.000000'),(@yearmonth + '28 03:00:00.000000'),
                         (@yearmonth + '27 03:00:00.000000'),(@yearmonth + '26 03:00:00.000000'),(@yearmonth + '25 03:00:00.000000')

--Last week of march
Select @changeoffsetdate = giorno From @lastweek Where  datepart(weekday, giorno) = 1

    if @dt_utc < @changeoffsetdate 
    Begin 
        Set @offset_since = 1 
    End Else Begin
        Set @offset_since = 2
    End
End

if @month = 10
Begin

Set @yearmonth = cast(@year as varchar) + '-10-'

Insert Into @lastweek Values(@yearmonth + '31 03:00:00.000000'),(@yearmonth + '30 03:00:00.000000'),(@yearmonth + '29 03:00:00.000000'),(@yearmonth + '28 03:00:00.000000'),
                         (@yearmonth + '27 03:00:00.000000'),(@yearmonth + '26 03:00:00.000000'),(@yearmonth + '25 03:00:00.000000')

--Last week of october
Select @changeoffsetdate = giorno From @lastweek Where  datepart(weekday, giorno) = 1

    if @dt_utc > @changeoffsetdate 
    Begin 
        Set @offset_since = 1 
    End Else Begin
        Set @offset_since = 2
    End
End

JMP:

if @current_offset < @offset_since Begin
    Set @offset = 1
End Else if @current_offset > @offset_since Set @offset = -1 Else Set @offset = 0

Return @offset

END

然后转换日期的功能

CREATE FUNCTION [dbo].[UF_CONVERT]
(
    @dt_utc datetime2(7)
)
RETURNS datetime
AS
BEGIN

    declare @offset int


    Select @offset = dbo.UF_ADJUST_OFFSET(@dt_utc)

    if @dt_utc >= '9999-12-31 22:59:59.9999999'
        set @dt_utc = '9999-12-31 23:59:59.9999999'
    Else
        set @dt_utc = (SELECT DATEADD(mi, DATEDIFF(mi, GETUTCDATE(), GETDATE()), @dt_utc) )

    if @offset <> 0
        Set @dt_utc = dateadd(hh, @offset, @dt_utc)

    RETURN @dt_utc

END


0

这可以在没有功能的情况下完成。下面的代码将把夏令时转换为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

0

您必须重新格式化字符串以及转换为正确的时间。在这种情况下,我需要祖鲁时间。

Declare @Date datetime;
Declare @DateString varchar(50);
set @Date = GETDATE(); 
declare @ZuluTime datetime;

Declare @DateFrom varchar (50);
Declare @DateTo varchar (50);
set @ZuluTime = DATEADD(second, DATEDIFF(second, GETDATE(), GETUTCDATE()), @Date);
set @DateString =  FORMAT(@ZuluTime, 'yyyy-MM-ddThh:mm:ssZ', 'en-US' )  
select @DateString;

0

甲骨文的最佳方法:

使用硬编码的日期时间:

SELECT TO_CHAR(CAST((FROM_TZ(CAST(TO_DATE('2018-10-27 21:00', 'YYYY-MM-DD HH24:MI') AS TIMESTAMP), 'UTC') AT  TIME ZONE 'EET') AS DATE), 'YYYY-MM-DD HH24:MI') UTC_TO_EET FROM DUAL

Result: 2018-10-28 00:00

具有列名和表名:

SELECT TO_CHAR(CAST((FROM_TZ(CAST(COLUMN_NAME AS TIMESTAMP), 'UTC') AT  TIME ZONE 'EET') AS DATE), 'YYYY-MM-DD HH24:MI') UTC_TO_EET FROM TABLE_NAME

0

我有执行UTC到本地和本地到UTC时间的代码,这允许使用这样的代码进行转换

DECLARE @usersTimezone VARCHAR(32)='Europe/London'
DECLARE @utcDT DATETIME=GetUTCDate()
DECLARE @userDT DATETIME=[dbo].[funcUTCtoLocal](@utcDT, @usersTimezone)

DECLARE @usersTimezone VARCHAR(32)='Europe/London'
DECLARE @userDT DATETIME=GetDate()
DECLARE @utcDT DATETIME=[dbo].[funcLocaltoUTC](@userDT, @usersTimezone)

这些功能可以支持NodaTime提供的IANA / TZDB中的全部或部分时区-请参阅https://nodatime.org/TimeZones上的完整列表

请注意,我的用例意味着我只需要一个“当前”窗口,就可以从现在开始在大约+/- 5年的范围内转换时间。这意味着如果您需要很长的时间,我使用的方法可能不适合您,因为它会在给定日期范围内为每个时区间隔生成代码。

该项目位于GitHub上:https : //github.com/elliveny/SQLServerTimeConversion

这将根据此示例生成SQL函数代码


0

好吧,如果您将数据以UTC日期存储在数据库中,则可以执行以下操作:

select 
 [MyUtcDate] + getdate() - getutcdate()
from [dbo].[mytable]

从服务器的角度来看,这始终是本地的,并且您不会对AT感到困惑TIME ZONE 'your time zone name',如果您的数据库被移至另一个时区(如客户端安装),则硬编码的时区可能会给您带来麻烦。



-1

这是将dst考虑在内的更简单的方法

CREATE FUNCTION [dbo].[UtcToLocal] 
(
    @p_utcDatetime DATETIME 
)
RETURNS DATETIME
AS
BEGIN
    RETURN DATEADD(MINUTE, DATEDIFF(MINUTE, GETUTCDATE(), @p_utcDatetime), GETDATE())
END

6
这实际上并没有考虑DST。尝试一下:SELECT DATEADD(MINUTE, DATEDIFF(MINUTE, GETUTCDATE(), '20150101'), GETDATE())。我目前处于CEST(UTC + 2),但是DST不会在元旦生效,因此正确的答案是2015年1月1日01:00。您的答案与接受的答案一样,返回2015年1月1日02:00。
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.