UTC时间到本地时区(中部时间)转换MS SQL服务器

时间:2017-09-27 15:22:39

标签: sql sql-server function sql-server-2012 timezone

这个问题是此question的后续问题。 我有一个UTC时间列,我希望转换为当前本地时间(Central Time Zone or America/Chicago)。我尝试使用@Ron Smith的答案中的函数,即[dbo].[fn_UTC_to_DST]函数。

在该函数中,它需要两个参数,例如UTC时间和偏移量。我输入这两个,

SELECT  dbo.fn_UTC_to_DST([time(UTC)],5) as Date
FROM tbl

由于我们处于Day Light Saving时间,因此我使用5作为偏移量。我的输出看起来像这样,

2017-09-27 20:55:00.000
2017-09-27 20:56:00.000
2017-09-27 20:57:00.000
2017-09-27 20:58:00.000
...

应该是(中央时间),

2017-09-27 09:55:00.000
2017-09-27 09:56:00.000
2017-09-27 09:57:00.000
2017-09-27 09:58:00.000
...

所以,我改变了@Ron Smith的功能,

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,-5,dateadd(day,datepart(dw,@SSM)*-1+1,@SSM))  -- Changed from 2 to -5
set @FSN = datename(year,@UTC) + '1107'
set @FSN = dateadd(second,-6,dateadd(hour,2,dateadd(day,datepart(dw,@FSN)*-1+1,@FSN)))  -- changed from 1 to -6 

-- 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

然而,这仍然给出了与上述相同的结果。 1.中央时间应该改变什么? 2.有没有办法在夏令时自动更改为-5,在标准时间内自动更改为-6?

修改

在查看答案和来自#Siyual的reference link之后,我创建了dbo.TZCalendar表,并尝试创建这样的函数(接受一个参数并从参考链接返回日期)< / p>

CREATE FUNCTION dbo.ConvertUTCToLocal
(
  @utc DATETIME
)
RETURNS Datetime
AS BEGIN 
  SELECT UTCToLocal = DATEADD(HOUR, CASE 

  -- within Daylight Savings Time
  WHEN @utc >= UTC_DST_Start AND @utc < UTC_DST_End 
  THEN -5 

  -- within Standard Time
  ELSE -6 END, @utc)

FROM dbo.TZCalendar 
WHERE CONVERT(DATE,@utc) >= [Year] 
  AND CONVERT(DATE,@utc) < DATEADD(YEAR, 1, [Year])
END
GO

这个,不起作用。逻辑似乎适合我,但是,我只需要一个没有SCHEMABINDING的函数(在参考链接中完成)。我怎么能这样做?

2 个答案:

答案 0 :(得分:4)

如果您使用的是SQL Server 2016+(或Azure SQL数据库),则内置于:

SELECT YourInputDatetimeInUTC AT TIME ZONE 'UTC' AT TIME ZONE 'Central Standard Time'

第一个断言您的输入是UTC,第二个断言将其转换为美国中部时间,包括适用时的DST(使用Windows时区标识符)。

但是,既然您说过SQL 2012,我就推荐我的SQL Server Time Zone Support项目,这是一个单一操作并使用IANA标识符:

SELECT Tzdb.UtcToLocal(YourInputDatetimeInUTC, 'America/Chicago')

答案 1 :(得分:0)

链接的答案(Sql Server Specify time in another timezone)可以帮助您完成大部分工作,但为了回答您的其余问题,您必须进行一些修改。

首先,我会创建一个DST日历,因为DST开始日期和结束日期是我们可以计算的:

CREATE TABLE dbo.TZCalendar
(
  Year          Int PRIMARY KEY,
  UTC_DST_Start SMALLDATETIME NOT NULL,
  UTC_DST_End   SMALLDATETIME NOT NULL
);

SET DATEFIRST 7;

;WITH cte(d,p) AS 
(
  -- all the years from 2000 through 50 years after the current year:
  SELECT TOP (YEAR(GETDATE())-2000+51) DATEADD(YEAR,number,'20000101'),
    CASE WHEN number < 7 THEN 1 ELSE 0 END -- year < 2007 = 1, else 0
    FROM [master].dbo.spt_values WHERE [type] = N'P' ORDER BY number
)
INSERT dbo.TZCalendar([Year],UTC_DST_Start,UTC_DST_End)
SELECT Year(d),
 -- First Sunday in April (< 2007) or second Sunday in March (>= 2007):
 DATEADD(HOUR, 7, DATEADD(DAY,(7-DATEPART(WEEKDAY,DATEADD(MONTH,2+p,d))+1)%7
    +(7*ABS(p-1)),DATEADD(MONTH,2+p,d))),
 -- Last Sunday in October (< 2007) or first Sunday in November (>= 2007):
 DATEADD(HOUR, 6, DATEADD(DAY,(7-DATEPART(WEEKDAY,DATEADD(MONTH,10,d))+1)%7
    -(7*p),DATEADD(MONTH,10,d)))
FROM cte
ORDER BY d;

这将生成从2000年到2067年的夏令时(这可以根据您的需要进行扩展)。

接下来,我将创建一个函数,在DATE中取UTC并返回CSTCDT中的值,具体取决于一年中的时间。

Create Function dbo.fnConvertUTCToCT(@UTC DateTime)
Returns DateTime
As Begin
    Declare @Offset Int = 0

    Select  @Offset = Case When @UTC Between UTC_DST_Start And UTC_DST_End Then -5 Else -6 End
    From    dbo.TZCalendar
    Where   Year = Year(@UTC)

    Set @UTC = DateAdd(Hour, @Offset, @UTC)

    Return @UTC
End

然后您可以在指定的任何时间调用该函数并返回CSTCDT转换:

Select   dbo.fnConvertUTCToCT(GetUTCDate())
  

2017-09-27 12:24:26.377