sql-server - 需要一个 SQL Server 函数将本地日期时间转换为支持 DST 的 UTC

标签 sql-server timezone azure-sql-database utc dst

我们正在将应用程序迁移到 Azure,但目前所有日期都存储为东部标准时间。由于 SQL Azure 采用 UTC,并且我们的许多日期都是通过 getdate() 调用生成的,因此如果我们保留所有内容,就会出现问题。看来,最不令人头痛的选项是将我们存储的所有日期转换为 UTC,并在前端将它们转换为本地时间。

不幸的是,似乎没有一种内置方法可以将 SQL 日期时间从一个时区转换为另一个时区,而且我发现的许多解决方案都没有考虑夏令时。我发现确实考虑 DST 的解决方案涉及导入日历和时区表,并且非常复杂。

我只是在寻找适合单次转换的东西,而且它不一定很漂亮。有什么想法吗?

更新:我编写了以下函数,我相信它可以完成我的需要。有人看到这个有什么漏洞吗?我的所有日​​期目前均为东部标准时间,但我的日期从 2002 年左右开始,因此我必须处理 2007 年的法律变更。

我想我会像这样使用这个函数:

UPDATE myTable SET myDate = dbo.fnESTtoUTC(myDate)

这是函数:

CREATE FUNCTION [dbo].[fnESTtoUTC]
    (@pESTDate  DATETIME)
    RETURNS DATETIME
AS
BEGIN

DECLARE @TimeZoneOffset INT
DECLARE @Year INT
DECLARE @Day INT
DECLARE @DSTStart DATETIME
DECLARE @DSTEnd DATETIME

SELECT @Year = DATEPART(year, @pESTDate)

IF @Year >= 2007
BEGIN
    SELECT @Day = 8
    WHILE @DSTStart IS NULL
    BEGIN
        -- Second Sunday in March
        IF DATEPART(weekday, DATEFROMPARTS(@Year, 3, @Day)) = 1
            SELECT @DSTStart = DATETIMEFROMPARTS(@Year, 3, @Day, 2, 0, 0, 0)
        SELECT @Day = @Day + 1
    END

    SELECT @Day = 1
    WHILE @DSTEnd IS NULL
    BEGIN
        -- First Sunday in November
        IF DATEPART(weekday, DATEFROMPARTS(@Year, 11, @Day)) = 1
            SELECT @DSTEnd = DATETIMEFROMPARTS(@Year, 11, @Day, 1, 0, 0, 0)
        SELECT @Day = @Day + 1
    END
END
ELSE
BEGIN
    SELECT @Day = 1
    WHILE @DSTStart IS NULL
    BEGIN
        -- First Sunday in April
        IF DATEPART(weekday, DATEFROMPARTS(@Year, 4, @Day)) = 1
            SELECT @DSTStart = DATETIMEFROMPARTS(@Year, 4, @Day, 2, 0, 0, 0)
        SELECT @Day = @Day + 1
    END

    SELECT @Day = 31
    WHILE @DSTEnd IS NULL
    BEGIN
        -- Last Sunday in October
        IF DATEPART(weekday, DATEFROMPARTS(@Year, 10, @Day)) = 1
            SELECT @DSTEnd = DATETIMEFROMPARTS(@Year, 10, @Day, 1, 0, 0, 0)
        SELECT @Day = @Day - 1
    END
END

IF @pESTDate >= @DSTStart AND @pESTDate < @DSTEnd
BEGIN
    -- Date is in DST
    SELECT @TimeZoneOffset = 4
END
ELSE
BEGIN
    -- Not DST
    SELECT @TimeZoneOffset = 5
END

RETURN ( dateadd(hh, @TimeZoneOffset, @pESTDate) )
END

最佳答案

有几个问题:

  • 您将根据当前日期而不是输入中提供的日期来使用哪个规则。您确实应该更改它。

  • 如果我传递诸如 2013-03-10 02:30 之类的值,您的函数将假定它是 EDT,但实际上该时间无效,不应存在于您的数据中。您可能应该提出错误。

  • 如果我传递一个值,例如 2013-11-03 01:30,您的函数将假定它是 EDT,但实际上它可能是 EDT 或 EST 。您需要存储偏移量或 dst 标志来消除歧义。如果数据中没有,您别无选择,只能假设其中之一。

  • 此函数不考虑 1987 年之前的日期,美国的 DST 规则也发生了变化。如果您有之前的数据,您也应该考虑到这一点。

除此之外,看起来还不错。不过,评论中的观点是正确的。这仅适用于该时区,并且您不能保证该时区的规则将来不会改变。我建议您以后将数据转换为使用 UTC。如果您愿意,您可以使用此函数进行转换,或者您也可以在应用程序级代码中轻松完成此操作。

哦,还有一件事。 “东部标准时间”或“EST”字面意思是 UTC-5,根本不考虑夏令时。就像“东部夏令时间”或“EDT”始终表示 UTC-4 一样。我假设您的意思是说您的数据位于问题中的“东部时间”,这两者都可以容纳。

如果您实际上指的是 EST,那么您的工作就简单得多 - 只需添加 5 个小时即可完成。我提出这个问题是因为确实存在不考虑夏令时来记录数据的情况。 (我相信金融领域有一些类似的用例。)

关于sql-server - 需要一个 SQL Server 函数将本地日期时间转换为支持 DST 的 UTC,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21491577/

相关文章:

sql-server - 是否可以在没有 XA 的事务中拥有两个 MSSQL 持久性单元?

sql - 如何使用sql server中的查找表替换列中的子字符串

sql-server - SQL Server 如何处理事务性 INSERT 中的 SELECT 语句?

sql - 如何将带时区的日期时间插入 SQLite?

使用 Azure Batch 的 Azure ADF 引发共享访问签名生成错误

javascript - 将字符串拆分为从 "] "开始、以 "As"结尾的子字符串

javascript - 使用 date-fns 将日期解析为 UTC 的正确方法

java - 在 Java 中将日期从 UTC 转换为 PST

sql - Azure SQL 数据库正在失去其容量

azure - 在哪里可以看到 SQL Azure 进行的内置备份