4

How to convert Epoch to DateTime SQL Server if epoch exceeds the year 2038?

Answer in Convert Epoch to DateTime SQL Server will not work.

Example:

SELECT DATEADD(ss, 2713795200000 / 1000, '19700101')

Thu, 30 Dec 2055 16:00:00 GMT

Community
  • 1
  • 1
Dobermaxx99
  • 318
  • 5
  • 16

5 Answers5

2

DATEADD function assumes an INT as an increment to your date, to bypass the limitation of INT you can either reduce the precision of your epoch, or do a slightly complex code to retain the precision of your epoch.

This reduces the precision to minutes:

SELECT DATEADD(MINUTE,@YourEpoch/60/1000, '1/1/1970')

This one splits your epoch to days and milliseconds and then combines them in a datetime

CREATE FUNCTION [dbo].[fn_EpochToDatetime] (@Epoch BIGINT)
RETURNS DATETIME
AS
BEGIN
    DECLARE @Days AS INT, @MilliSeconds AS INT
    SET @Days = @Epoch / (1000*60*60*24)
    SET @MilliSeconds = @Epoch % (1000*60*60*24)

    RETURN (SELECT DATEADD(MILLISECOND, @MilliSeconds, DATEADD(DAY, @Days, '1/1/1970')))
END;

However, I'm not quite sure why the 2nd solution is not as precise as I expect it to be.

  • 1. [DateTime] is only accurate to 3⅓ milliseconds. Try having your function return a DATETIME2(3). – LDawggie Mar 03 '21 at 20:10
  • 2. Modulo works when both parameters are positive. Instead try: `SET @Days = SIGN(@Epoch) * FLOOR(ABS(@Epoch) / (1000*60*60*24));` and `SET @MilliSeconds = SIGN(@Epoch) * (ABS(@Epoch) % (1000*60*60*24));` – LDawggie Mar 03 '21 at 20:11
0

Building on the response above, the solution provided works but does not protect from trying to convert to a date that is out of bounds for SQL server.

create function dbo.unixTimestampConversion ( @unixTime bigInt ) returns dateTime2(7) as begin

    declare
        @output dateTime2(7)
        , @days int
        , @ms   int
        , @x    int = (1000 * 60 * 60 * 24)
    ;


    set @days = @unixTime / @x
    ;
    set @ms = @unixTime % @x
    ;
    if (@unixTime < 32503593600000 and @unixTime > -2208988800000)
        begin
            set @output = dateAdd (millisecond, @ms, dateAdd (day, @days, '1/1/1970'))
            ;
        end
        ;
    else if (@unixTime <= -2208988800000)
             begin
                 set @output = '1/1/1900'
                 ;
             end
             ;
    else if (@unixTime >= 32503593600000)
             begin
                 set @output = '12/31/2999'
                 ;
             end
             ;
    return @output
    ;


end

;

Jake
  • 1
  • I tested this out. It does not fix the precision issue. I tested it with an epoch of 1628389678598. The value from https://www.epochconverter.com/ is 2021-08-08 02:27:58.598 . This answer returns 2021-08-08 02:27:58.5966667. Relying on DATEADD is the problem here, methinks. – onefootswill Sep 02 '21 at 08:15
0

You can assign the epoch time to your datetime directly (I tried this on SQL Server 15.0). Although it considers the number as the number of days since 1900-1-1 00:00:00 so you have to add 2208988800 (the number of seconds in 70 years) and then divide by 86400(number of seconds in a day).

DECLARE @time DATETIME = (2208988800.0 + [your epoch time in seconds])/86400;

However, it seems to be 0.007s or 0.003s behind the given epoch. Also, I'm not sure if this is faster than the DATEADD() function.

SMMB
  • 107
  • 6
0

Old question, but later versions of SQL Server that support the DATETIMEOFFSET data type have made this easier:

DATEADD(CAST('1970-01-01T00:00:00Z' AS DATETIMEOFFSET),s,<epoch time as bigint>))

DATEADD can work with s/second, ms/millisecond, mcs/microsecond, and ns/nanosecond.

Then, if you need it in a specific time zone, use SELECT <date> AS TIME ZONE <timezone>.

-2

create a function to convert epoch to datetime and use them in your query like below

create FUNCTION [dbo].[from_unixtime] (@Datetime BIGINT)
RETURNS DATETIME
AS
BEGIN
    DECLARE @LocalTimeOffset BIGINT
           ,@AdjustedLocalDatetime BIGINT;
    SET @LocalTimeOffset = DATEDIFF(second,GETDATE(),GETUTCDATE())
    SET @AdjustedLocalDatetime = @Datetime - @LocalTimeOffset
    RETURN (SELECT DATEADD(second,@AdjustedLocalDatetime, CAST('1970-01-01 00:00:00' AS datetime)))
END;

and then use this function in your query

Ankit Agrawal
  • 2,426
  • 1
  • 13
  • 27