SQL Server 2008 - 如何将 GMT(UTC) 日期时间转换为本地日期时间



我有一个插入过程,它作为值之一传入GETDATE(),因为每个插入也会存储插入的时间。它托管在SQL Azure上 - 它使用GMT。

现在,当我收到消息时,我将每个消息的 GMT 日期存储在它们的时间戳列中,当您访问我的页面时,我如何将其转换为本地datetime,无论您身在何处?

谢谢。

你可以做这样的事情:

declare @InputUtcDateTime datetime2 = '2011-05-20 06:30:18'
declare @LocalDateTime datetime2 = dateadd(minute, datepart(TZoffset, sysdatetimeoffset()), @InputUtcDateTime)
print @LocalDateTime

declare @InputUtcDateTime datetime2 = '2011-05-20 06:30:18'
declare @LocalDateTime datetime2 = dateadd(minute, datediff(minute, sysutcdatetime(), sysdatetime()), @InputUtcDateTime)
print @LocalDateTime

除了夏令时问题,为什么不简化:

yourDateTime - getutcdate() + getdate()

以 MST 为例...考虑到每个DTM都已经存储在GMT中,这简化了事情。

SWITCHOFFSET(CONVERT(DATETIMEOFFSET, [ColumnName]), '-07:00')

现在,如果您的本地日期/时间不是 GMT/UTC,您可能需要使用以下...

SWITCHOFFSET(TODATETIMEOFFSET([ColumnName], datepart(tz,sysdatetimeoffset())),'+00:00')

这是细分。

  • SWITCHOFFSET - 将日期时间偏移量值转换为不同的时区,同时保留偏移量。
  • TODATETIMEOFFSET - 将指定时区的日期时间值转换为日期时间偏移量值。
  • DATEPART - 在本例中是获取本地日期时间的时区部分。
  • '+00:00' - 目标偏移量,在第二个示例中是 UTC/GMT 目标,来自本地...前一个例子是 MST。

注意/警告:我不认为这考虑了夏令时,这对您来说可能是一个问题。 如果不需要绝对保留,您可能希望简单地添加一个辅助列,并进行粗略转换并安全地前进。

您可能希望将逻辑抽象为函数调用,以便考虑保留 DST...不过,这应该不会太难做到。

CREATE FUNCTION [dbo].[fn_DateTime_GMTFromLocal](@LocalTime DATETIME)
RETURNS DATETIME2(3)
AS
BEGIN
/*
=============================================
 Author:        Mark Griffiths
 Create date:   29/05/2018
 Description:   BST runs from 02:00AM on the last Sunday of March to the same time on the last Sunday of October.       
    The Series of DATEDIFFs and DATEADDS below function as follows
    1   ●   Count the number of months there have been between the given date and start of computer time
    2   ●   Add that number of months to the end of the first month to get the end of the given month
    3   ●   Count the number of days there have been between the end of the given month and the first Saturday
    4   ●   Add that number of days to the calculated end of the given month
    5   ●   Add Two hours to that time as the clocks go back at 02:00 in the morning
    I know that the tabbing below makes it all look odd, but the description above is the best way I could find to comment things, given the nesting...
    The comments in the code below should help find the nesting levels and the numbers refer to the bullet points above.
=============================================
-- Test Variables --
DECLARE @GMTime DATETIME2(3) = '2018-05-01 12:00:00.000'
*/
    DECLARE @RealTime As DATETIME2(3)
    DECLARE @Year VARCHAR(4)
    SET @Year = CONVERT(VARCHAR,DATEPART(YEAR,@GMTime))
    DECLARE @StartOfBST AS DATETIME
    DECLARE @EndOfBST AS DATETIME
    SELECT
        @StartOfBST =
        DATEADD     -----------------------------------------------------------------------------------------
            (                                                       --                                      |
             HOUR                                                   --                                      |
            ,2                                                      --                                      |
            ,DATEADD    -----------------------------------------------------------------------------       |
                (                                                   --                              |       |
                 DAY                                                --                              |       |
                ,DATEDIFF       -------------------------------------------------------------       |       |
                    (                                               --                      |       |       |
                     DAY                                            --                      |       |       |
                    ,'19000107'                                     --                      |       |       5
                    ,DATEADD            ---------------------------------------------       |       |       |
                        (                                           --              |       3       4       |
                         MONTH                                      --              |       |       |       |
                        ,DATEDIFF(MONTH,0,CONVERT(DATE,'03/01/' + @Year)) -- 1      2       |       |       |
                        ,CONVERT(DATE,'01/31/1900')                 --              |       |       |       |
                        )               ---------------------------------------------       |       |       |
                    )/7*7       -------------------------------------------------------------       |       |
                    ,'19000107'                                     --                              |       |
                )               ---------------------------------------------------------------------       |
            ),      -----------------------------------------------------------------------------------------
    @EndOfBST =
        DATEADD(HOUR,2,DATEADD(day,DATEDIFF(day,'19000107',DATEADD(month,DATEDIFF(MONTH,0,CONVERT(DATE,'10/01/' + @Year)),30))/7*7,'19000107'))
    SET @RealTime = CASE
                    WHEN @GMTime BETWEEN @StartOfBST AND @EndOfBST THEN DATEADD(HOUR,-1,@GMTime)
                    ELSE @GMTime
                END
RETURN @RealTime;
--SELECT @RealTime
END

*编辑:CONVERT(DATE,'01/30/1900')更改为CONVERT(DATE,'01/31/1900'),因为自公元前45年以来,一月有31天。这导致2019年的结果有时不正确,而3月的最后一个星期日是31日

这是一个处理历史数据的函数。我为英国夏令时写了它——不幸的是,它发生在三月和十月的最后一个星期日,使逻辑有点复杂。

基本上,硬编码日期部分 01/03 正在寻找 3 月的最后一个星期日,01/10 正在寻找 10 月的最后一个星期日(这是时钟在这里前进和返回的时间)。注意:如果您的服务器使用的是美国本地日期,请将这两个日期部分反转为 03/01 和 10/01!!!

因此,您向它输入UTC日期,它将自动计算出历史日期是BST还是GMT。不是在大数据集上使用的最佳选择,但它是一种解决方案。

运行此脚本以创建函数,并在选择中内联调用它。SQL 2008 在用户定义函数方面存在问题,它似乎在代码下放了一条红线,但只要您使用 dbo 前缀(SELECT dbo.UTCConvert(yourdate)来运行它)

CREATE FUNCTION [dbo].[UTCConvert] 
(
    @p1 datetime
)
RETURNS datetime
AS
BEGIN
    DECLARE @Result datetime

RETURN CASE 
WHEN
@p1 >
(DATEADD(day,DATEDIFF(day,'19000107',DATEADD(month,DATEDIFF(MONTH,0,'01/03/' + CAST(DATEPART(year,@p1) as CHAR)),30))/7*7,'19000107'))
AND
@p1<
(DATEADD(day,DATEDIFF(day,'19000107',DATEADD(month,DATEDIFF(MONTH,0,'01/10/' + CAST(DATEPART(year,@p1) as CHAR)),30))/7*7,'19000107'))
THEN (DATEADD(HH, 1, @p1)) 
ELSE @p1
END
END

相关内容

  • 没有找到相关文章

最新更新