2010-04-23 17 views
42

Ho recentemente aggiornato il mio sistema per registrare data/ora come UTC, come in precedenza memorizzavano come ora locale.SQL Server - Converti il ​​campo data in UTC

Ora ho bisogno di convertire tutte le date/orari memorizzati in UTC. Mi chiedevo se esiste una funzione incorporata, simile al metodo .NET ConvertTime?

Sto cercando di evitare di dover scrivere un'app di utilità per fare questo per me.

Qualche suggerimento?

+1

Questi orari sono tutti "locali" o sono tutti orari diversi da più fusi orari? – SqlRyan

+0

@rwmnau, sono tutti locali per me. – James

+0

possibile duplicato di [TSQL: Come convertire l'ora locale in UTC? (SQL Server 2008)] (http://stackoverflow.com/questions/1205142/tsql-how-to-convert-local-time-to-utc-sql-server-2008) – BroSlow

risposta

9

Se sono tutti locali a voi, allora ecco l'offset:

SELECT GETDATE() AS CurrentTime, GETUTCDATE() AS UTCTime 

e si dovrebbe essere in grado di aggiornare tutti i dati utilizzando:

UPDATE SomeTable 
    SET DateTimeStamp = DATEADD(hh, DATEDIFF(hh, GETDATE(), GETUTCDATE()), DateTimeStamp) 
Sarebbe

che il lavoro, o AM Mi manca un'altra angolazione di questo problema?

+0

Sembra la parte, gli darà un go – James

+0

I get get 'Il tipo di dati dell'argomento datetime non è valido per l'argomento 2 della funzione dateadd. Qualche idea? – James

+2

@James: è necessario invertire il secondo e il terzo parametro nella chiamata: 'DateTimeStamp = DATEADD (hh, DATEDIFF (hh, GETDATE(), GETUTCDATE()), DateTimeStamp)' - il secondo parametro è l'intervallo (il numero di ore da aggiungere o sottrarre), e il terzo è il valore per applicare tale intervallo a –

70

Non credo che il codice sopra funzionerà. Il motivo è che dipende dalla differenza tra la data corrente negli orari locali e quelli UTC. Ad esempio, qui in California siamo ora in PDT (Pacific Daylight Time); la differenza tra questo tempo e UTC è di 7 ore. Il codice fornito, se eseguito ora, aggiungerà 7 ore ad ogni data che si desidera convertire. Ma se una data storica memorizzata, o una data futura, viene convertita, e quella data non è durante l'ora legale, aggiungerà comunque 7, quando l'offset corretto è 8. In conclusione: non è possibile convertire correttamente data/ora tra fusi orari (compreso UTC, che non rispetta l'ora legale) guardando solo la data corrente. È necessario considerare la data stessa che si sta convertendo, a seconda che l'ora legale fosse in vigore in quella data. Inoltre, le date in cui la luce del giorno e gli orari standard si cambiano sono cambiate (George Bush ha cambiato le date durante la sua amministrazione per gli USA!). In altre parole, qualsiasi soluzione che faccia riferimento a getdate() o getutcdate() non funzioni. Deve analizzare la data effettiva da convertire.

+1

È possibile creare una funzione CLR che userà C# per convertire i fusi orari prendendo in considerazione l'ora legale http://www.jitbit.com/maxblog/17- sql-server-how-to-convert-datetime-to-utc/ – Alex

+0

Tutto qui è corretto. Il mio nuovo post qui sotto, 5 anni dopo questo, tiene conto di tutti questi problemi in una funzione definita dall'utente SQL Server nativo. –

0

Quanto segue dovrebbe funzionare in quanto calcola la differenza tra DATE e UTCDATE per il server in esecuzione e utilizza tale scostamento per calcolare l'equivalente UTC di qualsiasi data passata. Nel mio esempio, sto cercando di convertire l'equivalente UTC per '1-nov-2012 06:00' ad Adelaide, in Australia, dove l'offset UTC è di -630 minuti, che quando aggiunto a qualsiasi data comporterà l'equivalente UTC di qualsiasi data locale.

selezionare DATEADD (MINUTE, DATEDIFF (MINUTE, GETDATE(), GETUTCDATE()), '1-nov-2012 06:00')

+2

Non è la stessa cosa della risposta di @SqlRyan? Questo sembra avere lo stesso problema con l'ora legale. – Slider345

+0

Sì, cosa ha detto @ Slider345. –

14

Come accennato qui in passato, non c'è modo build-in a eseguire la conversione della data di conoscenza delle regole del fuso orario in SQL Server (almeno a SQL Server 2012).

Si sono essenzialmente tre opzioni per fare questo diritto:

  1. eseguire la conversione di fuori dei risultati di SQL Server e memorizzare nel database
  2. Introdurre fuso orario compensato regole in un tavolo stand-alone e creare stored procedure o UDF per fare riferimento alla tabella delle regole per eseguire le conversioni. È possibile trovare un approccio a questo approccio over at SQL Server Central (è richiesta la registrazione)
  3. È possibile creare un UDF SQL CLR; Descriverò l'approccio qui

Mentre SQL Server non offre strumenti per eseguire la conversione della data di conoscenza delle regole del fuso orario, il file.NET framework fa, e finché puoi usare SQL CLR, puoi approfittarne.

In Visual Studio 2012, assicuratevi di avere gli strumenti di dati installati (in caso contrario, il progetto di SQL Server non verrà visualizzato come opzione), e creare un nuovo progetto di SQL Server.

Poi, aggiungere un nuovo SQL CLR C# User Defined Function, lo chiamano "ConvertToUtc". VS genererà piastra della caldaia per te, che dovrebbe essere simile a questo:

public partial class UserDefinedFunctions 
{ 
    [Microsoft.SqlServer.Server.SqlFunction] 
    public static SqlString ConvertToUtc() 
    { 
     // Put your code here 
     return new SqlString (string.Empty); 
    } 
} 

Vogliamo fare diverse modifiche qui. Per uno, vogliamo restituire un SqlDateTime piuttosto che un SqlString. In secondo luogo, vogliamo fare qualcosa di utile. :)

Il codice rivisto dovrebbe essere così:

public partial class UserDefinedFunctions 
{ 
    [Microsoft.SqlServer.Server.SqlFunction] 
    public static SqlDateTime ConvertToUtc(SqlDateTime sqlLocalDate) 
    { 
     // convert to UTC and use explicit conversion 
     // to return a SqlDateTime 
     return TimeZone.CurrentTimeZone.ToUniversalTime(sqlLocalDate.Value); 
    } 
} 

A questo punto, siamo pronti a provarlo. Il modo più semplice è utilizzare la funzione Pubblica di pubblicazione in Visual Studio. Fare clic con il tasto destro del mouse sul progetto del database e selezionare "Pubblica". Configurare la connessione di database e il nome, e quindi fare clic su "Pubblica" per spingere il codice nel database o fare clic su "Generate Script", se si desidera memorizzare lo script per i posteri (o per spingere i bit in produzione).

Una volta che avete l'UDF nel database, è possibile vedere in azione:

declare @dt as datetime 
set @dt = '12/1/2013 1:00 pm' 
select dbo.ConvertToUtc(@dt) 
+0

Non penso che funzionerà per TUTTE le date storiche "Il metodo ToUniversalTime riconosce solo la regola di regolazione dell'ora legale per il fuso orario locale. Di conseguenza, è garantito il ritorno accurato del Coordinated Universal Time (UTC) corrispondente a una determinata ora locale solo durante il periodo in cui è in vigore la regola di regolazione più recente. Può restituire risultati imprecisi se il tempo è un valore di data e ora storico soggetto a una regola di regolazione precedente. " – OffHeGoes

+1

Probabilmente è necessario utilizzare [TimeZone.IsDaylightSavingTime] (http://msdn.microsoft.com/en-us/library/c1f14e97.aspx) e gestire da solo la conversione. "Supponendo che lo stesso sistema operativo disponga di dati cronologici precisi per l'ora legale, è disponibile un risultato più accurato utilizzando il metodo TimeZoneInfo.IsDaylightSavingTime. Se possibile, utilizzare il metodo TimeZoneInfo.IsDaylightSavingTime." – OffHeGoes

0

A seconda di quanto indietro è necessario andare, si può costruire una tabella dei tempi di risparmio di luce del giorno e poi unirsi alla tabella e fare una conversione dst-sensitive. Questo particolare converte da EST a GMT (cioè usa offset di 5 e 4).

select createdon, dateadd(hour, case when dstlow is null then 5 else 4 end, createdon) as gmt 
from photos 
left outer join (
      SELECT {ts '2009-03-08 02:00:00'} as dstlow, {ts '2009-11-01 02:00:00'} as dsthigh 
UNION ALL SELECT {ts '2010-03-14 02:00:00'} as dstlow, {ts '2010-11-07 02:00:00'} as dsthigh 
UNION ALL SELECT {ts '2011-03-13 02:00:00'} as dstlow, {ts '2011-11-06 02:00:00'} as dsthigh 
UNION ALL SELECT {ts '2012-03-11 02:00:00'} as dstlow, {ts '2012-11-04 02:00:00'} as dsthigh 
UNION ALL SELECT {ts '2013-03-10 02:00:00'} as dstlow, {ts '2013-11-03 02:00:00'} as dsthigh 
UNION ALL SELECT {ts '2014-03-09 02:00:00'} as dstlow, {ts '2014-11-02 02:00:00'} as dsthigh 
UNION ALL SELECT {ts '2015-03-08 02:00:00'} as dstlow, {ts '2015-11-01 02:00:00'} as dsthigh 
UNION ALL SELECT {ts '2016-03-13 02:00:00'} as dstlow, {ts '2016-11-06 02:00:00'} as dsthigh 
UNION ALL SELECT {ts '2017-03-12 02:00:00'} as dstlow, {ts '2017-11-05 02:00:00'} as dsthigh 
UNION ALL SELECT {ts '2018-03-11 02:00:00'} as dstlow, {ts '2018-11-04 02:00:00'} as dsthigh 
    ) dst 
    on createdon >= dstlow and createdon < dsthigh 
4

Se devi convertire date diverse da oggi in fusi orari diversi, devi occuparti dell'ora legale. Volevo una soluzione che potrebbe essere fatto senza preoccuparsi di versione del database, senza l'utilizzo di funzioni memorizzate e qualcosa che potrebbe essere facilmente portato su Oracle.

Penso che Warren sia sulla strada giusta per ottenere le date corrette per l'ora legale, ma per renderlo più utile per più fuso orario e regole diverse per i paesi e anche per la regola che è cambiata negli Stati Uniti tra il 2006 e il 2007, qui una variazione sulla soluzione di cui sopra. Si noti che questo non solo ci ha i fusi orari, ma anche l'Europa centrale. L'Europa centrale segue l'ultima domenica di aprile e l'ultima domenica di ottobre. Noterete anche che gli Stati Uniti nel 2006, segue la vecchia prima domenica di aprile, ultima domenica di regola ottobre.

Questo codice SQL può sembrare un po 'brutto, ma basta copiarlo e incollarlo in SQL Server e provarlo. Si noti che ci sono 3 sezioni per anni, fusi orari e regole. Se vuoi un altro anno, aggiungilo al sindacato dell'anno. Lo stesso vale per un altro fuso orario o regola.

select yr, zone, standard, daylight, rulename, strule, edrule, yrstart, yrend, 
    dateadd(day, (stdowref + stweekadd), stmonthref) dstlow, 
    dateadd(day, (eddowref + edweekadd), edmonthref) dsthigh 
from (
    select yrs.yr, z.zone, z.standard, z.daylight, z.rulename, r.strule, r.edrule, 
    yrs.yr + '-01-01 00:00:00' yrstart, 
    yrs.yr + '-12-31 23:59:59' yrend, 
    yrs.yr + r.stdtpart + ' ' + r.cngtime stmonthref, 
    yrs.yr + r.eddtpart + ' ' + r.cngtime edmonthref, 
    case when r.strule in ('1', '2', '3') then case when datepart(dw, yrs.yr + r.stdtpart) = '1' then 0 else 8 - datepart(dw, yrs.yr + r.stdtpart) end 
    else (datepart(dw, yrs.yr + r.stdtpart) - 1) * -1 end stdowref, 
    case when r.edrule in ('1', '2', '3') then case when datepart(dw, yrs.yr + r.eddtpart) = '1' then 0 else 8 - datepart(dw, yrs.yr + r.eddtpart) end 
    else (datepart(dw, yrs.yr + r.eddtpart) - 1) * -1 end eddowref, 
    datename(dw, yrs.yr + r.stdtpart) stdow, 
    datename(dw, yrs.yr + r.eddtpart) eddow, 
    case when r.strule in ('1', '2', '3') then (7 * CAST(r.strule AS Integer)) - 7 else 0 end stweekadd, 
    case when r.edrule in ('1', '2', '3') then (7 * CAST(r.edrule AS Integer)) - 7 else 0 end edweekadd 
from (
    select '2005' yr union select '2006' yr -- old us rules 
    UNION select '2007' yr UNION select '2008' yr UNION select '2009' yr UNION select '2010' yr UNION select '2011' yr 
    UNION select '2012' yr UNION select '2013' yr UNION select '2014' yr UNION select '2015' yr UNION select '2016' yr 
    UNION select '2017' yr UNION select '2018' yr UNION select '2018' yr UNION select '2020' yr UNION select '2021' yr 
    UNION select '2022' yr UNION select '2023' yr UNION select '2024' yr UNION select '2025' yr UNION select '2026' yr 
) yrs 
cross join (
    SELECT 'ET' zone, '-05:00' standard, '-04:00' daylight, 'US' rulename 
    UNION SELECT 'CT' zone, '-06:00' standard, '-05:00' daylight, 'US' rulename 
    UNION SELECT 'MT' zone, '-07:00' standard, '-06:00' daylight, 'US' rulename 
    UNION SELECT 'PT' zone, '-08:00' standard, '-07:00' daylight, 'US' rulename 
    UNION SELECT 'CET' zone, '+01:00' standard, '+02:00' daylight, 'EU' rulename 
) z 
join (
    SELECT 'US' rulename, '2' strule, '-03-01' stdtpart, '1' edrule, '-11-01' eddtpart, 2007 firstyr, 2099 lastyr, '02:00:00' cngtime 
    UNION SELECT 'US' rulename, '1' strule, '-04-01' stdtpart, 'L' edrule, '-10-31' eddtpart, 1900 firstyr, 2006 lastyr, '02:00:00' cngtime 
    UNION SELECT 'EU' rulename, 'L' strule, '-03-31' stdtpart, 'L' edrule, '-10-31' eddtpart, 1900 firstyr, 2099 lastyr, '01:00:00' cngtime 
) r on r.rulename = z.rulename 
    and datepart(year, yrs.yr) between firstyr and lastyr 
) dstdates 

Per le regole, utilizzare 1, 2, 3 o L per la prima, la seconda, la terza o l'ultima domenica. La parte della data indica il mese e in base alla regola, il primo giorno del mese o l'ultimo giorno del mese per il tipo di regola L.

Ho inserito la query sopra riportata in una vista. Ora, ogni volta che voglio una data con l'offset del fuso orario o convertito in ora UTC, mi limito a unirmi a questa vista e selezionare la data nel formato data. Invece di datetime, li ho convertiti in datetimeoffset.

select createdon, dst.zone 
    , case when createdon >= dstlow and createdon < dsthigh then dst.daylight else dst.standard end pacificoffsettime 
    , TODATETIMEOFFSET(createdon, case when createdon >= dstlow and createdon < dsthigh then dst.daylight else dst.standard end) pacifictime 
    , SWITCHOFFSET(TODATETIMEOFFSET(createdon, case when createdon >= dstlow and createdon < dsthigh then dst.daylight else dst.standard end), '+00:00') utctime 
from (select '2014-01-01 12:00:00' createdon union select '2014-06-01 12:00:00' createdon) photos 
left join US_DAYLIGHT_DATES dst on createdon between yrstart and yrend and zone = 'PT' 
+0

Quindi questo account per i precedenti campi data/ora nel passato? o solo quali sono attualmente le regole? –

+0

Perdonami, ora capisco cosa stai facendo. –

+0

Hai un esempio della tua seconda query che non usa elementi 2008+. Il mio database è nel 2005. Qualche consiglio? –

5

Ecco una procedura testata che ha aggiornato il mio database da locale a tempo di utc. L'unico input richiesto per l'aggiornamento di un database consiste nell'immettere il numero di minuti in cui l'ora locale viene spostata dal tempo utc in @Offset e se il fuso orario è soggetto alle regolazioni dell'ora legale impostando @ ApplyDaylightSavings.

Ad esempio, il fuso orario US inserire @ Offset = -360 e @ ApplyDaylightSavings = 1 per 6 ore e sì applicare la regolazione dell'ora legale.

Sostenere Database Funzione


CREATE FUNCTION [dbo].[GetUtcDateTime](@LocalDateTime DATETIME, @Offset smallint, @ApplyDaylightSavings bit) 
RETURNS DATETIME AS BEGIN 

    --==================================================== 
    --Calculate the Offset Datetime 
    --==================================================== 
    DECLARE @UtcDateTime AS DATETIME 
    SET @UtcDateTime = DATEADD(MINUTE, @Offset * -1, @LocalDateTime) 

    IF @ApplyDaylightSavings = 0 RETURN @UtcDateTime; 

    --==================================================== 
    --Calculate the DST Offset for the UDT Datetime 
    --==================================================== 
    DECLARE @Year as SMALLINT 
    DECLARE @DSTStartDate AS DATETIME 
    DECLARE @DSTEndDate AS DATETIME 

    --Get Year 
    SET @Year = YEAR(@LocalDateTime) 

    --Get First Possible DST StartDay 
    IF (@Year > 2006) SET @DSTStartDate = CAST(@Year AS CHAR(4)) + '-03-08 02:00:00' 
    ELSE    SET @DSTStartDate = CAST(@Year AS CHAR(4)) + '-04-01 02:00:00' 
    --Get DST StartDate 
    WHILE (DATENAME(dw, @DSTStartDate) <> 'sunday') SET @DSTStartDate = DATEADD(day, 1,@DSTStartDate) 


    --Get First Possible DST EndDate 
    IF (@Year > 2006) SET @DSTEndDate = CAST(@Year AS CHAR(4)) + '-11-01 02:00:00' 
    ELSE    SET @DSTEndDate = CAST(@Year AS CHAR(4)) + '-10-25 02:00:00' 

    --Get DST EndDate 
    WHILE (DATENAME(dw, @DSTEndDate) <> 'sunday') SET @DSTEndDate = DATEADD(day,1,@DSTEndDate) 

    --Finally add the DST Offset if needed 
    RETURN CASE WHEN @LocalDateTime BETWEEN @DSTStartDate AND @DSTEndDate THEN 
     DATEADD(MINUTE, -60, @UtcDateTime) 
    ELSE 
     @UtcDateTime 
    END 

END 
GO 

Amplia Script


  1. Fare un backup prima di eseguire questo script!
  2. Set @Offset & @ ApplyDaylightSavings
  3. Esegui una sola volta!

begin try 
    begin transaction; 

    declare @sql nvarchar(max), @Offset smallint, @ApplyDaylightSavings bit; 

    set @Offset = -360;    --US Central Time, -300 for US Eastern Time, -480 for US West Coast 
    set @ApplyDaylightSavings = 1; --1 for most US time zones except Arizona which doesn't observer daylight savings, 0 for most time zones outside the US 

    declare rs cursor for 
    select 'update [' + a.TABLE_SCHEMA + '].[' + a.TABLE_NAME + '] set [' + a.COLUMN_NAME + '] = dbo.GetUtcDateTime([' + a.COLUMN_NAME + '], ' + cast(@Offset as nvarchar) + ', ' + cast(@ApplyDaylightSavings as nvarchar) + ') ;' 
    from INFORMATION_SCHEMA.COLUMNS a 
     inner join INFORMATION_SCHEMA.TABLES b on a.TABLE_SCHEMA = b.TABLE_SCHEMA and a.TABLE_NAME = b.TABLE_NAME 
    where a.DATA_TYPE = 'datetime' and b.TABLE_TYPE = 'BASE TABLE' ; 

    open rs; 
    fetch next from rs into @sql; 
    while @@FETCH_STATUS = 0 begin 
     exec sp_executesql @sql; 
     print @sql; 
     fetch next from rs into @sql; 
    end 
    close rs; 
    deallocate rs; 

    commit transaction; 
end try 
begin catch 
    close rs; 
    deallocate rs; 

    declare @ErrorMessage nvarchar(max), @ErrorSeverity int, @ErrorState int; 
    select @ErrorMessage = ERROR_MESSAGE() + ' Line ' + cast(ERROR_LINE() as nvarchar(5)), @ErrorSeverity = ERROR_SEVERITY(), @ErrorState = ERROR_STATE(); 
    rollback transaction; 
    raiserror (@ErrorMessage, @ErrorSeverity, @ErrorState); 
end catch 
25

Con SQL Server 2016, non v'è ora costruito un supporto per i fusi orari con la dichiarazione AT TIME ZONE. È possibile concatenare questi da fare conversioni:

SELECT YourOriginalDateTime AT TIME ZONE 'Pacific Standard Time' AT TIME ZONE 'UTC' 

Oppure, questo dovrebbe funzionare così:

SELECT SWITCHOFFSET(YourOriginalDateTime AT TIME ZONE 'Pacific Standard Time', '+00:00') 

Uno di questi interpreterà l'ingresso nel tempo del Pacifico, opportunamente conto o meno l'ora legale è in effetto e quindi convertire in UTC. Il risultato sarà uno datetimeoffset con uno spostamento zero.

More examples in the CTP announcement.

+0

UPVOTE UPVOTE UPVOTE !!! –

+1

Perché al Pacific Standard Time prima? – xr280xr

+0

@ xr280xr: esegue la conversione da un fuso orario specifico a UTC. Pacific è solo un esempio qui. –

0

A meno che ho perso qualcosa sopra (possibile), tutti i metodi di cui sopra sono errate in quanto non prendono la sovrapposizione quando si passa da legale (diciamo EDT) a tempo standard (diciamo EST) in considerazione. Un esempio (molto dettagliato):

[1] EDT 2016-11-06 00:59 - UTC 2016-11-06 04:59 
[2] EDT 2016-11-06 01:00 - UTC 2016-11-06 05:00 
[3] EDT 2016-11-06 01:30 - UTC 2016-11-06 05:30 
[4] EDT 2016-11-06 01:59 - UTC 2016-11-06 05:59 
[5] EST 2016-11-06 01:00 - UTC 2016-11-06 06:00 
[6] EST 2016-11-06 01:30 - UTC 2016-11-06 06:30 
[7] EST 2016-11-06 01:59 - UTC 2016-11-06 06:59 
[8] EST 2016-11-06 02:00 - UTC 2016-11-06 07:00 

Gli offset di ora semplice in base alla data e all'ora non lo taglieranno. Se non sai se l'ora locale è stata registrata in EDT o EST tra 01:00 e 01:59, non ne avrai la minima idea! Usiamo l'01:30 per esempio: se trovi in ​​un secondo momento nell'intervallo da 01:31 a 01:59 PRIMA, non saprai se l'01:30 che stai guardando è [3 o [6. In questo caso, è possibile ottenere il tempo UTC corretto con un po 'di codifica essere guardando le voci precedenti (non divertente in SQL), e questo è il caso migliore ...

dire che hai i seguenti orari locali registrati, e non dedicare un bit per indicare EDT o EST:

     UTC time   UTC time   UTC time 
        if [2] and [3] if [2] and [3] if [2] before 
local time   before switch after switch  and [3] after 
[1] 2016-11-06 00:43  04:43   04:43   04:43 
[2] 2016-11-06 01:15  05:15   06:15   05:15 
[3] 2016-11-06 01:45  05:45   06:45   06:45 
[4] 2016-11-06 03:25  07:25   07:25   07:25 

Times [2] e [3] può essere nella 5:00 calendario, l'06:00 temporale, o uno in 05:00 e l'altra nel tempo del 6 AM. . . In altre parole: tu sei un hosed, e devi buttare via tutte le letture tra 01:00:00 e 01:59:59. In questa circostanza, non esiste assolutamente alcun modo per risolvere il tempo UTC effettivo!

2

Ecco la mia versione veloce e sporca. So che tutte le mie date stavano usando il fuso orario degli Stati Uniti orientali. Puoi modificare l'offset o renderlo più intelligente quando necessario. Stavo facendo una migrazione una tantum, quindi questo era abbastanza buono.

CREATE FUNCTION [dbo].[ConvertToUtc] 
(
    @date datetime 
) 
RETURNS DATETIME 
AS 
BEGIN 
    -- Declare the return variable here 
    DECLARE @utcDate datetime; 
    DECLARE @offset int; 

    SET @offset = (SELECT CASE WHEN 
            @date BETWEEN '1987-04-05 02:00 AM' AND '1987-10-25 02:00 AM' 
           OR @date BETWEEN '1988-04-03 02:00 AM' AND '1988-10-30 02:00 AM' 
           OR @date BETWEEN '1989-04-02 02:00 AM' AND '1989-10-29 02:00 AM' 
           OR @date BETWEEN '1990-04-01 02:00 AM' AND '1990-10-28 02:00 AM' 
           OR @date BETWEEN '1991-04-07 02:00 AM' AND '1991-10-27 02:00 AM' 
           OR @date BETWEEN '1992-04-05 02:00 AM' AND '1992-10-25 02:00 AM' 
           OR @date BETWEEN '1993-04-04 02:00 AM' AND '1993-10-31 02:00 AM' 
           OR @date BETWEEN '1994-04-03 02:00 AM' AND '1994-10-30 02:00 AM' 
           OR @date BETWEEN '1995-04-02 02:00 AM' AND '1995-10-29 02:00 AM' 
           OR @date BETWEEN '1996-04-07 02:00 AM' AND '1996-10-27 02:00 AM' 
           OR @date BETWEEN '1997-04-06 02:00 AM' AND '1997-10-26 02:00 AM' 
           OR @date BETWEEN '1998-04-05 02:00 AM' AND '1998-10-25 02:00 AM' 
           OR @date BETWEEN '1999-04-04 02:00 AM' AND '1999-10-31 02:00 AM' 
           OR @date BETWEEN '2000-04-02 02:00 AM' AND '2000-10-29 02:00 AM' 
           OR @date BETWEEN '2001-04-01 02:00 AM' AND '2001-10-28 02:00 AM' 
           OR @date BETWEEN '2002-04-07 02:00 AM' AND '2002-10-27 02:00 AM' 
           OR @date BETWEEN '2003-04-06 02:00 AM' AND '2003-10-26 02:00 AM' 
           OR @date BETWEEN '2004-04-04 02:00 AM' AND '2004-10-31 02:00 AM' 
           OR @date BETWEEN '2005-04-03 02:00 AM' AND '2005-10-30 02:00 AM' 
           OR @date BETWEEN '2006-04-02 02:00 AM' AND '2006-10-29 02:00 AM' 
           OR @date BETWEEN '2007-03-11 02:00 AM' AND '2007-11-04 02:00 AM' 
           OR @date BETWEEN '2008-03-09 02:00 AM' AND '2008-11-02 02:00 AM' 
           OR @date BETWEEN '2009-03-08 02:00 AM' AND '2009-11-01 02:00 AM' 
           OR @date BETWEEN '2010-03-14 02:00 AM' AND '2010-11-07 02:00 AM' 
           OR @date BETWEEN '2011-03-13 02:00 AM' AND '2011-11-06 02:00 AM' 
           OR @date BETWEEN '2012-03-11 02:00 AM' AND '2012-11-04 02:00 AM' 
           OR @date BETWEEN '2013-03-10 02:00 AM' AND '2013-11-03 02:00 AM' 
           OR @date BETWEEN '2014-03-09 02:00 AM' AND '2014-11-02 02:00 AM' 
           OR @date BETWEEN '2015-03-08 02:00 AM' AND '2015-11-01 02:00 AM' 
           OR @date BETWEEN '2016-03-13 02:00 AM' AND '2016-11-06 02:00 AM' 
           OR @date BETWEEN '2017-03-12 02:00 AM' AND '2017-11-05 02:00 AM' 
           OR @date BETWEEN '2018-03-11 02:00 AM' AND '2018-11-04 02:00 AM' 
           OR @date BETWEEN '2019-03-10 02:00 AM' AND '2019-11-03 02:00 AM' 
           OR @date BETWEEN '2020-03-08 02:00 AM' AND '2020-11-01 02:00 AM' 
           OR @date BETWEEN '2021-03-14 02:00 AM' AND '2021-11-07 02:00 AM' 
           THEN 4 
           ELSE 5 END); 

    SELECT @utcDate = DATEADD(hh, @offset, @date) 
    RETURN @utcDate; 

END 
0

possiamo convertire ServerZone DateTime per UTC e UTC di ServerZone DateTime

Basta eseguire i seguenti script per capire la conversione quindi modificare come quello che vi serve

--Get Server's TimeZone 
DECLARE @ServerTimeZone VARCHAR(50) 
EXEC MASTER.dbo.xp_regread 'HKEY_LOCAL_MACHINE', 
'SYSTEM\CurrentControlSet\Control\TimeZoneInformation', 
'TimeZoneKeyName',@ServerTimeZone OUT 

-- ServerZone to UTC DATETIME 
DECLARE @CurrentServerZoneDateTime DATETIME = GETDATE() 
DECLARE @UTCDateTime DATETIME = @CurrentServerZoneDateTime AT TIME ZONE @ServerTimeZone AT TIME ZONE 'UTC' 
--(OR) 
--DECLARE @UTCDateTime DATETIME = GETUTCDATE() 
SELECT @CurrentServerZoneDateTime AS CURRENTZONEDATE,@UTCDateTime AS UTCDATE 

-- UTC to ServerZone DATETIME 
SET @CurrentServerZoneDateTime = @UTCDateTime AT TIME ZONE 'UTC' AT TIME ZONE @ServerTimeZone 
SELECT @UTCDateTime AS UTCDATE,@CurrentServerZoneDateTime AS CURRENTZONEDATE 

Nota: Questo (AT TIME ZONE) funziona solo su SQL Server 2016 + e questo vantaggio è auto considerando la Daylight durante la conversione in un particolare fuso orario