对于 DST 之前或之后的日期,如何获得 UTC 和本地时间之间的正确偏移量?

Rac*_*hel 33 sql-server-2005 sql-server utc-time timezone

我目前使用以下方法从 UTC 日期时间获取本地日期时间:

SET @offset = DateDiff(minute, GetUTCDate(), GetDate())
SET @localDateTime = DateAdd(minute, @offset, @utcDateTime)
Run Code Online (Sandbox Code Playgroud)

我的问题是,如果夏令时发生在GetUTCDate()和之间@utcDateTime@localDateTime最终会休息一个小时。

是否有一种简单的方法可以将非当前日期的日期从 UTC 转换为当地时间?

我使用的是 SQL Server 2005

Kev*_*sel 20

在 SQL Server 2016 之前,将非当前 UTC 日期转换为本地时间的最佳方法是使用 Microsoft .Net 公共语言运行时或 CLR。

代码本身很简单;困难的部分通常是让人们相信 CLR 不是纯粹的邪恶或可怕的......

对于众多示例之一,请查看Harsh Chawla 关于该主题的博客文章

不幸的是,除了基于 CLR 的解决方案,在 SQL Server 2016 之前没有任何内置的东西可以处理这种类型的转换。你可以编写一个 T-SQL 函数来做这样的事情,但是你必须自己实现日期更改逻辑,我认为这绝对不容易。


ads*_*dss 17

我已经在 codeplex 上开发并发布了T-SQL Toolbox项目,以帮助任何在 Microsoft SQL Server 中处理日期时间和时区的人。它是开源的,完全免费使用。

除了开箱即用的预填充配置表外,它还使用普通 T-SQL(无 CLR)提供简单的日期时间转换 UDF。它具有完整的 DST(夏令时)支持。

可以在表“DateTimeUtil.Timezone”(在 T-SQL Toolbox 数据库中提供)中找到所有支持的时区的列表。

在您的示例中,您可以使用以下示例:

SELECT [DateTimeUtil].[UDF_ConvertUtcToLocalByTimezoneIdentifier] (
    'W. Europe Standard Time', -- the target local timezone
    '2014-03-30 00:55:00' -- the original UTC datetime you want to convert
)
Run Code Online (Sandbox Code Playgroud)

这将返回转换后的本地日期时间值。

不幸的是,SQL Server 2008 或更高版本支持它只是因为更新的数据类型(DATE、TIME、DATETIME2)。但是由于提供了完整的源代码,您可以通过将它们替换为 DATETIME 来轻松调整表和 UDF。我没有可用于测试的 MSSQL 2005,但它应该也适用于 MSSQL 2005。如有疑问,请告诉我。


小智 13

我总是使用这个 TSQL 命令。

-- the utc value 
declare @utc datetime = '20/11/2014 05:14'

-- the local time

select DATEADD(hh, DATEDIFF(hh, getutcdate(), getdate()), @utc)

-- or if you're concerned about non-whole-hour offsets, use:

SELECT DATEADD(MINUTE, DATEDIFF(MINUTE, GETUTCDATE(), GETDATE()), @utc).
Run Code Online (Sandbox Code Playgroud)

它非常简单并且可以完成工作。

  • 这不起作用,因为您只是确定当前时间是否为 DST,然后比较可能是 DST 的时间。使用上面的示例代码和英国的日期时间目前告诉我应该是上午 6:14,但是 11 月不在夏令时,所以应该是上午 5:14,因为 GMT 和 UTC 重合。 (4认同)

Rac*_*hel 11

我在 StackOverflow 上找到了这个答案,它提供了一个用户定义的函数,它似乎可以准确地翻译日期时间

您唯一需要修改的是@offset顶部的变量,将其设置为运行此函数的 SQL 服务器的时区偏移量。就我而言,我们的 SQL 服务器使用 EST,即 GMT - 5

它并不完美,并且可能不适用于许多情况,例如半小时或 15 分钟的 TZ 偏移量(对于那些我推荐像Kevin 推荐的 CLR 函数的人),但是它对于北部的大多数通用时区工作得很好美国。

CREATE FUNCTION [dbo].[UDTToLocalTime](@UDT AS DATETIME)  
RETURNS DATETIME
AS
BEGIN 
--====================================================
--Set the Timezone Offset (NOT During DST [Daylight Saving Time])
--====================================================
DECLARE @Offset AS SMALLINT
SET @Offset = -5

--====================================================
--Figure out the Offset Datetime
--====================================================
DECLARE @LocalDate AS DATETIME
SET @LocalDate = DATEADD(hh, @Offset, @UDT)

--====================================================
--Figure out the DST Offset for the UDT Datetime
--====================================================
DECLARE @DaylightSavingOffset AS SMALLINT
DECLARE @Year as SMALLINT
DECLARE @DSTStartDate AS DATETIME
DECLARE @DSTEndDate AS DATETIME
--Get Year
SET @Year = YEAR(@LocalDate)

--Get First Possible DST StartDay
IF (@Year > 2006) SET @DSTStartDate = CAST(@Year AS CHAR(4)) + '-03-08 02:00:00'
ELSE              SET @DSTStartDate = CAST(@Year AS CHAR(4)) + '-04-01 02:00:00'
--Get DST StartDate 
WHILE (DATENAME(dw, @DSTStartDate) <> 'sunday') SET @DSTStartDate = DATEADD(day, 1,@DSTStartDate)


--Get First Possible DST EndDate
IF (@Year > 2006) SET @DSTEndDate = CAST(@Year AS CHAR(4)) + '-11-01 02:00:00'
ELSE              SET @DSTEndDate = CAST(@Year AS CHAR(4)) + '-10-25 02:00:00'
--Get DST EndDate 
WHILE (DATENAME(dw, @DSTEndDate) <> 'sunday') SET @DSTEndDate = DATEADD(day,1,@DSTEndDate)

--Get DaylightSavingOffset
SET @DaylightSavingOffset = CASE WHEN @LocalDate BETWEEN @DSTStartDate AND @DSTEndDate THEN 1 ELSE 0 END

--====================================================
--Finally add the DST Offset 
--====================================================
RETURN DATEADD(hh, @DaylightSavingOffset, @LocalDate)
END



GO
Run Code Online (Sandbox Code Playgroud)


got*_*tqn 11

对于 SQL Server 2016+,您可以使用AT TIME ZONE。它将自动处理夏令时。