แปลงคอลัมน์วันที่และเวลาจาก UTC เป็นเวลาท้องถิ่นในใบแจ้งยอดที่เลือก


208

ฉันกำลังใช้แบบสอบถามแบบใช้เลือกข้อมูล SQL สองสามรายการและต้องการแปลงคอลัมน์วันที่และเวลา UTC ของฉันเป็นเวลาท้องถิ่นเพื่อแสดงเป็นเวลาท้องถิ่นในผลการสืบค้นของฉัน หมายเหตุฉันไม่ต้องการทำการแปลงผ่านรหัส แต่เมื่อฉันทำแบบสอบถาม SQL ด้วยตนเองและสุ่มกับฐานข้อมูลของฉัน


คำถามนี้ดูเหมือนกับสถานการณ์ของคุณหรือไม่? stackoverflow.com/questions/3404646/…
Taryn East

คำตอบ:


322

คุณสามารถทำได้ดังนี้บน SQL Server 2008 หรือมากกว่า:

SELECT CONVERT(datetime, 
               SWITCHOFFSET(CONVERT(datetimeoffset, 
                                    MyTable.UtcColumn), 
                            DATENAME(TzOffset, SYSDATETIMEOFFSET()))) 
       AS ColumnInLocalTime
FROM MyTable

คุณยังสามารถทำ verbose น้อย:

SELECT DATEADD(mi, DATEDIFF(mi, GETUTCDATE(), GETDATE()), MyTable.UtcColumn) 
       AS ColumnInLocalTime
FROM MyTable

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

โปรดทราบว่าคำตอบนี้ไม่ได้คำนึงถึง DST หากคุณต้องการรวมการปรับ DST โปรดดูคำถาม SO ต่อไปนี้:

วิธีการสร้างฟังก์ชั่นการเริ่มต้นและสิ้นสุดเวลาออมแสงใน SQL Server


38
มีวิธีที่จะทำให้บัญชีนี้เพื่อการประหยัดเวลากลางวันหรือไม่?
Steve

15
ฉันไม่เห็นชื่อของเขตเวลาที่นี่จึงไม่ถูกต้อง เป็นความคิดที่ดีจริงๆที่จะสมมติว่าคุณสามารถแปลงเป็นเวลาท้องถิ่นได้โดยทำเลขคณิต
JonnyRaa

7
@MichaelGoldshteyn หากคุณมีเขตเวลาชดเชยคุณยังไม่ทราบว่าเขตเวลาแบบลอจิคัลคืออะไรเขตเวลาเป็นสิ่งที่สังคมและสามารถเปลี่ยนแปลงได้โดยรัฐบาลในจุดต่าง ๆ การชดเชยสำหรับเขตเวลาอาจแตกต่างกันในแต่ละช่วงเวลา / ประวัติ (ฤดูร้อนเป็นช่วงเวลาปกติ) คุณกำลังออฟเซ็ตเวลาด้วยออฟเซ็ตปัจจุบันจาก UTC ... จุดต่อไปคือการให้เขตเวลาของเซิร์ฟเวอร์ไม่ใช่ไคลเอ็นต์ซึ่งอาจเป็นปัญหาเพิ่มเติมหากคุณโฮสต์ในประเทศอื่น
JonnyRaa

4
@Niloofar คำตอบง่าย ๆ คือคุณไม่ควรทำ ควรจัดเก็บชุดข้อมูลใน UTC ทุกครั้ง (โดยเฉพาะอย่างยิ่งขึ้นอยู่กับนาฬิกาของเซิร์ฟเวอร์ฐานข้อมูลไม่ใช่ของเซิร์ฟเวอร์เว็บเซิร์ฟเวอร์แอปพลิเคชันและไม่ใช่นาฬิกาของลูกค้า) การแสดงวันที่และเวลานั้นเป็นฟังก์ชั่นสำหรับเลเยอร์ UI และมีหน้าที่ในการแปลงวันที่และเวลาเป็นรูปแบบที่คุณต้องการ (รวมถึงเขตเวลาหากจำเป็น)
Robert McKee

11
สำหรับทุกคนที่ใช้ sql azure วิธีการนี้จะไม่ทำงานเนื่องจากฟังก์ชั่นวันที่ / เวลาทั้งหมดกลับ UTC ดังนั้นการเปรียบเทียบ GETDATE () กับ GETUTCDATE () ไม่ได้ให้อะไรคุณเลยและผลลัพธ์ของคุณก็เหมือนกับที่คุณเริ่มต้น
Brian Surowiec

59

ฉันไม่พบตัวอย่างใด ๆ เหล่านี้มีประโยชน์ในการเรียกใช้เวลาเก็บข้อมูลเป็น UTC ไปยังวันที่และเวลาในเขตเวลาที่ระบุ (ไม่ใช่เขตเวลาของเซิร์ฟเวอร์เนื่องจากฐานข้อมูล Azure SQL ทำงานเป็น UTC) นี่คือวิธีที่ฉันจัดการ มันไม่ได้สวยงาม แต่มันง่ายและให้คำตอบที่ถูกต้องโดยไม่ต้องรักษาตารางอื่น ๆ :

select CONVERT(datetime, SWITCHOFFSET(dateTimeField, DATEPART(TZOFFSET, 
dateTimeField AT TIME ZONE 'Eastern Standard Time')))

4
ใช้งานได้ในปี 2559 เท่านั้นและใช้รีจิสตรีระบบ แต่ทางออกที่ดีสำหรับ Azure
Dan Cundy

2
อันนี้ใช้ได้กับเวลาสีฟ้าที่จัดเก็บใน UTC ขอบคุณครับ
Null

3
นี่คือรายการของสตริงที่คุณสามารถใช้สำหรับเขตเวลา: stackoverflow.com/a/7908482/631277
Matt Kemp

1
ถ้าใช้ SQL 2016 และAT TIME ZONEไวยากรณ์พิจารณาstackoverflow.com/a/44941536/112764 - คุณสามารถห่วงโซ่หลายแปลงด้วยกันโดยเพียงแค่การเชื่อมโยงหลายat time zone <blah>s
NateJ

3
นี่เป็นเรื่องแปลกเล็กน้อยเช่นกัน แต่การทดสอบขั้นพื้นฐานบางอย่างดูเหมือนว่าสิ่งนี้อาจใช้ได้เช่นกันdateTimeField AT TIME ZONE 'UTC' AT TIME ZONE 'Eastern Standard Time'- เพียงแค่ผูกมัดAT TIME ZONEข้อความ (@NateJ ที่กล่าวถึงข้างต้นนี้ผมเห็นตอนนี้)
เดวิด Mohundro

22

หากเวลาท้องถิ่นของคุณพูดEastern Standard Timeและคุณต้องการแปลงจาก UTC เป็นเวลานั้นใน Azure SQL และ SQL Server 2016 และสูงกว่าคุณสามารถทำได้:

SELECT YourUtcColumn AT TIME ZONE 'UTC' AT TIME ZONE 'Eastern Standard Time' AS
       LocalTime
FROM   YourTable

รายชื่อเต็มของเขตเวลาสามารถพบได้ด้วย:

SELECT * FROM sys.time_zone_info 

และใช่เขตเวลามีการตั้งชื่อไม่ดี - ถึงแม้ว่าจะเป็นการEastern Standard Timeประหยัดเวลากลางวันก็ตาม


2
เขตเวลาและออฟเซ็ตสามารถพบได้ใน SQL Server ที่นี่: SELECT * จาก sys.time_zone_info
rayzinnz

21

หากคุณต้องการการแปลงที่ไม่ใช่ตำแหน่งเซิร์ฟเวอร์ของคุณนี่คือฟังก์ชั่นที่ช่วยให้คุณผ่านการหักล้างมาตรฐานและบัญชีสำหรับ US Daylight Saving Times:

-- =============================================
-- Author:      Ron Smith
-- Create date: 2013-10-23
-- Description: Converts UTC to DST
--              based on passed Standard offset
-- =============================================
CREATE FUNCTION [dbo].[fn_UTC_to_DST]
(
    @UTC datetime,
    @StandardOffset int
)
RETURNS datetime
AS
BEGIN

    declare 
        @DST datetime,
        @SSM datetime, -- Second Sunday in March
        @FSN datetime  -- First Sunday in November

    -- get DST Range
    set @SSM = datename(year,@UTC) + '0314' 
    set @SSM = dateadd(hour,2,dateadd(day,datepart(dw,@SSM)*-1+1,@SSM))
    set @FSN = datename(year,@UTC) + '1107'
    set @FSN = dateadd(second,-1,dateadd(hour,2,dateadd(day,datepart(dw,@FSN)*-1+1,@FSN)))

    -- add an hour to @StandardOffset if @UTC is in DST range
    if @UTC between @SSM and @FSN
        set @StandardOffset = @StandardOffset + 1

    -- convert to DST
    set @DST = dateadd(hour,@StandardOffset,@UTC)

    -- return converted datetime
    return @DST

END

GO

2
รอนสมิ ธ ฉันรู้ว่านี่เป็นโพสต์เก่า แต่ฉันอยากรู้ว่ารหัส 0314 และ 1107 นั้นเป็นรหัสอะไรในการรับช่วง DST ดูเหมือนว่าจะเป็นวันรหัสยากซึ่งการเปลี่ยนแปลงเนื่องจาก DTS เหตุใดคุณจึงต้องใช้รหัสอย่างหนักเมื่อควรเป็นวันที่คำนวณเนื่องจากวันเปลี่ยนไปตามวันอาทิตย์ที่สองของเดือนมีนาคมและวันอาทิตย์แรกของเดือนพฤศจิกายน วันที่เขียนโค้ดยากจะทำให้โค้ดนี้มีข้อบกพร่องพื้นฐาน
Mike

2
คำถามที่ดี :) เป็นวันที่สูงสุดที่วันอาทิตย์ที่สองของเดือนมีนาคมและวันอาทิตย์แรกของเดือนพฤศจิกายน บรรทัดต่อไปนี้ตั้งค่าตัวแปรเป็นวันที่แท้จริง
รอนสมิ ธ

8

การใช้โอกาสใหม่ของ SQL Server 2016:

CREATE FUNCTION ToLocalTime(@dtUtc datetime, @timezoneId nvarchar(256))
RETURNS datetime
AS BEGIN

return @dtUtc AT TIME ZONE 'UTC' AT TIME ZONE @timezoneId

/* -- second way, faster

return SWITCHOFFSET(@dtUtc , DATENAME(tz, @dtUtc AT TIME ZONE @timezoneId))

*/

/* -- third way

declare @dtLocal datetimeoffset
set @dtLocal = @dtUtc AT TIME ZONE @timezoneId
return dateadd(minute, DATEPART (TZoffset, @dtLocal), @dtUtc)

*/

END
GO

แต่โพรซีเดอร์ clr ทำงานได้เร็วขึ้น 5 เท่า: '- (

ให้ความสนใจว่าออฟเซ็ตสำหรับเขตเวลาหนึ่งสามารถเปลี่ยนเป็นฤดูหนาวหรือฤดูร้อน ตัวอย่างเช่น

select cast('2017-02-08 09:00:00.000' as datetime) AT TIME ZONE 'Eastern Standard Time'
select cast('2017-08-08 09:00:00.000' as datetime) AT TIME ZONE 'Eastern Standard Time'

ผล:

2017-02-08 09:00:00.000 -05:00
2017-08-08 09:00:00.000 -04:00

คุณไม่สามารถเพิ่มออฟเซ็ตคงที่ได้


5

หากเปิดใช้งาน CLR ในฐานข้อมูลของคุณเป็นตัวเลือกเช่นเดียวกับการใช้เขตเวลาของเซิร์ฟเวอร์ sql ก็สามารถเขียนใน. Net ได้อย่างง่ายดาย

public partial class UserDefinedFunctions
{
    [Microsoft.SqlServer.Server.SqlFunction]
    public static SqlDateTime fn_GetLocalFromUTC(SqlDateTime UTC)
    {
        if (UTC.IsNull)
            return UTC;

        return new SqlDateTime(UTC.Value.ToLocalTime());
    }
}

ค่าวันที่และเวลา UTC จะเข้าและค่าวันที่และเวลาแบบโลคอลที่สัมพันธ์กับเซิร์ฟเวอร์จะออกมา ค่า Null ส่งคืนค่าว่าง


5

ไม่มีวิธีง่ายๆในการทำเช่นนี้ในวิธีที่ถูกต้องและทั่วไป

ก่อนอื่นจะต้องเข้าใจว่าการชดเชยขึ้นอยู่กับวันที่ถาม, เขตเวลาและเวลา GetDate()-GetUTCDateให้ออฟเซ็ตวันนี้เฉพาะคุณที่ TZ ของเซิร์ฟเวอร์ซึ่งไม่เกี่ยวข้อง

ฉันเห็นโซลูชันการทำงานเพียงสองข้อเท่านั้นและฉันค้นหามาก

1) ฟังก์ชั่น SQL แบบกำหนดเองที่มีตารางฐานข้อมูลจำนวนหนึ่งเช่นเขตเวลาและกฎ DST ต่อ TZ ทำงานได้ แต่ไม่หรูหรามาก ฉันไม่สามารถโพสต์ได้เนื่องจากฉันไม่ได้เป็นเจ้าของรหัส

แก้ไข: นี่คือตัวอย่างของวิธีการนี้ https://gist.github.com/drumsta/16b79cee6bc195cd89c8

2) เพิ่มแอสเซมบลี. net ลงใน db, .Net สามารถทำได้อย่างง่ายดาย สิ่งนี้ทำงานได้ดีมาก แต่ข้อเสียคือคุณต้องกำหนดค่าพารามิเตอร์หลายตัวในระดับเซิร์ฟเวอร์และการกำหนดค่าจะแตกง่ายเช่นถ้าคุณกู้คืนฐานข้อมูล ฉันใช้วิธีนี้ แต่ฉันไม่สามารถโพสต์ได้เพราะฉันไม่ได้เป็นเจ้าของรหัส


4

สิ่งเหล่านี้ไม่ได้ผลสำหรับฉัน แต่สิ่งนี้ด้านล่างใช้งานได้ 100% หวังว่านี้จะช่วยให้ผู้อื่นพยายามแปลงมันเหมือนฉัน

CREATE FUNCTION [dbo].[fn_UTC_to_EST]
(
    @UTC datetime,
    @StandardOffset int
)
RETURNS datetime
AS
BEGIN

declare 
    @DST datetime,
    @SSM datetime, -- Second Sunday in March
    @FSN datetime  -- First Sunday in November
-- get DST Range
set @SSM = DATEADD(dd,7 + (6-(DATEDIFF(dd,0,DATEADD(mm,(YEAR(GETDATE())-1900) * 12 + 2,0))%7)),DATEADD(mm,(YEAR(GETDATE())-1900) * 12 + 2,0))+'02:00:00' 
set @FSN = DATEADD(dd, (6-(DATEDIFF(dd,0,DATEADD(mm,(YEAR(GETDATE())-1900) * 12 + 10,0))%7)),DATEADD(mm,(YEAR(GETDATE())-1900) * 12 + 10,0)) +'02:00:00'

-- add an hour to @StandardOffset if @UTC is in DST range
if @UTC between @SSM and @FSN
    set @StandardOffset = @StandardOffset + 1

-- convert to DST
set @DST = dateadd(hour,@StandardOffset,@UTC)

-- return converted datetime
return @DST

END

1
นี่ควรเป็นคำตอบที่ยอมรับได้ สิ่งเดียวที่ฉันจะเปลี่ยนคือชื่อตามที่แสดงถึงเวลา EST เมื่อจริง ๆ แล้วมันเป็นเวลาท้องถิ่นและ StandardOffset จะถูกส่งผ่านเป็นพารามิเตอร์
Greg Gum

เห็นด้วยคำตอบที่ดีที่สุด ... แต่แทนที่จะต้องผ่านการชดเชยเป็นพารามิเตอร์ฉันเพิ่มสิ่งนี้ภายในเนื้อหาของฟังก์ชั่น:declare @StandardOffset int = datediff (hh, GETUTCDATE(), GETDATE())
Tom Warfield

ติดตาม suggetion ก่อนหน้าของฉัน - หากคุณคำนวณ @StandardOffset คุณไม่จำเป็นต้องทำการแก้ไข DST
Tom Warfield

3

ต่อไปนี้เป็นรุ่นที่มีการบัญชีสำหรับการปรับเวลาตามฤดูกาล UTC ชดเชยและไม่ได้ล็อคไว้ในปีที่เฉพาะเจาะจง

---------------------------------------------------------------------------------------------------
--Name:     udfToLocalTime.sql
--Purpose:  To convert UTC to local US time accounting for DST
--Author:   Patrick Slesicki
--Date:     3/25/2014
--Notes:    Works on SQL Server 2008R2 and later, maybe SQL Server 2008 as well.
--          Good only for US States observing the Energy Policy Act of 2005.
--          Function doesn't apply for years prior to 2007.
--          Function assumes that the 1st day of the week is Sunday.
--Tests:        
--          SELECT dbo.udfToLocalTime('2014-03-09 9:00', DEFAULT)
--          SELECT dbo.udfToLocalTime('2014-03-09 10:00', DEFAULT)
--          SELECT dbo.udfToLocalTime('2014-11-02 8:00', DEFAULT)
--          SELECT dbo.udfToLocalTime('2014-11-02 9:00', DEFAULT)
---------------------------------------------------------------------------------------------------
ALTER FUNCTION udfToLocalTime
    (
    @UtcDateTime    AS DATETIME
    ,@UtcOffset     AS INT = -8 --PST
    )
RETURNS DATETIME
AS 
BEGIN
    DECLARE 
        @PstDateTime    AS DATETIME
        ,@Year          AS CHAR(4)
        ,@DstStart      AS DATETIME
        ,@DstEnd        AS DATETIME
        ,@Mar1          AS DATETIME
        ,@Nov1          AS DATETIME
        ,@MarTime       AS TIME
        ,@NovTime       AS TIME
        ,@Mar1Day       AS INT
        ,@Nov1Day       AS INT
        ,@MarDiff       AS INT
        ,@NovDiff       AS INT

    SELECT
        @Year       = YEAR(@UtcDateTime)
        ,@MarTime   = CONVERT(TIME, DATEADD(HOUR, -@UtcOffset, '1900-01-01 02:00'))
        ,@NovTime   = CONVERT(TIME, DATEADD(HOUR, -@UtcOffset - 1, '1900-01-01 02:00'))
        ,@Mar1      = CONVERT(CHAR(16), @Year + '-03-01 ' + CONVERT(CHAR(5), @MarTime), 126)
        ,@Nov1      = CONVERT(CHAR(16), @Year + '-11-01 ' + CONVERT(CHAR(5), @NovTime), 126)
        ,@Mar1Day   = DATEPART(WEEKDAY, @Mar1)
        ,@Nov1Day   = DATEPART(WEEKDAY, @Nov1)

    --Get number of days between Mar 1 and DST start date
    IF @Mar1Day = 1 SET @MarDiff = 7
    ELSE SET @MarDiff = 15 - @Mar1Day

    --Get number of days between Nov 1 and DST end date
    IF @Nov1Day = 1 SET @NovDiff = 0
    ELSE SET @NovDiff = 8 - @Nov1Day

    --Get DST start and end dates
    SELECT 
        @DstStart   = DATEADD(DAY, @MarDiff, @Mar1)
        ,@DstEnd    = DATEADD(DAY, @NovDiff, @Nov1)

    --Change UTC offset if @UtcDateTime is in DST Range
    IF @UtcDateTime >= @DstStart AND @UtcDateTime < @DstEnd SET @UtcOffset = @UtcOffset + 1

    --Get Conversion
    SET @PstDateTime = DATEADD(HOUR, @UtcOffset, @UtcDateTime)
    RETURN @PstDateTime
END
GO

3

ฉันพบวิธีปิดฟังก์ชั่นที่ช้าเกินไปเมื่อมีข้อมูลจำนวนมาก ดังนั้นฉันจึงผ่านการเข้าร่วมฟังก์ชั่นตารางที่จะช่วยให้การคำนวณชั่วโมงต่างกัน มันเป็นส่วน datetime โดยทั่วไปกับการชดเชยชั่วโมง ปีจะเป็น 4 แถว ดังนั้นฟังก์ชั่นตาราง

dbo.fn_getTimeZoneOffsets('3/1/2007 7:00am', '11/5/2007 9:00am', 'EPT')

จะกลับตารางนี้:

startTime          endTime   offset  isHr2
3/1/07 7:00     3/11/07 6:59    -5    0
3/11/07 7:00    11/4/07 6:59    -4    0
11/4/07 7:00    11/4/07 7:59    -5    1
11/4/07 8:00    11/5/07 9:00    -5    0

มันบัญชีสำหรับการออมแสง ตัวอย่างของวิธีการที่จะใช้เป็นด้านล่างและบล็อกโพสต์เต็มรูปแบบที่นี่

select mt.startTime as startUTC, 
    dateadd(hh, tzStart.offset, mt.startTime) as startLocal, 
    tzStart.isHr2
from MyTable mt 
inner join dbo.fn_getTimeZoneOffsets(@startViewUTC, @endViewUTC, @timeZone)  tzStart
on mt.startTime between tzStart.startTime and tzStart.endTime

ดูเหมือนจะไม่พิจารณา DST ในวิธีที่ถูกต้อง ไม่แน่ใจว่าคุณคิดว่ามี แต่สหรัฐอเมริกาเท่านั้นและกฎ DST นั้นไม่มีวันเปลี่ยนแปลง
vikjon0

@ vikjon0 ใช่โครงการที่ฉันสร้างขึ้นนี้มีโซนเวลาในสหรัฐฯเท่านั้น
JBrooks


1

คำตอบของรอนมีข้อผิดพลาด มันใช้เวลาท้องถิ่น 2:00 น. ซึ่งจำเป็นต้องมีค่าเทียบเท่า UTC ฉันมีคะแนนชื่อเสียงไม่เพียงพอที่จะแสดงความคิดเห็นต่อคำตอบของ Ron ดังนั้นรุ่นที่แก้ไขจะปรากฏด้านล่าง

-- =============================================
-- Author:      Ron Smith
-- Create date: 2013-10-23
-- Description: Converts UTC to DST
--              based on passed Standard offset
-- =============================================
CREATE FUNCTION [dbo].[fn_UTC_to_DST]
(
    @UTC datetime,
    @StandardOffset int
)
RETURNS datetime
AS
BEGIN

declare 
    @DST datetime,
    @SSM datetime, -- Second Sunday in March
    @FSN datetime  -- First Sunday in November
-- get DST Range
set @SSM = datename(year,@UTC) + '0314' 
set @SSM = dateadd(hour,2 - @StandardOffset,dateadd(day,datepart(dw,@SSM)*-1+1,@SSM))
set @FSN = datename(year,@UTC) + '1107'
set @FSN = dateadd(second,-1,dateadd(hour,2 - (@StandardOffset + 1),dateadd(day,datepart(dw,@FSN)*-1+1,@FSN)))

-- add an hour to @StandardOffset if @UTC is in DST range
if @UTC between @SSM and @FSN
    set @StandardOffset = @StandardOffset + 1

-- convert to DST
set @DST = dateadd(hour,@StandardOffset,@UTC)

-- return converted datetime
return @DST

END

มันเป็นคุณสมบัติไม่ใช่ข้อผิดพลาด :) ส่วนใหญ่ของสหรัฐอเมริกาเริ่มต้นการปรับเวลาตามฤดูกาลเวลา 2:00 น. en.wikipedia.org/wiki/Daylight_saving_time
Ron Smith

@RonSmith ใช่เวลา 2:00 น. ตามเวลาท้องถิ่นซึ่งเราต้องแปลงเป็น UTC เพื่อตรวจสอบว่าเวลา UTC ที่ระบุอยู่ในช่วง DST หรือไม่
jlspublic

1

การประทับเวลา UNIX เป็นเพียงจำนวนวินาทีระหว่างวันที่ใดวันหนึ่งกับ Unix Epoch

SELECT DATEDIFF (วินาที, {d '1970-01-01'}, GETDATE ()) // นี่จะส่งคืนการประทับเวลา UNIX ในเซิร์ฟเวอร์ SQL

คุณสามารถสร้างฟังก์ชั่นสำหรับเวลาวันที่ท้องถิ่นเป็น Unix UTC โดยใช้ฟังก์ชั่น Country Offset เพื่อ Unix Time Stamp ในเซิร์ฟเวอร์ SQL


1

มันง่ายมาก ลองใช้วิธีนี้กับ Azure SQL Server:

SELECT YourDateTimeColumn AT TIME ZONE 'Eastern Standard Time' FROM YourTable

สำหรับเซิร์ฟเวอร์ SQL ในเครื่อง:

SELECT CONVERT(datetime2, SWITCHOFFSET(CONVERT(datetimeoffset, gETDATE()), DATENAME(TzOffset, gETDATE() AT TIME ZONE 'Eastern Standard Time'))) FROM YourTable

1
จะเกิดอะไรขึ้นกับสิ่งนี้ในช่วงเวลากลางวัน (เนื่องจากโซนเวลาระบุว่า "เวลามาตรฐานตะวันออก")
Mark

1

สำหรับ Azure SQL และ@@Version> = SQL Server 2016 AT TIME ZONEผู้ใช้ด้านล่างนี้เป็นฟังก์ชั่นอย่างง่ายโดยใช้

CREATE FUNCTION [dbo].[Global_Convert_UTCTimeTo_LocalTime]
(
   @LocalTimeZone        VARCHAR(50),
   @UTCDateTime          DATETIME
)
RETURNS DATETIME
AS
BEGIN
   DECLARE @ConvertedDateTime DATETIME;

   SELECT @ConvertedDateTime = @UTCDateTime AT TIME ZONE 'UTC' AT TIME ZONE @LocalTimeZone
   RETURN @ConvertedDateTime

END
GO

สำหรับประเภทของค่าที่@LocalTimeZoneสามารถรับได้โปรดไปที่ลิงค์นี้หรือไปที่KEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones


0

เพื่อเป็นการเตือน - หากคุณจะใช้สิ่งต่อไปนี้ (ให้สังเกตมิลลิวินาทีแทนนาที):

    SELECT DATEADD(ms, DATEDIFF(ms, GETUTCDATE(), GETDATE()), MyTable.UtcColumn) 
    AS ColumnInLocalTime
    FROM MyTable

โปรดทราบว่าส่วน DATEDIFF จะไม่ส่งคืนหมายเลขเดิมเสมอไป ดังนั้นอย่าใช้เพื่อเปรียบเทียบ DateTimes ลงไปมิลลิวินาที


0

ฉันพบว่าฟังก์ชันนี้เร็วกว่าโซลูชันอื่น ๆ ที่ใช้ตารางหรือลูปแยกกัน มันเป็นเพียงคำสั่งกรณีพื้นฐาน ระบุว่าทุกเดือนระหว่างเดือนเมษายนถึงตุลาคมจะมีการชดเชย 4 ชั่วโมง (เวลาตะวันออก) เราเพียงแค่ต้องเพิ่มอีกสองสามบรรทัดกรณีในวันที่ มิฉะนั้นค่าชดเชยคือ -5 ชั่วโมง

นี่เป็นเฉพาะการแปลงจาก UTC เป็นเวลาตะวันออก แต่สามารถเพิ่มฟังก์ชันโซนเวลาเพิ่มเติมได้ตามต้องการ

USE [YourDatabaseName]
GO

/****** Object:  UserDefinedFunction [dbo].[ConvertUTCtoEastern]    Script Date: 11/2/2016 5:21:52 PM ******/
SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO


CREATE FUNCTION [dbo].[ConvertUTCtoEastern]
(
@dtStartDate DATETIME
)
RETURNS DATETIME
AS
BEGIN
DECLARE @Working DATETIME
DECLARE @Returned DATETIME

SET @Working = @dtStartDate
SET @Working = 
case when month(@Working) between 4 and 10 then dateadd(HH,-4,@Working) 
     when @Working between '2017-03-12' and '2017-11-05' then dateadd(HH,-4,@Working) 
     when @Working between '2016-03-13' and '2016-11-06' then dateadd(HH,-4,@Working) 
     when @Working between '2015-03-08' and '2015-11-01' then dateadd(HH,-4,@Working) 
     when @Working between '2014-03-09' and '2014-11-02' then dateadd(HH,-4,@Working) 
     when @Working between '2013-03-10' and '2013-11-03' then dateadd(HH,-4,@Working) 
     when @Working between '2012-03-11' and '2012-11-04' then dateadd(HH,-4,@Working) 
else dateadd(HH,-5,@Working) end

SET @Returned = @Working

RETURN @Returned

END


GO

0

สิ่งนี้จะสามารถรับเวลาเซิร์ฟเวอร์ด้วย DST

declare @dt datetime
set @dt = getutcdate() -- GMT equivalent

sysdatetimeoffset ใช้เวลา DST เข้าบัญชี

select [InputTime] = @dt
       , [LocalTime2] = dateadd(mi, datediff(mi, sysdatetimeoffset(),getdate()), @dt) 

0

ฟังก์ชั่นแรก: กำหนดค่าสำหรับเขตเวลาอิตาลี (+1, +2), สลับวันที่: วันอาทิตย์สุดท้ายของเดือนมีนาคมและตุลาคม, ส่งคืนความแตกต่างระหว่างเขตเวลาปัจจุบันและวันที่เป็นพารามิเตอร์

Returns:
current timezone < parameter timezone ==> +1
current timezone > parameter timezone ==> -1
else 0

รหัสคือ:

CREATE FUNCTION [dbo].[UF_ADJUST_OFFSET]
(
    @dt_utc datetime2(7)
)
RETURNS INT
AS
BEGIN


declare @month int,
        @year int,
        @current_offset int,
        @offset_since int,
        @offset int,
        @yearmonth varchar(8),
        @changeoffsetdate datetime2(7)

declare @lastweek table(giorno datetime2(7))

select @current_offset = DATEDIFF(hh, GETUTCDATE(), GETDATE())

select @month = datepart(month, @dt_utc)

if @month < 3 or @month > 10 Begin Set @offset_since = 1 Goto JMP End

if @month > 3 and @month < 10 Begin Set @offset_since = 2 Goto JMP End

--If i'm here is march or october
select @year = datepart(yyyy, @dt_utc)

if @month = 3
Begin

Set @yearmonth = cast(@year as varchar) + '-03-'

Insert Into @lastweek Values(@yearmonth + '31 03:00:00.000000'),(@yearmonth + '30 03:00:00.000000'),(@yearmonth + '29 03:00:00.000000'),(@yearmonth + '28 03:00:00.000000'),
                         (@yearmonth + '27 03:00:00.000000'),(@yearmonth + '26 03:00:00.000000'),(@yearmonth + '25 03:00:00.000000')

--Last week of march
Select @changeoffsetdate = giorno From @lastweek Where  datepart(weekday, giorno) = 1

    if @dt_utc < @changeoffsetdate 
    Begin 
        Set @offset_since = 1 
    End Else Begin
        Set @offset_since = 2
    End
End

if @month = 10
Begin

Set @yearmonth = cast(@year as varchar) + '-10-'

Insert Into @lastweek Values(@yearmonth + '31 03:00:00.000000'),(@yearmonth + '30 03:00:00.000000'),(@yearmonth + '29 03:00:00.000000'),(@yearmonth + '28 03:00:00.000000'),
                         (@yearmonth + '27 03:00:00.000000'),(@yearmonth + '26 03:00:00.000000'),(@yearmonth + '25 03:00:00.000000')

--Last week of october
Select @changeoffsetdate = giorno From @lastweek Where  datepart(weekday, giorno) = 1

    if @dt_utc > @changeoffsetdate 
    Begin 
        Set @offset_since = 1 
    End Else Begin
        Set @offset_since = 2
    End
End

JMP:

if @current_offset < @offset_since Begin
    Set @offset = 1
End Else if @current_offset > @offset_since Set @offset = -1 Else Set @offset = 0

Return @offset

END

จากนั้นฟังก์ชั่นที่แปลงวันที่

CREATE FUNCTION [dbo].[UF_CONVERT]
(
    @dt_utc datetime2(7)
)
RETURNS datetime
AS
BEGIN

    declare @offset int


    Select @offset = dbo.UF_ADJUST_OFFSET(@dt_utc)

    if @dt_utc >= '9999-12-31 22:59:59.9999999'
        set @dt_utc = '9999-12-31 23:59:59.9999999'
    Else
        set @dt_utc = (SELECT DATEADD(mi, DATEDIFF(mi, GETUTCDATE(), GETDATE()), @dt_utc) )

    if @offset <> 0
        Set @dt_utc = dateadd(hh, @offset, @dt_utc)

    RETURN @dt_utc

END

0

- รับเวลามาตรฐานอินเดียจาก utc

CREATE FUNCTION dbo.getISTTime
(
@UTCDate datetime
)
RETURNS datetime
AS
BEGIN

    RETURN dateadd(minute,330,@UTCDate)

END
GO

0

สิ่งนี้สามารถทำได้โดยไม่มีฟังก์ชั่น รหัสด้านล่างจะแปลงเวลา UTC เป็นการบัญชีเวลาบนภูเขาเพื่อการประหยัดเวลากลางวัน ปรับตัวเลข -6 และ -7 ทั้งหมดให้สอดคล้องกับเขตเวลาของคุณ (เช่นสำหรับ EST คุณจะปรับเป็น -4 และ -5 ตามลำดับ)

--Adjust a UTC value, in the example the UTC field is identified as UTC.Field, to account for daylight savings time when converting out of UTC to Mountain time.
CASE
    --When it's between March and November, it is summer time which is -6 from UTC
    WHEN MONTH ( UTC.Field ) > 3 AND MONTH ( UTC.Field ) < 11 
        THEN DATEADD ( HOUR , -6 , UTC.Field )
    --When its March and the day is greater than the 14, you know it's summer (-6)
    WHEN MONTH ( UTC.Field ) = 3
        AND DATEPART ( DAY , UTC.Field ) >= 14 
        THEN
            --However, if UTC is before 9am on that Sunday, then it's before 2am Mountain which means it's still Winter daylight time.
            CASE 
                WHEN DATEPART ( WEEKDAY , UTC.Field ) = 1 
                    AND UTC.Field < '9:00'
                    --Before 2am mountain time so it's winter, -7 hours for Winter daylight time
                    THEN DATEADD ( HOUR , -7 , UTC.Field )
                --Otherwise -6 because it'll be after 2am making it Summer daylight time
                ELSE DATEADD ( HOUR , -6 , UTC.Field )
            END
    WHEN MONTH ( UTC.Field ) = 3
        AND ( DATEPART ( WEEKDAY , UTC.Field ) + 7 ) <= DATEPART ( day , UTC.Field ) 
        THEN 
            --According to the date, it's moved onto Summer daylight, but we need to account for the hours leading up to 2am if it's Sunday
            CASE 
                WHEN DATEPART ( WEEKDAY , UTC.Field ) = 1 
                    AND UTC.Field < '9:00'
                    --Before 9am UTC is before 2am Mountain so it's winter Daylight, -7 hours
                    THEN DATEADD ( HOUR , -7 , UTC.Field )
                --Otherwise, it's summer daylight, -6 hours
                ELSE DATEADD ( HOUR , -6 , UTC.Field )
            END
    --When it's November and the weekday is greater than the calendar date, it's still Summer so -6 from the time
    WHEN MONTH ( UTC.Field ) = 11
        AND DATEPART ( WEEKDAY , UTC.Field ) > DATEPART ( DAY , UTC.Field ) 
        THEN DATEADD ( HOUR , -6 , UTC.Field )
    WHEN MONTH ( UTC.Field ) = 11
        AND DATEPART ( WEEKDAY , UTC.Field ) <= DATEPART ( DAY , UTC.Field ) 
            --If the weekday is less than or equal to the calendar day it's Winter daylight but we need to account for the hours leading up to 2am.
            CASE 
                WHEN DATEPART ( WEEKDAY , UTC.Field ) = 1 
                    AND UTC.Field < '8:00'
                    --If it's before 8am UTC and it's Sunday in the logic outlined, then it's still Summer daylight, -6 hours
                    THEN DATEADD ( HOUR , -6 , UTC.Field )
                --Otherwise, adjust for Winter daylight at -7
                ELSE DATEADD ( HOUR , -7 , UTC.Field )
            END
    --If the date doesn't fall into any of the above logic, it's Winter daylight, -7
    ELSE
        DATEADD ( HOUR , -7 , UTC.Field )
END

0

คุณต้องจัดรูปแบบสตริงรวมทั้งแปลงเป็นเวลาที่ถูกต้อง ในกรณีนี้ฉันต้องการเวลาซูลู

Declare @Date datetime;
Declare @DateString varchar(50);
set @Date = GETDATE(); 
declare @ZuluTime datetime;

Declare @DateFrom varchar (50);
Declare @DateTo varchar (50);
set @ZuluTime = DATEADD(second, DATEDIFF(second, GETDATE(), GETUTCDATE()), @Date);
set @DateString =  FORMAT(@ZuluTime, 'yyyy-MM-ddThh:mm:ssZ', 'en-US' )  
select @DateString;

0

วิธีที่ดีที่สุดสำหรับ Oracle:

ด้วยฮาร์ดโค้ดวันที่:

SELECT TO_CHAR(CAST((FROM_TZ(CAST(TO_DATE('2018-10-27 21:00', 'YYYY-MM-DD HH24:MI') AS TIMESTAMP), 'UTC') AT  TIME ZONE 'EET') AS DATE), 'YYYY-MM-DD HH24:MI') UTC_TO_EET FROM DUAL

Result: 2018-10-28 00:00

ด้วยชื่อคอลัมน์และตาราง:

SELECT TO_CHAR(CAST((FROM_TZ(CAST(COLUMN_NAME AS TIMESTAMP), 'UTC') AT  TIME ZONE 'EET') AS DATE), 'YYYY-MM-DD HH24:MI') UTC_TO_EET FROM TABLE_NAME

0

ฉันมีรหัสเพื่อดำเนินการ UTC เป็นเวลาท้องถิ่นและท้องถิ่นเป็นเวลา UTC ซึ่งอนุญาตให้มีการแปลงโดยใช้รหัสเช่นนี้

DECLARE @usersTimezone VARCHAR(32)='Europe/London'
DECLARE @utcDT DATETIME=GetUTCDate()
DECLARE @userDT DATETIME=[dbo].[funcUTCtoLocal](@utcDT, @usersTimezone)

และ

DECLARE @usersTimezone VARCHAR(32)='Europe/London'
DECLARE @userDT DATETIME=GetDate()
DECLARE @utcDT DATETIME=[dbo].[funcLocaltoUTC](@userDT, @usersTimezone)

ฟังก์ชั่นสามารถรองรับเขตเวลาทั้งหมดหรือบางส่วนใน IANA / TZDB ตามที่จัดเตรียมโดย NodaTime - ดูรายการทั้งหมดได้ที่https://nodatime.org/TimeZones

โปรดทราบว่ากรณีการใช้งานของฉันหมายความว่าฉันต้องมีหน้าต่าง 'ปัจจุบัน' เท่านั้นทำให้สามารถแปลงเวลาได้ภายในช่วงประมาณ +/- 5 ปีนับจากนี้ ซึ่งหมายความว่าวิธีที่ฉันใช้อาจไม่เหมาะสำหรับคุณหากคุณต้องการช่วงเวลาที่กว้างมากเนื่องจากวิธีที่จะสร้างรหัสสำหรับแต่ละช่วงเวลาในช่วงวันที่ที่กำหนด

โครงการอยู่ใน GitHub: https://github.com/elliveny/SQLServerTimeConversion

สิ่งนี้สร้างโค้ดฟังก์ชัน SQL ตามตัวอย่างนี้


0

ถ้าคุณเก็บข้อมูลเป็นวันที่ UTC ในฐานข้อมูลคุณสามารถทำอะไรง่าย ๆ

select 
 [MyUtcDate] + getdate() - getutcdate()
from [dbo].[mytable]

นี่คือมันเป็นแบบโลคัลเสมอจากจุดเซิร์ฟเวอร์และคุณไม่คลาดเคลื่อนกับ AT TIME ZONE 'your time zone name'หากฐานข้อมูลของคุณถูกย้ายไปยังโซนเวลาอื่นเช่นการติดตั้งไคลเอนต์โซนเวลาที่กำหนดรหัสยากอาจกัดคุณ


0

ใน postgres มันทำงานได้ดีมาก .. บอกเซิร์ฟเวอร์เวลาที่บันทึกเวลา 'utc' แล้วขอให้แปลงเป็นเขตเวลาเฉพาะในกรณีนี้ 'Brazil / East'

quiz_step_progresses.created_at  at time zone 'utc' at time zone 'Brazil/East'

รับรายการเขตเวลาทั้งหมดด้วยตัวเลือกต่อไปนี้

select * from pg_timezone_names;

ดูรายละเอียดได้ที่นี่

https://popsql.com/learn-sql/postgresql/how-to-convert-utc-to-local-time-zone-in-postgresql


-1

ต่อไปนี้เป็นวิธีที่ง่ายกว่าที่ใช้ dst ในบัญชี

CREATE FUNCTION [dbo].[UtcToLocal] 
(
    @p_utcDatetime DATETIME 
)
RETURNS DATETIME
AS
BEGIN
    RETURN DATEADD(MINUTE, DATEDIFF(MINUTE, GETUTCDATE(), @p_utcDatetime), GETDATE())
END

6
นี่ไม่ได้คำนึงถึง DST ลองดูสิSELECT DATEADD(MINUTE, DATEDIFF(MINUTE, GETUTCDATE(), '20150101'), GETDATE()). ขณะนี้ฉันอยู่ใน CEST (UTC + 2) แต่ DST จะไม่มีผลบังคับใช้ในวันปีใหม่ดังนั้นคำตอบที่ถูกต้องสำหรับฉันคือ 1 มกราคม 2558 01:00 คำตอบของคุณเช่นเดียวกับคำตอบที่ยอมรับส่งคืน 1 มกราคม 2558 02:00
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.