Ubah kolom Datetime dari UTC ke waktu lokal di pernyataan pilihan

208

Saya sedang melakukan beberapa pertanyaan pilih SQL dan ingin mengubah kolom waktu UTC saya menjadi waktu lokal untuk ditampilkan sebagai waktu lokal dalam hasil permintaan saya. Catatan, saya TIDAK ingin melakukan konversi ini melalui kode melainkan ketika saya melakukan query SQL manual dan acak terhadap database saya.

Nugs
sumber
Apakah pertanyaan ini mirip dengan keadaan Anda? stackoverflow.com/questions/3404646/…
Taryn East
kemungkinan duplikat dari TSQL: Bagaimana cara mengubah waktu lokal ke UTC? (SQL Server 2008)
Pasang kembali Monica Harap

Jawaban:

322

Anda dapat melakukan ini sebagai berikut pada SQL Server 2008 atau lebih tinggi:

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

Anda juga dapat melakukan lebih sedikit verbose:

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

Apa pun yang Anda lakukan, jangan gunakan -untuk mengurangi tanggal, karena operasi ini tidak bersifat atomik, dan Anda kadang-kadang akan mendapatkan hasil yang tidak ditentukan karena kondisi balapan antara waktu sistem dan waktu lokal yang diperiksa pada waktu yang berbeda (yaitu, non-atom) .

Harap perhatikan bahwa jawaban ini tidak memperhitungkan DST. Jika Anda ingin menyertakan penyesuaian DST, silakan lihat juga pertanyaan SO berikut:

Cara membuat fungsi Start dan End Daylight Savings time di SQL Server

Michael Goldshteyn
sumber
38
Apakah ada cara untuk membuat akun ini untuk penghematan cahaya siang hari?
Steve
15
Saya tidak melihat nama zona waktu di sini jadi ini tidak benar. Itu ide yang sangat buruk untuk menganggap Anda dapat mengkonversi ke waktu lokal dengan melakukan aritmatika
JonnyRaa
7
@MichaelGoldshteyn jika Anda memiliki offset zona waktu, Anda masih tidak tahu zona waktu logis mana saat ini. Zona waktu adalah hal sosial dan dapat diubah oleh pemerintah di berbagai titik. Offset untuk zona waktu dapat berbeda pada titik yang berbeda dalam waktu / sejarah (waktu musim panas menjadi yang umum). Anda mengimbangi waktu dengan offset saat ini dari UTC ... poin selanjutnya adalah ini akan memberikan zona waktu server dan bukan klien, yang bisa menjadi masalah lebih lanjut jika Anda hosting di negara lain.
JonnyRaa
4
@Niloofar Jawaban sederhananya adalah Anda tidak, dan seharusnya tidak. Datetimes harus selalu disimpan dalam UTC (lebih disukai berdasarkan jam server database, bukan server web, server aplikasi, dan jelas bukan jam klien). Menampilkan datetime adalah fungsi untuk lapisan UI, dan bertanggung jawab untuk mengubah datetime ke format yang Anda inginkan (termasuk zona waktu jika perlu).
Robert McKee
11
Bagi siapa pun yang menggunakan sql azure pendekatan ini tidak akan berfungsi karena fungsi tanggal / waktu semua mengembalikan UTC, jadi membandingkan GETDATE () ke GETUTCDATE () tidak memberi Anda apa pun untuk bekerja dan hasil Anda sama dengan yang Anda mulai.
Brian Surowiec
59

Saya tidak menemukan contoh ini membantu menyimpan datetime disimpan sebagai UTC ke datetime dalam zona waktu tertentu (BUKAN zona waktu server karena database Azure SQL dijalankan sebagai UTC). Beginilah cara saya menanganinya. Itu tidak elegan tetapi sederhana dan memberi Anda jawaban yang benar tanpa mempertahankan tabel lain:

select CONVERT(datetime, SWITCHOFFSET(dateTimeField, DATEPART(TZOFFSET, 
dateTimeField AT TIME ZONE 'Eastern Standard Time')))
Aiden Kaskela
sumber
4
Hanya berfungsi untuk 2016 dan menggunakan sistem registry. Tapi solusi hebat untuk Azure.
Dan Cundy
2
Yang ini berfungsi untuk waktu biru yang disimpan di UTC, terima kasih kawan
Null
3
Berikut daftar string yang dapat Anda gunakan untuk zona waktu: stackoverflow.com/a/7908482/631277
Matt Kemp
1
Jika menggunakan SQL 2016 dan AT TIME ZONEsintaksis, pertimbangkan stackoverflow.com/a/44941536/112764 - Anda dapat mengaitkan beberapa konversi secara bersamaan dengan hanya menggabungkan beberapa at time zone <blah>s.
NateJ
3
Ini agak aneh juga, tetapi beberapa pengujian yang sangat mendasar seperti ini mungkin bekerja juga - dateTimeField AT TIME ZONE 'UTC' AT TIME ZONE 'Eastern Standard Time'- hanya merantai AT TIME ZONEpernyataan. (@NateJ menyebutkan ini di atas saya lihat sekarang)
David Mohundro
22

Jika waktu lokal Anda diucapkan Eastern Standard Timedan Anda ingin mengonversi dari UTC ke itu, maka di Azure SQL dan SQL Server 2016 dan di atasnya, Anda bisa melakukan:

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

Daftar lengkap nama zona waktu dapat ditemukan dengan:

SELECT * FROM sys.time_zone_info 

Dan ya, zona waktu diberi nama yang buruk - meskipun demikian Eastern Standard Time, penghematan siang hari diperhitungkan.

Matt Frear
sumber
2
Zona waktu dan offset juga dapat ditemukan di SQL Server di sini: SELECT * FROM sys.time_zone_info
rayzinnz
21

Jika Anda memerlukan konversi selain lokasi server Anda, berikut adalah fungsi yang memungkinkan Anda untuk melewati offset standar dan akun untuk US Daylight Savings 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
Ron Smith
sumber
2
Ron Smith Saya tahu ini adalah posting lama tapi saya ingin tahu apa yang mewakili kode keras '0314' dan '1107' dalam mendapatkan kisaran DST. Tampaknya ini adalah hari-hari dengan kode keras yang berubah karena DTS. Mengapa Anda membuat kode sulit ini ketika itu harus menjadi tanggal yang dihitung karena hari-hari berubah berdasarkan di mana pada kalender hari Minggu kedua pawai dan hari Minggu pertama bulan November jatuh. Hari-hari dengan kode keras akan membuat kode ini cacat secara mendasar.
Mike
2
Pertanyaan bagus :) Itu adalah tanggal maksimal di mana hari Minggu kedua di bulan Maret dan hari Minggu pertama di bulan November dapat terjadi. Baris berikut mengatur variabel ke tanggal aktual.
Ron Smith
8

Menggunakan peluang SQL Server 2016 baru:

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

Tetapi prosedur CLR bekerja 5 kali lebih cepat: '- (

Perhatikan bahwa Offset untuk satu TimeZone dapat berubah ke waktu musim dingin atau musim panas. Sebagai contoh

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'

hasil:

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

Anda tidak bisa hanya menambahkan offset konstan.

Pavel Samoylenko
sumber
5

Jika mengaktifkan CLR pada basis data Anda merupakan opsi dan juga menggunakan zona waktu server sql, ini dapat ditulis dalam .Net dengan mudah.

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

Nilai datetime UTC masuk dan nilai datetime lokal relatif ke server keluar. Nilai kosong mengembalikan nol.

JGates
sumber
5

Tidak ada cara sederhana untuk melakukan ini dengan cara yang benar DAN generik.

Pertama-tama harus dipahami bahwa offset tergantung pada tanggal yang dimaksud, Zona Waktu DAN DST. GetDate()-GetUTCDatehanya memberi Anda offset hari ini di TZ server, yang tidak relevan.

Saya hanya melihat dua solusi yang berfungsi dan saya telah banyak mencari.

1) Fungsi SQL khusus dengan beberapa tabel data dasar seperti Zona Waktu dan aturan DST per TZ. Bekerja tetapi tidak terlalu elegan. Saya tidak dapat memposting karena saya tidak memiliki kode.

EDIT: Ini adalah contoh metode ini https://gist.github.com/drumsta/16b79cee6bc195cd89c8

2) Tambahkan .net assembly ke db, .Net dapat melakukan ini dengan sangat mudah. Ini berfungsi dengan baik tetapi downside adalah bahwa Anda perlu mengkonfigurasi beberapa parameter pada tingkat server dan konfigurasi mudah rusak misalnya jika Anda mengembalikan database. Saya menggunakan metode ini tetapi saya tidak dapat mempostingnya karena saya tidak memiliki kode.

vikjon0
sumber
4

Tidak ada yang bekerja untuk saya tetapi di bawah ini bekerja 100%. Semoga ini bisa membantu orang lain yang mencoba mengubahnya seperti saya.

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
Mike
sumber
1
Ini harus menjadi jawaban yang diterima. Satu-satunya hal yang akan saya ubah adalah namanya seperti yang diisyaratkan untuk waktu EST, ketika benar-benar untuk Waktu Lokal dan StandardOffset dilewatkan sebagai parameter.
Greg Gum
Setuju, jawaban terbaik ... tapi bukannya harus lulus dalam offset sebagai parameter, saya menambahkan ini dalam fungsi tubuh:declare @StandardOffset int = datediff (hh, GETUTCDATE(), GETDATE())
Tom Warfield
Menindaklanjuti suggetion saya sebelumnya - Jika Anda menghitung @StandardOffset, maka Anda tidak perlu melakukan koreksi DST.
Tom Warfield
3

Ini adalah versi yang menyumbang penghematan siang hari, offset UTC, dan tidak dikunci pada tahun tertentu.

---------------------------------------------------------------------------------------------------
--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
Patrick Slesicki
sumber
3

Saya menemukan satu cara fungsi menjadi terlalu lambat ketika ada banyak data. Jadi saya melakukannya dengan bergabung ke fungsi tabel yang akan memungkinkan untuk perhitungan jam diff. Ini pada dasarnya adalah segmen datetime dengan offset jam. Setahun akan menjadi 4 baris. Jadi fungsi tabel

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

akan mengembalikan tabel ini:

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

Itu memperhitungkan penghematan siang hari. Contoh cara penggunaannya ada di bawah dan posting blog lengkapnya ada di sini .

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
JBrooks
sumber
Tampaknya tidak mempertimbangkan DST dengan cara yang benar. Tidak yakin apakah Anda menganggap hanya AS yang ada dan bahwa aturan DST tidak pernah berubah.
vikjon0
@ vikjon0 ya, proyek yang saya buat ini hanya memiliki zona waktu AS.
JBrooks
2
 declare @mydate2 datetime
 set @mydate2=Getdate()
 select @mydate2 as mydate,
 dateadd(minute, datediff(minute,getdate(),@mydate2),getutcdate())
Looking_for_answers
sumber
1

Jawaban Ron mengandung kesalahan. Ini menggunakan 02:00 waktu setempat di mana setara UTC diperlukan. Saya tidak memiliki poin reputasi yang cukup untuk mengomentari jawaban Ron sehingga versi yang diperbaiki muncul di bawah:

-- =============================================
-- 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
jlspublic
sumber
Ini adalah fitur, bukan bug :) Sebagian besar Amerika Serikat memulai Daylight Saving Time pada pukul 2:00 pagi. En.wikipedia.org/wiki/Daylight_saving_time
Ron Smith
@RonSmith Ya, pukul 02:00 waktu setempat, yang harus kita konversi ke UTC untuk mendeteksi apakah waktu UTC yang diberikan berada dalam kisaran DST.
jlspublic
1

Stempel waktu UNIX hanyalah jumlah detik antara tanggal tertentu dan Unix Epoch,

SELECT DATEDIFF (SECOND, {d '1970-01-01'}, GETDATE ()) // Ini Akan Mengembalikan cap waktu UNIX Dalam SQL server

Anda dapat membuat fungsi untuk tanggal lokal waktu untuk Unix UTC konversi menggunakan Country Offset Function ke Unix Time Stamp di SQL server

Vasanthlal VA
sumber
1

Itu mudah. Coba ini untuk Azure SQL Server:

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

Untuk SQL Server Lokal:

SELECT CONVERT(datetime2, SWITCHOFFSET(CONVERT(datetimeoffset, gETDATE()), DATENAME(TzOffset, gETDATE() AT TIME ZONE 'Eastern Standard Time'))) FROM YourTable
lijuthoma
sumber
1
Apa yang terjadi dengan ini selama waktu musim panas (karena zona waktu secara khusus mengatakan "Waktu Standar Timur")?
Markus
1

Untuk pengguna Azure SQL dan @@Version> = SQL Server 2016, Di bawah ini adalah fungsi sederhana yang digunakan 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

Untuk jenis nilai yang @LocalTimeZonedapat diambil, buka tautan ini atau KeKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones

Ranger
sumber
0

Sebagai peringatan - jika Anda akan menggunakan yang berikut (perhatikan milidetik alih-alih menit):

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

Perlu diingat bahwa bagian DATEDIFF tidak akan selalu mengembalikan nomor yang sama. Jadi jangan gunakan untuk membandingkan DateTimes hingga milidetik.

Sasquatch
sumber
0

Saya telah menemukan bahwa fungsi ini lebih cepat daripada solusi lain menggunakan tabel atau loop terpisah. Itu hanya pernyataan kasus dasar. Mengingat bahwa semua bulan antara April dan Oktober memiliki offset -4-jam (Waktu Timur), kita hanya perlu menambahkan beberapa garis kasus lagi untuk hari-hari pinggiran. Jika tidak, offset -5 jam.

Ini khusus untuk konversi dari UTC ke waktu Timur, tetapi fungsi zona waktu tambahan dapat ditambahkan sesuai kebutuhan.

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
Jason Green
sumber
0

Ini harus bisa mendapatkan waktu server dengan DST

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

sysdatetimeoffset memperhitungkan DST

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

Fungsi pertama: dikonfigurasikan untuk zona waktu Italia (+1, +2), berganti tanggal: minggu terakhir Maret dan Oktober, mengembalikan perbedaan antara zona waktu saat ini dan datetime sebagai parameter.

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

Kode tersebut adalah:

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

Kemudian fungsi yang mengonversi tanggal

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
GigiS
sumber
0

- dapatkan waktu standar India dari utc

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

    RETURN dateadd(minute,330,@UTCDate)

END
GO
Meghraj Swami
sumber
0

Ini bisa dilakukan tanpa fungsi. Kode di bawah ini akan mengonversi waktu UTC ke Waktu pegunungan yang menunjukkan penghematan siang hari. Sesuaikan semua angka -6 dan -7 dengan zona waktu Anda (untuk EST Anda akan menyesuaikan masing-masing ke -4 dan -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
Alex Fenech
sumber
0

Anda harus memformat ulang string serta mengonversi ke waktu yang tepat. Dalam hal ini saya membutuhkan waktu Zulu.

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;
Tommyz
sumber
0

Cara terbaik untuk Oracle:

Dengan datetime hardcoded:

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

Dengan nama kolom dan tabel:

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
BOB
sumber
0

Saya memiliki kode untuk melakukan UTC ke Lokal dan Lokal ke kali UTC yang memungkinkan konversi menggunakan kode seperti ini

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

dan

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

Fungsi-fungsinya dapat mendukung semua atau sebagian dari zona waktu di IANA / TZDB seperti yang disediakan oleh NodaTime - lihat daftar lengkapnya di https://nodatime.org/TimeZones

Ketahuilah bahwa use case saya berarti saya hanya perlu jendela 'saat ini', memungkinkan konversi waktu dalam kisaran sekitar +/- 5 tahun dari sekarang. Ini berarti bahwa metode yang saya gunakan mungkin tidak cocok untuk Anda jika Anda memerlukan periode waktu yang sangat luas, karena cara itu menghasilkan kode untuk setiap interval zona waktu dalam rentang tanggal yang diberikan.

Proyek ini ada di GitHub: https://github.com/elliveny/SQLServerTimeConversion

Ini menghasilkan kode fungsi SQL seperti contoh ini

Elliveny
sumber
0

Nah jika Anda menyimpan data sebagai tanggal UTC dalam database Anda dapat melakukan sesuatu yang sederhana

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

ini selalu lokal dari titik server dan Anda tidak meraba-raba dengan AT TIME ZONE 'your time zone name', jika database Anda dipindahkan ke zona waktu lain seperti instalasi klien zona waktu kode keras mungkin menggigit Anda.

Walter Vehoeven
sumber
0

Dalam postgres ini bekerja dengan sangat baik .. Beritahu server waktu di mana waktu disimpan, 'utc', dan kemudian minta untuk mengonversi ke zona waktu tertentu, dalam hal ini 'Brasil / Timur'

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

Dapatkan daftar zona waktu lengkap dengan pilihan berikut;

select * from pg_timezone_names;

Lihat detailnya di sini.

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

Harada
sumber
-1

Inilah yang lebih sederhana yang membawa pertama ke akun

CREATE FUNCTION [dbo].[UtcToLocal] 
(
    @p_utcDatetime DATETIME 
)
RETURNS DATETIME
AS
BEGIN
    RETURN DATEADD(MINUTE, DATEDIFF(MINUTE, GETUTCDATE(), @p_utcDatetime), GETDATE())
END
Morten Sølvberg
sumber
6
Ini sebenarnya tidak memperhitungkan DST. Coba saja: SELECT DATEADD(MINUTE, DATEDIFF(MINUTE, GETUTCDATE(), '20150101'), GETDATE()). Saya saat ini dalam CEST (UTC + 2), tetapi DST tidak akan berlaku pada hari Tahun Baru, jadi jawaban yang tepat untuk saya adalah 1 Januari 2015 01:00. Jawaban Anda, seperti jawaban yang diterima, mengembalikan 1 Januari 2015 02:00.