Select deyiminde Tarih Saat sütununu UTC'den yerel saate dönüştürme


208

Birkaç SQL seçme sorguları yapıyorum ve UTC datetime sütun benim sorgu sonuçlarında yerel saat olarak görüntülenecek yerel saate dönüştürmek istiyorum. Not, ben kod üzerinden bu dönüşüm yapmak değil, benim veritabanlarına karşı manuel ve rastgele SQL sorguları yaparken arıyorum.


Bu soru sizin durumunuza benziyor mu? stackoverflow.com/questions/3404646/…
Taryn East

Yanıtlar:


322

Bunu SQL Server 2008 veya sonraki sürümlerde aşağıdaki gibi yapabilirsiniz:

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

Daha az ayrıntılı da yapabilirsiniz:

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

Ne yaparsan yap, yok kullanmak- operasyon atom olmadığı için, tarih çıkarmak ve vesilesiyle nedeniyle sistem datetime ve yerel datetime arasındaki yarış koşullarına belirsiz sonuçlar elde edecek farklı zamanlarda denetleniyor (yani olmayan atomik) .

Bu yanıtın DST'yi dikkate almadığını lütfen unutmayın. Bir DST ayarlaması eklemek istiyorsanız, lütfen aşağıdaki SO sorusuna da bakın:

SQL Server'da Yaz Saati uygulaması Başlat ve Sonlandır işlevi nasıl oluşturulur


38
Bu hesabı gün ışığından tasarruf etmek için yapmanın bir yolu var mı?
Steve

15
Burada saat dilimi adını göremiyorum, bu yüzden bu yanlış. Aritmetik yaparak yerel saate dönüştürebileceğinizi varsaymak gerçekten kötü bir fikir
JonnyRaa

7
@MichaelGoldshteyn bir saat dilimi ofsetiniz varsa, hala bir zamanın hangi mantıksal saat diliminde olduğunu bilmiyorsunuz. Zaman dilimleri sosyal şeylerdir ve hükümetler tarafından farklı noktalarda değiştirilebilir. Bir saat dilimi için ofset, zaman / tarihin farklı noktalarında farklı olabilir (yaz saati yaygındır). UTC'den şu anki ofset ile bir zamanı dengeliyorsunuz ... bir başka nokta, bu, istemciye değil, sunucunun saat dilimini verecektir, bu da farklı bir ülkede ev sahipliği yapıyorsanız daha fazla sorun olabilir.
JonnyRaa

4
@Niloofar Basit cevap, yapmamanız ve yapmamanızdır. Tarihler her zaman UTC'de saklanmalıdır (tercihen web sunucusunun, uygulama sunucusunun ve kesinlikle istemcinin saatinin değil, veritabanı sunucusunun saatine bağlı olarak). Bu tarih saatini göstermek kullanıcı arabirimi katmanı için bir işlevdir ve tarih saatini istediğiniz formata dönüştürmekle sorumludur (gerekirse saat dilimi dahil).
Robert McKee

11
Sql azure kullanan herkes için, tarih / saat işlevlerinin tümü UTC döndürdüğü için bu yaklaşım işe yaramaz, bu nedenle GETDATE () ile GETUTCDATE () karşılaştırılması size çalışmak için hiçbir şey vermez ve sonucunuz başladığınızla aynıdır.
Brian Surowiec

59

Belirtilen bir saat diliminde (tarihin Azure SQL veritabanları UTC olarak çalıştığı için DEĞİL sunucunun saat dilimi) UTC olarak depolanan bir datetime almada bu örneğin hiçbirini bulamadım. Ben böyle idare ettim. Zarif değil ama basit ve diğer tabloları tutmadan size doğru cevabı veriyor:

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

4
Yalnızca 2016 için çalışır ve sistem kayıt defterini kullanır. Ancak Azure için harika bir çözüm.
Dan Cundy

2
Bu, UTC'de depolanan masmavi süreler için çalışıyor, teşekkürler çocuklar
Null

3
Zaman dilimleri için kullanabileceğiniz dizelerin listesi: stackoverflow.com/a/7908482/631277
Matt Kemp

1
SQL 2016 ve kullanılıyorsa AT TIME ZONEsözdizimi, düşünün stackoverflow.com/a/44941536/112764 - yapabilirsiniz zincir birden çok dönüşüm birlikte basitçe birden birleştirerek at time zone <blah>s.
NateJ

3
Bu da biraz tuhaf, ama bazı çok temel testler de işe yarayabilir dateTimeField AT TIME ZONE 'UTC' AT TIME ZONE 'Eastern Standard Time'- sadece AT TIME ZONEifadeleri zincirlemek . (@NateJ, şimdi gördüğüm yukarıda bahsetti)
David Mohundro

22

Yerel tarih saatiniz söyleniyorsa Eastern Standard Timeve UTC'den buna dönüştürmek istiyorsanız, Azure SQL ve SQL Server 2016 ve üstü sürümlerde şunları yapabilirsiniz:

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

Saat dilimi adlarının tam listesini şu adreste bulabilirsiniz:

SELECT * FROM sys.time_zone_info 

Ve evet, zaman dilimleri kötü bir şekilde adlandırıldı - olmasına rağmen Eastern Standard Time, gün ışığından yararlanma dikkate alınır.


2
Zaman dilimleri ve ofsetler SQL Server'da da bulunabilir: SELECT * FROM sys.time_zone_info
rayzinnz

21

Sunucunuzun konumu dışında bir dönüşüme ihtiyacınız varsa, standart bir ofseti geçirmenize ve ABD Yaz Saati'ni hesaplamanıza olanak tanıyan bir işlev şunlardır:

-- =============================================
-- 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
Ron Smith Bunun eski bir yazı olduğunu biliyorum ama DST ürün yelpazesinde '0314' ve '1107' kodlu kodların neyi temsil ettiğini merak ettim. DTS nedeniyle değişen sabit kodlanmış günler gibi görünüyor. Günün takviminin ikinci Pazar günü ve Kasım ayının ilk Pazar günü nereye düştüğüne bağlı olarak değiştiği için, bunu hesaplanan bir tarih olması gerektiğinde neden kodlayalım? Zor kodlanmış günler bu kodu temelde hatalı yapar.
Mike

2
Güzel soru :) Bunlar Mart ayının ikinci Pazar günü ile Kasım ayının ilk Pazar gününün gerçekleşebileceği maksimum tarihlerdir. Aşağıdaki satırlar değişkenleri gerçek tarihe ayarlar.
Ron Smith

8

Yeni SQL Server 2016 fırsatlarını kullanma:

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

Ancak clr prosedürü 5 kat daha hızlı çalışır: '- (

Bir TimeZone için Ofset'in kış veya yaz saati olarak değişebileceğine dikkat edin. Örneğin

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'

Sonuçlar:

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

Sadece sabit ofset ekleyemezsiniz.


5

Veritabanınızda CLR'yi etkinleştirmenin yanı sıra sql sunucusunun saat dilimini kullanmak bir seçenekse, .Net'e kolayca yazılabilir.

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());
    }
}

Bir UTC datetime değeri girilir ve sunucuya göre yerel datetime değeri çıkar. Null değerler null değerini döndürür.


5

Bunu doğru VE genel bir şekilde yapmanın basit bir yolu yoktur.

Her şeyden önce, kaymanın söz konusu tarihe, Saat Dilimi VE DST'ye bağlı olduğu anlaşılmalıdır. GetDate()-GetUTCDatebugün size sadece sunucunun ilgili olmayan TZ'sinde ofseti verir.

Sadece iki çalışma çözümü gördüm ve çok fazla araştırma yaptım.

1) TZ başına Zaman Dilimi ve DST kuralları gibi birkaç temel veri tablosu içeren özel bir SQL işlevi. Çalışıyor ama çok zarif değil. Kod sahibi olmadığım için gönderemiyorum.

DÜZENLEME: İşte bu yöntemin bir örneği https://gist.github.com/drumsta/16b79cee6bc195cd89c8

2) db'ye bir .net derlemesi ekleyin, .Net bunu çok kolay bir şekilde yapabilir. Bu çok iyi çalışıyor, ancak olumsuz, sunucu düzeyinde birkaç parametre yapılandırmanız gerektiğidir ve örneğin veritabanını geri yüklerseniz, yapılandırma kolayca bozulur. Bu yöntemi kullanın ama kod sahibi olmadığım için gönderemiyorum.


4

Bunların hiçbiri benim için çalışmadı ama aşağıda% 100 çalıştı. Umarım bu benim gibi dönüştürmeye çalışan başkalarına yardımcı olabilir.

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
Bu kabul edilen cevap olmalı. Değiştireceğim tek şey, gerçekten Yerel Saat ve StandardOffset bir parametre olarak geçirildiğinde, EST zamanı anlamına gelir adıdır.
Greg Gum

Kabul et, en iyi cevap ... ama ofseti parametre olarak geçirmek yerine, bunu fonksiyon gövdesi içine ekledim:declare @StandardOffset int = datediff (hh, GETUTCDATE(), GETDATE())
Tom Warfield

Önceki önerimi takip etmek - @StandardOffset hesaplarsanız, DST düzeltmesi yapmanız gerekmez.
Tom Warfield

3

İşte gün ışığından yararlanma, UTC dengelemesi ve belirli bir yıla kilitlenmemiş bir sürüm.

---------------------------------------------------------------------------------------------------
--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

Bir çok veri olduğunda bir kapalı fonksiyon yolu çok yavaş buldum. Bu yüzden saat farkının hesaplanmasına izin verecek bir tablo işlevine katılarak yaptım. Temelde saat ofseti olan datetime segmentleridir. Bir yıl 4 sıra olacaktır. Yani tablo işlevi

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

bu tabloyu döndürür:

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

Yaz saatini hesaba katar. Nasıl kullanıldığına dair bir örnek aşağıdadır ve blog gönderisinin tamamı buradadır .

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'yi doğru bir şekilde düşünüyor gibi görünmüyor. Yalnızca ABD'nin var olduğunu ve DST kurallarının asla değişmediğini varsayalım.
vikjon0

@ vikjon0 evet, bunun için yaptığım projenin sadece ABD saat dilimleri vardı.
JBrooks

2
 declare @mydate2 datetime
 set @mydate2=Getdate()
 select @mydate2 as mydate,
 dateadd(minute, datediff(minute,getdate(),@mydate2),getutcdate())

1

Ron'un cevabı bir hata içeriyor. UTC eşdeğerinin gerekli olduğu yerel saati 2: 00'da kullanır. Ron'un cevabı hakkında yorum yapmak için yeterli itibar puanım yok, bu yüzden düzeltilmiş bir sürüm aşağıda görünüyor:

-- =============================================
-- 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

Bu bir hata değil, bir özellik :) Amerika Birleşik Devletleri'nin çoğu Yaz Saati Uygulaması ile başlar 2:00 am en.wikipedia.org/wiki/Daylight_saving_time
Ron Smith

@RonSmith Evet, yerel saatle 2: 00'da, verilen UTC saatinin DST aralığında olup olmadığını tespit etmek için UTC'ye dönüştürmemiz gerekir.
jlspublic

1

UNIX zaman damgası yalnızca belirli bir tarih ile Unix Dönemi arasındaki saniye sayısıdır,

TARİHİ SEÇİN (İKİNCİ, {d '1970-01-01'}, GETDATE ()) // Bu, SQL sunucusunda UNIX zaman damgasını döndürür

SQL Server'da Ülke Dengesi İşlevini Unix'e Zaman Damgası kullanarak yerel tarih saati için Unix UTC dönüşümü için bir işlev oluşturabilirsiniz


1

Basit. Azure SQL Server için bunu deneyin:

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

Yerel SQL Server için:

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

1
Gün ışığından yararlanma saati sırasında buna ne olur (saat dilimi özellikle "Doğu Standart Saati" dediğinden)?
Mark

1

Azure SQL ve @@Version> = SQL Server 2016 kullanıcıları için, Aşağıda basit bir işlev kullanılmıştır 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

Olabilecek değer türleri @LocalTimeZoneiçin lütfen bu bağlantıya gidin veyaKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones


0

Uyarı olarak - aşağıdakileri kullanacaksanız (dakika yerine milisaniyeye dikkat edin):

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

DATEDIFF parçasının her zaman aynı numarayı döndürmeyeceğini unutmayın. Yani DateTimes'ı milisaniye ile karşılaştırmak için kullanmayın.


0

Bu fonksiyonun ayrı bir tablo veya döngüler kullanan diğer çözümlerden daha hızlı olduğunu gördüm. Bu sadece temel bir vaka ifadesi. Nisan ve Ekim arasındaki tüm ayların -4 saatlik bir ofset (Doğu Saati) olduğu göz önüne alındığında, saçak günler için sadece birkaç vaka satırı eklememiz gerekiyor. Aksi takdirde, ofset -5 saattir.

Bu, UTC'den Doğu zamanına dönüştürmeye özgüdür, ancak gerektiğinde ek saat dilimi işlevleri eklenebilir.

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

Bu, DST ile sunucu zamanını alabilmelidir

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

sysdatetimeoffset DST'yi dikkate alır

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

0

İlk işlev: İtalyan saat dilimi (+1, +2) için yapılandırılmış, geçiş tarihleri: Mart ve ekimin son pazar günü, geçerli saat dilimi ile tarih saati arasındaki farkı parametre olarak döndürür.

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

Kod:

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

Sonra tarihi dönüştüren işlev

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'den Hint standart zamanını alın

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

    RETURN dateadd(minute,330,@UTCDate)

END
GO

0

Bu bir işlev olmadan yapılabilir. Aşağıdaki kod, bir UTC saatini yaz saati uygulaması için Mountain saatine dönüştürecektir. Tüm -6 ve -7 sayılarını saat diliminize göre ayarlayın (yani EST için sırasıyla -4 ve -5 olarak ayarlayabilirsiniz)

--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

Dizeyi yeniden biçimlendirmeniz ve doğru zamana dönüştürmeniz gerekir. Bu durumda Zulu zamanına ihtiyacım vardı.

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 için en iyi yol:

Sabit kodlanmış tarih ile:

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

Sütun ve tablo adlarıyla:

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

Ben böyle kodu kullanarak dönüşüm sağlayan UTC Yerel ve Yerel UTC UTC yapmak için kod var

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

ve

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

İşlevler, NodaTime tarafından sağlanan IANA / TZDB'deki zaman dilimlerinin tümünü veya bir alt kümesini destekleyebilir - https://nodatime.org/TimeZones adresindeki tam listeye bakın.

Kullanım durumumun şu andan itibaren yaklaşık +/- 5 yıl aralığında zaman dönüşümüne izin veren sadece 'geçerli' bir pencereye ihtiyacım olduğu anlamına geldiğini unutmayın. Bu, belirli bir tarih aralığındaki her saat dilimi aralığı için kod oluşturma biçimi nedeniyle çok geniş bir süreye ihtiyacınız varsa kullandığım yöntemin muhtemelen sizin için uygun olmadığı anlamına gelir.

Proje GitHub'da: https://github.com/elliveny/SQLServerTimeConversion

Bu, bu örneğe göre SQL işlev kodu üretir


0

Verileri veritabanında UTC tarihi olarak saklarsanız,

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

bu her zaman sunucunun açısından yerel ve AT ile uğraşmıyor TIME ZONE 'your time zone name', eğer veritabanınız bir istemci kurulumu gibi başka bir saat dilimine taşındıysa, sabit kodlanmış bir saat dilimi sizi ısırır.


0

Postgres'de bu çok güzel çalışıyor .. Sunucuya zamanın kaydedildiği zamanı söyleyin, 'utc' ve daha sonra belirli bir zaman dilimine dönüştürmesini isteyin, bu durumda 'Brezilya / Doğu'

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

Aşağıdaki seçim ile saat dilimlerinin tam bir listesini alın;

select * from pg_timezone_names;

Ayrıntılar için buraya bakın.

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


-1

İşte dst'yi hesaba katan daha basit olanı

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

6
Bu aslında DST'yi dikkate almaz. Sadece deneyin: SELECT DATEADD(MINUTE, DATEDIFF(MINUTE, GETUTCDATE(), '20150101'), GETDATE()). Şu anda CEST'deyim (UTC + 2), ancak DST Yılbaşı gününde geçerli olmayacak, bu yüzden benim için doğru cevap 1 Ocak 2015 01:00 olacaktır. Cevabınız, kabul edilen cevap gibi, 1 Ocak 2015 02:00.
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.