Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SQL Server 2008 - How to convert GMT(UTC) datetime to local datetime?

I have an insert proc that passes in GETDATE() as one of the values because each insert also stores when it was inserted. This is hosted on SQL Azure - which uses GMT.

Now, when I am receiving messages, I have the GMT date stored for each of them in their timestamp columns, how do I convert this to the local datetime for wherever you are when you are accessing my page?

Thanks.

like image 246
slandau Avatar asked May 19 '11 20:05

slandau


4 Answers

You could do something like this:

declare @InputUtcDateTime datetime2 = '2011-05-20 06:30:18'

declare @LocalDateTime datetime2 = dateadd(minute, datepart(TZoffset, sysdatetimeoffset()), @InputUtcDateTime)
print @LocalDateTime

or

declare @InputUtcDateTime datetime2 = '2011-05-20 06:30:18'

declare @LocalDateTime datetime2 = dateadd(minute, datediff(minute, sysutcdatetime(), sysdatetime()), @InputUtcDateTime)
print @LocalDateTime
like image 95
Alex Aza Avatar answered Oct 12 '22 14:10

Alex Aza


Aside from the Daylight Savings issue, why not simplify with:

yourDateTime - getutcdate() + getdate()
like image 21
bwperrin Avatar answered Oct 12 '22 14:10

bwperrin


For MST as an example... considering each DTM is stored in GMT already, that simplifies things..

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

Now, if your local date/time is something other than GMT/UTC, you'll likely want to use the following...

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

Here's the breakdown.

  • SWITCHOFFSET - converts a DateTimeOffset value to a different timezone, while preserving the offset.
  • TODATETIMEOFFSET - converts a DateTime value to a DateTimeOffset value at a specified timezone.
  • DATEPART - in this case is getting the timezone part of the local datetime.
  • '+00:00' - the target offset, in the second example is UTC/GMT target, from local... the former example is to MST.

NOTE/WARNING: I don't believe that this accounts for Daylight Savings Time, which could be an issue for you. If absolute preservation isn't necessary, you may want to simply add a secondary column, with the rough conversion and go forward safely.

You may want to abstract the logic into a function call, in order to account for the preservation of DST... it shouldn't be excessively difficult to do, though.

like image 44
Tracker1 Avatar answered Oct 12 '22 14:10

Tracker1


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

*EDIT: Changed CONVERT(DATE,'01/30/1900') to CONVERT(DATE,'01/31/1900') as since 45BC, January has had 31 days. This caused some times an incorrect result for 2019, and any others where the last Sunday in March is the 31st.

like image 33
High Plains Grifter Avatar answered Oct 12 '22 14:10

High Plains Grifter