ฉันจะแปลง bigint (UNIX timestamp) เป็น datetime ใน SQL Server ได้อย่างไร


คำตอบ:


58

ลอง:

CREATE FUNCTION dbo.fn_ConvertToDateTime (@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;
GO

2
+1 สำหรับ UTC-> การแปลงในพื้นที่ โปรดทราบว่าฤดูร้อน / ฤดูหนาวจะยังคงปิดอยู่หากคุณพยายามแปลวันที่ 10 มิถุนายนในช่วงเดือนกุมภาพันธ์
Andomar

11
-1 สำหรับ UTC-> การแปลงในพื้นที่ การจัดการเวลาออมแสงไม่ถูกต้อง สำหรับฉันนี่เป็นการเข้าใจผิด
Pavel Horal

+1 สำหรับโซลูชันที่สร้างสรรค์! ใช้งานได้ดี FYI มีข้อผิดพลาดทางไวยากรณ์ใน SQL เครื่องหมายอัฒภาคที่ท้ายบรรทัด "DECLARE" แรกจะต้องถูกลบออกเนื่องจากมีเครื่องหมายจุลภาคตามหลัง
เซท

2
มันไม่ได้ผลสำหรับฉัน ฉันกำลังลองกับ 1517270400000 และได้รับข้อผิดพลาดนี้: ข้อผิดพลาดทางคณิตศาสตร์ล้นในการแปลงนิพจน์เป็นชนิดข้อมูล int
เดนมาร์ก

1
นอกจากนี้ยังได้รับการโอเวอร์โฟลว์ซึ่งโดยปกติหมายความว่ามีส่วนร่วมในมิลลิวินาทีแก้ไขได้ง่ายๆดังนี้: เลือก dbo.fn_ConvertToDateTime (src_column / 1000) จาก src_table;
access_granted

305

สิ่งนี้ใช้ได้ผลสำหรับฉัน:

Select
    dateadd(S, [unixtime], '1970-01-01')
From [Table]

ในกรณีใด ๆ สิ่งมหัศจรรย์หนึ่งว่าทำไม 1970/01/01, นี้เรียกว่าเวลา Epoch

ด้านล่างนี้เป็นคำพูดจาก Wikipedia:

จำนวนวินาทีที่ผ่านไปตั้งแต่ 00:00:00 เวลาสากลเชิงพิกัด (UTC) วันพฤหัสบดีที่ 1 มกราคม 1970 [1] [หมายเหตุ 1] ไม่นับวินาทีอธิกสุรทิน


17
ควรทำเครื่องหมายว่าถูกต้อง ฉันหวังว่าฉันจะโหวตคำตอบนี้อีกครั้งทุกครั้งที่มาที่นี่ :)
BenDundee

2
@BenDundee ฉันเห็นด้วยกับคุณจริงๆ ช่างเป็นทางออกที่สวยงาม ฉันมองหาสูตรทั้งหมดและในที่สุดก็ตัดสินใจเลือกสูตรเดียวที่จะต้องค้นหาอีกครั้งเมื่อฉันเริ่มพบข้อผิดพลาดในอีกหนึ่งสัปดาห์ต่อมา โชคดีที่ฉันพบสิ่งนี้ในการไปรอบที่สอง
ล่าช้า

1
ฉันใช้วิธีนี้มาตลอด วันที่จัดรูปแบบนี้เชื่อมต่อกับข้อมูลอื่นดังนั้นฉันจึงมี varchar ... ง่าย! ไม่ต้องยุ่งยากในการจัดรูปแบบบันทึกเหล่านั้นในแอปพลิเคชัน อย่างไรก็ตามปัญหาเขตเวลาบางอย่างปรากฏขึ้น! วันที่ของฉันใช้เขตเวลา UTC แทนเขตเวลาของลูกค้า :(
gustavohenke

2
@Whitecat ไม่รู้ว่าคุณแก้ปัญหาแล้วหรือยัง แต่ดูปลอก! บางทีการตั้งค่าการเรียงฐานข้อมูลของคุณอาจถูกตั้งค่าเป็น "SQL_Latin1_General_CP1_CS_AS" CS เป็นคีย์เวิร์ดที่นี่ ย่อมาจาก "CaseSensitiv" ดังนั้นรหัสของคุณจะต้องตรงกับปลอก! อีกประเด็นหนึ่งอาจเป็นได้ว่าระบบของคุณคือ MySql กว่าชื่อคือ date_add () ขอแสดงความนับถือ;)
Nightking

3
โซลูชันนี้จะได้รับผลกระทบจากปัญหาปี 2038 เนื่องจากฟังก์ชัน dateadd ต้องการชนิด int เอกสารระบุว่า "อาร์กิวเมนต์ number ต้องไม่เกินช่วง int" docs.microsoft.com/en-us/sql/t-sql/functions/… th.wikipedia.org/wiki/Year_2038_problem
Patrick H

30

หากใครได้รับข้อผิดพลาดด้านล่าง:

ข้อผิดพลาดทางคณิตศาสตร์ล้นในการแปลงนิพจน์เป็นชนิดข้อมูล int

เนื่องจากการประทับเวลาของยูนิกซ์อยู่ใน bigint (แทนที่จะเป็น int) คุณสามารถใช้สิ่งนี้:

SELECT DATEADD(S, CONVERT(int,LEFT(1462924862735870900, 10)), '1970-01-01')
FROM TABLE

แทนที่การประทับเวลาแบบฮาร์ดโค้ดสำหรับคอลัมน์จริงของคุณด้วย unix-timestamp

ที่มา: MSSQL bigint Unix Timestamp เป็น Datetime ด้วยมิลลิวินาที


เมื่อพิจารณาถึงช่วงมิลลิวินาทีที่ดียิ่งขึ้น: SELECT DATEADD (ms, 1517270454852% 1000, DATEADD (S, 1517270454852/1000, '1970-01-01'))
G DeMasters

25

แบบนี้

เพิ่มวันที่และเวลาของ Unix (epoch) เป็นวันที่ฐานเป็นวินาที

สิ่งนี้จะได้รับทันที (2010-05-25 07: 56: 23.000)

 SELECT dateadd(s,1274756183,'19700101 05:00:00:000')

หากคุณต้องการย้อนกลับลองดูที่http://wiki.lessthandot.com/index.php/Epoch_Dateนี้


1
ทำไม 05:00:00 แทนที่จะเป็น 00:00:00?
Svisstack

2
@Svisstack 5 ชั่วโมงสำหรับความแตกต่างของเขตเวลา 5:00:00 หมายความว่าเขาเป็น GMT-5 ชั่วโมง
Jordy van Eijk

ใช้งานได้เหมือนมีเสน่ห์ หากคุณต้องการปรับเปลี่ยนสำหรับเขตเวลาก็ควรทำอย่างนั้น แต่ให้ถือว่ามีประสิทธิภาพมาก
clifton_h

7

สิ่งนี้จะทำ:

declare @UNIX_TIME int
select @UNIX_TIME = 1111111111
-- Using dateadd to add seconds to 1970-01-01
select [Datetime from UNIX Time] = dateadd(!precision!,@UNIX_TIME,'1970-01-01')

แทน! แม่นยำ! ใช้: ss, ms หรือ mcs ตามความแม่นยำของการประทับเวลา Bigint สามารถจับความแม่นยำระดับไมโครวินาที



4

เพิ่มnวินาทีเพื่อ1970-01-01ที่จะทำให้คุณวัน UTCเพราะnที่เวลา Unix เป็นจำนวนวินาทีที่ได้ผ่านไปนับตั้งแต่ 00:00:00 Coordinated Universal Time (UTC), พฤหัสบดี 1 มกราคม, 1970

ใน SQL Server 2016 คุณสามารถแปลงโซนเวลาหนึ่งเป็นอีกโซนโดยใช้AT TIME ZONE. คุณต้องรู้ชื่อเขตเวลาในรูปแบบมาตรฐานของ Windows:

SELECT *
FROM (VALUES (1514808000), (1527854400)) AS Tests(UnixTimestamp)
CROSS APPLY (SELECT DATEADD(SECOND, UnixTimestamp, '1970-01-01') AT TIME ZONE 'UTC') AS CA1(UTCDate)
CROSS APPLY (SELECT UTCDate AT TIME ZONE 'Pacific Standard Time') AS CA2(LocalDate)
| UnixTimestamp | UTCDate                    | LocalDate                  |
|---------------|----------------------------|----------------------------|
| 1514808000    | 2018-01-01 12:00:00 +00:00 | 2018-01-01 04:00:00 -08:00 |
| 1527854400    | 2018-06-01 12:00:00 +00:00 | 2018-06-01 05:00:00 -07:00 |

หรือเพียงแค่:

SELECT *, DATEADD(SECOND, UnixTimestamp, '1970-01-01') AT TIME ZONE 'UTC' AT TIME ZONE 'Pacific Standard Time'
FROM (VALUES (1514808000), (1527854400)) AS Tests(UnixTimestamp)
| UnixTimestamp | LocalDate                  |
|---------------|----------------------------|
| 1514808000    | 2018-01-01 04:00:00 -08:00 |
| 1527854400    | 2018-06-01 05:00:00 -07:00 |

หมายเหตุ:

  • คุณสามารถตัดข้อมูลเขตเวลาโดยการหล่อไปDATETIMEOFFSETDATETIME
  • การแปลงจะคำนึงถึงเวลาออมแสง เวลาแปซิฟิกคือ UTC-08: 00 ของวันที่มกราคม 2018 และ UTC-07: 00 ของมิถุนายน 2018

3

หากเวลาเป็นมิลลิวินาทีและจำเป็นต้องสงวนไว้:

DECLARE @value VARCHAR(32) = '1561487667713';

SELECT DATEADD(MILLISECOND, CAST(RIGHT(@value, 3) AS INT) - DATEDIFF(MILLISECOND,GETDATE(),GETUTCDATE()), DATEADD(SECOND, CAST(LEFT(@value, 10) AS INT), '1970-01-01T00:00:00'))

1

นี่เป็นการสร้างจากงานที่ Daniel Little ทำสำหรับคำถามนี้ แต่คำนึงถึงเวลาออมแสง (ใช้ได้กับวันที่ 01-01 1902 และสูงกว่าเนื่องจากขีด จำกัด int ในฟังก์ชัน dateadd):

ก่อนอื่นเราต้องสร้างตารางที่จะเก็บช่วงวันที่สำหรับเวลาออมแสง (ที่มา: ประวัติเวลาในสหรัฐอเมริกา ):

CREATE TABLE [dbo].[CFG_DAY_LIGHT_SAVINGS_TIME](
  [BEGIN_DATE] [datetime] NULL,
  [END_DATE] [datetime] NULL,
  [YEAR_DATE] [smallint] NULL
) ON [PRIMARY]

GO

INSERT INTO CFG_DAY_LIGHT_SAVINGS_TIME VALUES
('2001-04-01 02:00:00.000',   '2001-10-27 01:59:59.997',    2001),
('2002-04-07 02:00:00.000',   '2002-10-26 01:59:59.997',    2002),
('2003-04-06 02:00:00.000',   '2003-10-25 01:59:59.997',    2003),
('2004-04-04 02:00:00.000',   '2004-10-30 01:59:59.997',    2004),
('2005-04-03 02:00:00.000',   '2005-10-29 01:59:59.997',    2005),
('2006-04-02 02:00:00.000',   '2006-10-28 01:59:59.997',    2006),
('2007-03-11 02:00:00.000',   '2007-11-03 01:59:59.997',    2007),
('2008-03-09 02:00:00.000',   '2008-11-01 01:59:59.997',    2008),
('2009-03-08 02:00:00.000',   '2009-10-31 01:59:59.997',    2009),
('2010-03-14 02:00:00.000',   '2010-11-06 01:59:59.997',    2010),
('2011-03-13 02:00:00.000',   '2011-11-05 01:59:59.997',    2011),
('2012-03-11 02:00:00.000',   '2012-11-03 01:59:59.997',    2012),
('2013-03-10 02:00:00.000',   '2013-11-02 01:59:59.997',    2013),
('2014-03-09 02:00:00.000',   '2014-11-01 01:59:59.997',    2014),
('2015-03-08 02:00:00.000',   '2015-10-31 01:59:59.997',    2015),
('2016-03-13 02:00:00.000',   '2016-11-05 01:59:59.997',    2016),
('2017-03-12 02:00:00.000',   '2017-11-04 01:59:59.997',    2017),
('2018-03-11 02:00:00.000',   '2018-11-03 01:59:59.997',    2018),
('2019-03-10 02:00:00.000',   '2019-11-02 01:59:59.997',    2019),
('2020-03-08 02:00:00.000',   '2020-10-31 01:59:59.997',    2020),
('2021-03-14 02:00:00.000',   '2021-11-06 01:59:59.997',    2021),
('2022-03-13 02:00:00.000',   '2022-11-05 01:59:59.997',    2022),
('2023-03-12 02:00:00.000',   '2023-11-04 01:59:59.997',    2023),
('2024-03-10 02:00:00.000',   '2024-11-02 01:59:59.997',    2024),
('2025-03-09 02:00:00.000',   '2025-11-01 01:59:59.997',    2025),
('1967-04-30 02:00:00.000',   '1967-10-29 01:59:59.997',    1967),
('1968-04-28 02:00:00.000',   '1968-10-27 01:59:59.997',    1968),
('1969-04-27 02:00:00.000',   '1969-10-26 01:59:59.997',    1969),
('1970-04-26 02:00:00.000',   '1970-10-25 01:59:59.997',    1970),
('1971-04-25 02:00:00.000',   '1971-10-31 01:59:59.997',    1971),
('1972-04-30 02:00:00.000',   '1972-10-29 01:59:59.997',    1972),
('1973-04-29 02:00:00.000',   '1973-10-28 01:59:59.997',    1973),
('1974-01-06 02:00:00.000',   '1974-10-27 01:59:59.997',    1974),
('1975-02-23 02:00:00.000',   '1975-10-26 01:59:59.997',    1975),
('1976-04-25 02:00:00.000',   '1976-10-31 01:59:59.997',    1976),
('1977-04-24 02:00:00.000',   '1977-10-31 01:59:59.997',    1977),
('1978-04-30 02:00:00.000',   '1978-10-29 01:59:59.997',    1978),
('1979-04-29 02:00:00.000',   '1979-10-28 01:59:59.997',    1979),
('1980-04-27 02:00:00.000',   '1980-10-26 01:59:59.997',    1980),
('1981-04-26 02:00:00.000',   '1981-10-25 01:59:59.997',    1981),
('1982-04-25 02:00:00.000',   '1982-10-25 01:59:59.997',    1982),
('1983-04-24 02:00:00.000',   '1983-10-30 01:59:59.997',    1983),
('1984-04-29 02:00:00.000',   '1984-10-28 01:59:59.997',    1984),
('1985-04-28 02:00:00.000',   '1985-10-27 01:59:59.997',    1985),
('1986-04-27 02:00:00.000',   '1986-10-26 01:59:59.997',    1986),
('1987-04-05 02:00:00.000',   '1987-10-25 01:59:59.997',    1987),
('1988-04-03 02:00:00.000',   '1988-10-30 01:59:59.997',    1988),
('1989-04-02 02:00:00.000',   '1989-10-29 01:59:59.997',    1989),
('1990-04-01 02:00:00.000',   '1990-10-28 01:59:59.997',    1990),
('1991-04-07 02:00:00.000',   '1991-10-27 01:59:59.997',    1991),
('1992-04-05 02:00:00.000',   '1992-10-25 01:59:59.997',    1992),
('1993-04-04 02:00:00.000',   '1993-10-31 01:59:59.997',    1993),
('1994-04-03 02:00:00.000',   '1994-10-30 01:59:59.997',    1994),
('1995-04-02 02:00:00.000',   '1995-10-29 01:59:59.997',    1995),
('1996-04-07 02:00:00.000',   '1996-10-27 01:59:59.997',    1996),
('1997-04-06 02:00:00.000',   '1997-10-26 01:59:59.997',    1997),
('1998-04-05 02:00:00.000',   '1998-10-25 01:59:59.997',    1998),
('1999-04-04 02:00:00.000',   '1999-10-31 01:59:59.997',    1999),
('2000-04-02 02:00:00.000',   '2000-10-29 01:59:59.997',    2000)
GO

ตอนนี้เราสร้างฟังก์ชันสำหรับแต่ละเขตเวลาของอเมริกา นี่คือสมมติว่าเวลายูนิกซ์อยู่ในหน่วยมิลลิวินาที หากเป็นวินาทีให้ลบ / 1000 ออกจากรหัส:

แปซิฟิก

create function [dbo].[UnixTimeToPacific] 
 (@unixtime bigint)
   returns datetime
   as
   begin
     declare @pacificdatetime datetime
     declare @interimdatetime datetime = dateadd(s, @unixtime/1000, '1970-01-01')
     select  @pacificdatetime =  dateadd(hour,case when @interimdatetime between begin_date and end_date then -7 else -8 end  ,@interimdatetime)
     from cfg_day_light_savings_time  where  year_date = datepart(year,@interimdatetime)
     if @pacificdatetime is null 
       select @pacificdatetime= dateadd(hour, -7, @interimdatetime)
return @pacificdatetime    
end

ตะวันออก

create function [dbo].[UnixTimeToEastern] 
 (@unixtime bigint)
   returns datetime
   as
   begin
     declare @easterndatetime datetime
     declare @interimdatetime datetime = dateadd(s, @unixtime/1000, '1970-01-01')
     select  @easterndatetime =  dateadd(hour,case when @interimdatetime between begin_date and end_date then -4 else -5 end  ,@interimdatetime)
     from cfg_day_light_savings_time  where  year_date = datepart(year,@interimdatetime)
     if @easterndatetime is null 
       select @easterndatetime= dateadd(hour, -4, @interimdatetime)
return @easterndatetime    
end

ศูนย์กลาง

create function [dbo].[UnixTimeToCentral] 
 (@unixtime bigint)
   returns datetime
   as
   begin
     declare @centraldatetime datetime
     declare @interimdatetime datetime = dateadd(s, @unixtime/1000, '1970-01-01')
     select  @centraldatetime =  dateadd(hour,case when @interimdatetime between begin_date and end_date then -5 else -6 end  ,@interimdatetime)
     from cfg_day_light_savings_time  where  year_date = datepart(year,@interimdatetime)
     if @centraldatetime is null 
       select @centraldatetime= dateadd(hour, -5, @interimdatetime)
return @centraldatetime    
end

ภูเขา

create function [dbo].[UnixTimeToMountain] 
 (@unixtime bigint)
   returns datetime
   as
   begin
     declare @mountaindatetime datetime
     declare @interimdatetime datetime = dateadd(s, @unixtime/1000, '1970-01-01')
     select  @mountaindatetime =  dateadd(hour,case when @interimdatetime between begin_date and end_date then -6 else -7 end  ,@interimdatetime)
     from cfg_day_light_savings_time  where  year_date = datepart(year,@interimdatetime)
     if @mountaindatetime is null 
       select @mountaindatetime= dateadd(hour, -6, @interimdatetime)
return @mountaindatetime    
end

ฮาวาย

create function [dbo].[UnixTimeToHawaii] 
 (@unixtime bigint)
   returns datetime
   as
   begin
     declare @hawaiidatetime datetime
     declare @interimdatetime datetime = dateadd(s, @unixtime/1000, '1970-01-01')
     select  @hawaiidatetime =  dateadd(hour,-10,@interimdatetime)
     from cfg_day_light_savings_time  where  year_date = datepart(year,@interimdatetime)

return @hawaiidatetime    
end

แอริโซนา

create function [dbo].[UnixTimeToArizona] 
 (@unixtime bigint)
   returns datetime
   as
   begin
     declare @arizonadatetime datetime
     declare @interimdatetime datetime = dateadd(s, @unixtime/1000, '1970-01-01')
     select  @arizonadatetime =  dateadd(hour,-7,@interimdatetime)
     from cfg_day_light_savings_time  where  year_date = datepart(year,@interimdatetime)

return @arizonadatetime    
end

อลาสก้า

create function [dbo].[UnixTimeToAlaska] 
 (@unixtime bigint)
   returns datetime
   as
   begin
     declare @alaskadatetime datetime
     declare @interimdatetime datetime = dateadd(s, @unixtime/1000, '1970-01-01')
     select  @alaskadatetime =  dateadd(hour,case when @interimdatetime between begin_date and end_date then -8 else -9 end  ,@interimdatetime)
     from cfg_day_light_savings_time  where  year_date = datepart(year,@interimdatetime)
     if @alaskadatetime is null 
       select @alaskadatetime= dateadd(hour, -8, @interimdatetime)
return @alaskadatetime    
end

1
//BIGINT UNIX TIMESTAMP CONVERSION upto Millisecond Accuracy
CREATE FUNCTION [dbo].[ConvertUnixTimestamp] (@Datetime [BIGINT]) RETURNS DATETIME
AS
BEGIN

    RETURN DATEADD(MILLISECOND, cast(@Datetime as bigint) % 1000, 
    DATEADD(SECOND, (cast(@Datetime as bigint) / 1000)%60, 
    DATEADD(MINUTE, ((cast(@Datetime as bigint) / 1000)/60)%60, 
    DATEADD(HOUR, ((cast(@Datetime as bigint) / 1000)/60)/60, '19700101'))))
END

1

ฉันก็ต้องเผชิญกับปัญหานี้เช่นกัน น่าเสียดายที่ไม่มีคำตอบใด (ที่นี่และในหน้าอื่น ๆ อีกหลายสิบหน้า) ที่น่าพอใจสำหรับฉันเนื่องจากฉันยังไม่สามารถไปถึงวันที่เกินกว่าปี 2038 ได้เนื่องจากจำนวนเต็ม 32 บิตถูกทิ้งไว้ที่ไหนสักแห่ง

วิธีการแก้ปัญหาที่ไม่ทำงานสำหรับฉันในท้ายที่สุดคือการใช้ตัวแปรดังนั้นฉันสามารถมีอย่างน้อยวันสูงสุดfloat 2262-04-11T23:47:16.854775849ถึงกระนั้นก็ยังไม่ครอบคลุมทั้งdatetimeโดเมน แต่ก็เพียงพอสำหรับความต้องการของฉันและอาจช่วยให้ผู้อื่นที่ประสบปัญหาเดียวกันได้

-- date variables
declare @ts bigint; -- 64 bit time stamp, 100ns precision
declare @d datetime2(7) = GETUTCDATE(); -- 'now'
-- select @d = '2262-04-11T23:47:16.854775849'; -- this would be the max date

-- constants:
declare @epoch datetime2(7) = cast('1970-01-01T00:00:00' as datetime2(7));
declare @epochdiff int = 25567; -- = days between 1900-01-01 and 1970-01-01
declare @ticksofday bigint = 864000000000; -- = (24*60*60*1000*1000*10)

-- helper variables:
declare @datepart float;
declare @timepart float;
declare @restored datetime2(7);

-- algorithm:
select @ts = DATEDIFF_BIG(NANOSECOND, @epoch, @d) / 100; -- 'now' in ticks according to unix epoch
select @timepart = (@ts % @ticksofday) / @ticksofday; -- extract time part and scale it to fractional part (i. e. 1 hour is 1/24th of a day)
select @datepart = (@ts - @timepart) / @ticksofday; -- extract date part and scale it to fractional part
select @restored = cast(@epochdiff + @datepart + @timepart as datetime); -- rebuild parts to a datetime value

-- query original datetime, intermediate timestamp and restored datetime for comparison
select
  @d original,
  @ts unix64,
  @restored restored
;

-- example result for max date:
-- +-----------------------------+-------------------+-----------------------------+
-- | original                    | unix64            | restored                    |
-- +-----------------------------+-------------------+-----------------------------+
-- | 2262-04-11 23:47:16.8547758 | 92233720368547758 | 2262-04-11 23:47:16.8533333 |
-- +-----------------------------+-------------------+-----------------------------+

มีบางประเด็นที่ควรพิจารณา:

  • ความแม่นยำ 100ns เป็นข้อกำหนดในกรณีของฉันอย่างไรก็ตามสิ่งนี้ดูเหมือนจะเป็นความละเอียดมาตรฐานสำหรับการประทับเวลายูนิกซ์ 64 บิต หากคุณใช้ความละเอียดอื่นคุณต้องปรับ@ticksofdayและบรรทัดแรกของอัลกอริทึมให้สอดคล้องกัน
  • ฉันใช้ระบบอื่นที่มีปัญหาเกี่ยวกับเขตเวลา ฯลฯ และฉันพบว่าทางออกที่ดีที่สุดสำหรับฉันคือใช้ UTC เสมอ สำหรับความต้องการของคุณสิ่งนี้อาจแตกต่างกัน
  • 1900-01-01คือวันที่เริ่มต้นdatetime2เช่นเดียวกับยุค1970-01-01สำหรับการประทับเวลาแบบยูนิกซ์
  • floats ช่วยฉันแก้ปัญหาปี 2038 และจำนวนเต็มล้นและเช่นนี้ แต่โปรดทราบว่าตัวเลขทศนิยมไม่ได้มีประสิทธิภาพมากนักและอาจทำให้การประมวลผลการประทับเวลาจำนวนมากช้าลง นอกจากนี้การลอยตัวอาจทำให้สูญเสียความแม่นยำเนื่องจากข้อผิดพลาดในการปัดเศษดังที่คุณเห็นในการเปรียบเทียบผลลัพธ์ตัวอย่างสำหรับวันที่สูงสุดด้านบน (ที่นี่ข้อผิดพลาดประมาณ 1.4425 มิลลิวินาที)
  • datetimeในบรรทัดสุดท้ายของอัลกอริทึมที่มีการโยนไป แต่น่าเสียดายที่ไม่มีนักแสดงอย่างชัดเจนจากค่าตัวเลขที่จะdatetime2ได้รับอนุญาต แต่มันได้รับอนุญาตให้ numerics โยนไปอย่างชัดเจนและในที่สุดก็ถูกโยนไปโดยปริยายdatetime datetime2สิ่งนี้อาจถูกต้องในตอนนี้ แต่อาจมีการเปลี่ยนแปลงใน SQL Server เวอร์ชันอนาคต: อาจมีdateadd_big()ฟังก์ชันหรือการแคสต์ที่ชัดเจนdatetime2จะได้รับอนุญาตหรือการแคสต์อย่างชัดเจนdatetimeจะไม่ได้รับอนุญาตดังนั้นสิ่งนี้อาจแตกหรืออาจเกิดขึ้น วิธีที่ง่ายกว่าในบางวัน


0

ดีกว่ามั้ย? ฟังก์ชันนี้จะแปลง unixtime ในหน่วยมิลลิวินาทีเป็นวันที่และเวลา มันหายไปมิลลิวินาที แต่ยังมีประโยชน์มากสำหรับการกรอง

CREATE FUNCTION [dbo].[UnixTimestampToGMTDatetime] 
(@UnixTimestamp bigint)
RETURNS datetime
AS
BEGIN
       DECLARE @GMTDatetime datetime
       select @GMTDatetime = 
       CASE
       WHEN dateadd(ss, @UnixTimestamp/1000, '1970-01-01') 
       BETWEEN 
           Convert(DATETIME, Convert(VARCHAR(4), Year(dateadd(ss, @UnixTimestamp/1000, '1970-01-01') )) + '-03-' + Convert(VARCHAR(2), (31 - (5 * Year(dateadd(ss, @UnixTimestamp/1000, '1970-01-01') )/4 + 4) % 7)) + ' 01:00:00', 20)
       AND
           Convert(DATETIME, Convert(VARCHAR(4), Year(dateadd(ss, @UnixTimestamp/1000, '1970-01-01') )) + '-10-' + Convert(VARCHAR(2), (31 - (5 * Year(dateadd(ss, @UnixTimestamp/1000, '1970-01-01') )/4 + 1) % 7)) + ' 02:00:00', 20)
       THEN Dateadd(hh, 1, dateadd(ss, @UnixTimestamp/1000, '1970-01-01'))
       ELSE Dateadd(hh, 0, dateadd(ss, @UnixTimestamp/1000, '1970-01-01'))
       END
RETURN @GMTDatetime    
END

0

วิธีแก้ไขมีดังต่อไปนี้:

DECLARE @UnixTimeStamp bigint = 1564646400000 /*2019-08-01 11:00 AM*/

DECLARE @LocalTimeOffset bigint = DATEDIFF(MILLISECOND, GETDATE(), GETUTCDATE());
DECLARE @AdjustedTimeStamp bigint = @UnixTimeStamp - @LocalTimeOffset;
SELECT [DateTime] = DATEADD(SECOND, @AdjustedTimeStamp % 1000, DATEADD(SECOND, @AdjustedTimeStamp / 1000, '19700101'));

0

@DanielLittle มีคำตอบที่ง่ายและสง่างามที่สุดสำหรับคำถามเฉพาะ อย่างไรก็ตามหากคุณสนใจที่จะแปลงเป็นเขตเวลาที่เฉพาะเจาะจงและคำนึงถึง DST (เวลาออมแสง) สิ่งต่อไปนี้ใช้ได้ดี:

CAST(DATEADD(S, [UnixTimestamp], '1970-01-01') AT TIME ZONE 'UTC' AT TIME ZONE 'Pacific Standard Time' AS Datetime)

หมายเหตุ: โซลูชันนี้ใช้ได้เฉพาะบน SQL Server 2016 ขึ้นไป (และ Azure)

ในการสร้างฟังก์ชัน:

CREATE FUNCTION dbo.ConvertUnixTime (@input INT)
RETURNS Datetime
AS BEGIN
    DECLARE @Unix Datetime

    SET @Unix = CAST(DATEADD(S, @Input, '1970-01-01') AT TIME ZONE 'UTC' AT TIME ZONE 'Pacific Standard Time' AS Datetime)

    RETURN @Unix
END

คุณสามารถเรียกใช้ฟังก์ชันดังนี้:

SELECT   dbo.ConvertUnixTime([UnixTimestamp])
FROM     YourTable
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.