2013-06-01 8 views
13

Ho una colonna di timestamp UNIX nella tabella del mio database, che proviene da un sistema che si trova nel fuso orario del Kuwait.Conversione data ora da fuso orario a fuso orario in server sql

Il fuso orario del mio server di database è Eastern Time US & Canada. Ora ho bisogno di convertire il timestamp UNIX in valore di data fuso orario Kuwait utilizzando una query SQL.

Qualcuno può dirmi come posso convertire questo timestamp UNIX in un valore di data del fuso orario del Kuwait?

risposta

24

I timestamp Unix sono un numero intero di secondi dal primo gennaio 1970 UTC.

Supponendo che si abbia una colonna intera nel database con questo numero, il fuso orario del server del database non è rilevante.

prima convertire il timestamp a un tipo datetime:

SELECT DATEADD(second, yourTimeStamp, '1970-01-01') 

Questo sarà l'UTC datetime che corrisponde al timestamp.

Quindi è necessario sapere come regolare questo valore sul fuso orario target. In gran parte del mondo, una singola zona può avere più offset, a causa dell'ora legale.

Sfortunatamente, SQL Server non ha la capacità di lavorare direttamente in fusi orari lavorativi. Quindi, se tu fossi, ad esempio, utilizzando il tempo del Pacifico americano, non avresti modo di sapere se dovresti sottrarre 7 ore o 8 ore. Altri database (Oracle, Postgres, MySql, ecc.) Hanno metodi integrati per gestirli, ma ahimè, SQL Server no. Quindi, se siete alla ricerca di una soluzione di uso generale, è necessario effettuare una delle seguenti operazioni:

  • dati di fuso orario Importa in una tabella, e mantenere quel tavolo come regole di fuso orario cambiano. Usa quella tabella con un po 'di logica personalizzata per risolvere l'offset per una data particolare.

  • Utilizzare xp_regread per ottenere le chiavi del Registro di sistema di Windows che contengono i dati del fuso orario e utilizzare nuovamente una serie di logica personalizzata per risolvere l'offset per una data specifica. Naturalmente, xp_regread è una brutta cosa da fare, richiede determinate autorizzazioni concesse e non è supportato o documentato.

  • Scrivere una funzione SQLCLR che utilizza la classe TimeZoneInfo in .Net. Sfortunatamente, questo requires an "unsafe" SQLCLR assembly e potrebbe causare problemi.

IMHO, nessuno di questi approcci è molto buono e non esiste una buona soluzione per farlo direttamente in SQL. La soluzione migliore sarebbe quella di restituire il valore UTC (sia il numero intero originale o lo datetime all'UTC) al codice dell'applicazione chiamante, e invece eseguire la conversione del fuso orario (con, ad esempio, TimeZoneInfo in. Netto o meccanismi simili in altri piattaforme).

TUTTAVIA: avete scoperto che il Kuwait è (ed è sempre stato) in una zona che non cambia per l'ora legale. È sempre stato UTC + 03: 00. Così si può semplicemente aggiungere tre ore e restituire il risultato:

SELECT DATEADD(hour, 3, DATEADD(second, yourTimeStamp, '1970-01-01')) 

Ma non riconoscere che questa non è una soluzione general purpose che funzionerà in qualsiasi fuso orario.

Se si desidera, è possibile restituire uno degli altri tipi di dati SQL, come ad esempio datetimeoffset, ma ciò consentirà solo di riflettere che il valore è di tre ore sfalsato rispetto a chi potrebbe guardarlo. Non renderà il processo di conversione diverso o migliore.


risposta Aggiornato

Ho creato un progetto per il supporto di fusi orari in SQL Server. È possibile installarlo from here. Poi si può semplicemente convertire in questo modo:

SELECT Tzdb.UtcToLocal('2015-07-01 00:00:00', 'Asia/Kuwait') 

È possibile utilizzare any time zone from the IANA tz database, compresi quelli che utilizzano l'ora legale.

È ancora possibile utilizzare il metodo illustrato sopra per convertire da un timestamp unix. mettendoli entrambi insieme:

SELECT Tzdb.UtcToLocal(DATEADD(second, yourTimeStamp, '1970-01-01'), 'Asia/Kuwait') 

nuovamente aggiornato

Con SQL Server 2016, non v'è ora costruito un supporto per i fusi orari con la dichiarazione AT TIME ZONE. Questo è disponibile anche nel database SQL di Azure (v12).

SELECT DATEADD(second, yourTimeStamp, '1970-01-01') AT TIME ZONE 'Arab Standard Time' 

More examples in this announcement.

+0

Io uso questa query e funziona per me. SELECT CAST (SWITCHOFFSET (CAST (dateadd (s, 1356052117, '01/01/1970 ') AS datetimeoffset),' +03: 00 ') AS DATETIME) AS [Data] –

+2

Bene, la commutazione dell'offset è buona - se lavorerai con 'DateTimeOffset' nella tua applicazione. Ma se si esegue il ritorno a un 'datetime', non c'è alcun reale vantaggio aggiunto. Potresti anche aggiungere 3 ore. –

+0

Inoltre, vedo che stai trasmettendo "date" alla fine. Ciò troncherà qualsiasi componente temporale. A meno che non sia ciò che volevi, dovresti invece eseguire il cast di 'datetime'. –