it-swarm.it

Come gestire correttamente TimeZone in SQL Server?

Il mio server di sviluppo locale è in Medio Oriente, ma il mio server di produzione è nel Regno Unito.

Devo mostrare la data all'utente nel suo fuso orario. Ad esempio, se un utente si trova in Arabia Saudita, allora devo mostrare l'ora in base al formato dell'Arabia Saudita.

Devo creare una nuova tabella di database chiamata TimeZone e salvare l'ora in UTC?

39
user960567

Purtroppo non esiste una soluzione rapida per questo. L'internazionalizzazione di un'applicazione dovrebbe far parte delle prime discussioni di progettazione, in quanto va davvero al centro di molte aree diverse, tra cui confronti di data/ora e formattazione dell'output.

Ad ogni modo, per seguire la strada del Do Right, è essenziale memorizzare le informazioni sul fuso orario con l'ora. In altre parole, rendendosi conto che la data/ora 20130407 14:50 is insignificante senza (a) incluso l'offset UTC allora attuale del fuso orario(nota 1)oppure (b) assicurando che tutta la logica che inserisce questi valori si converta prima in un determinato offset fisso (molto probabilmente 0). Senza una di queste cose, due valori di tempo indicati sono incomparabile, e i dati sono corrotto. (Quest'ultimo metodo sta giocando con il fuoco(nota 2), a proposito; non farlo.)

In SQL Server 2008+, è possibile memorizzare l'offset con l'ora direttamente utilizzando il tipo di dati datetimeoffset . (Per completezza, nel 2005 e prima, aggiungerei una seconda colonna per memorizzare il valore di offset UTC allora attuale (in minuti).)

Ciò semplifica un'applicazione di tipo desktop, poiché queste piattaforme normalmente dispongono di meccanismi per convertire automaticamente una data/ora + fuso orario in un'ora locale e quindi formattare per l'output, il tutto in base alle impostazioni internazionali dell'utente.

Per il Web, che è un'architettura intrinsecamente disconnessa, anche con i dati di back-end impostati correttamente, è più complesso perché sono necessarie informazioni sul client per poter eseguire la conversione e/o la formattazione. Questo di solito viene fatto tramite le impostazioni delle preferenze dell'utente (l'applicazione converte/formatta le cose prima dell'output) o semplicemente mostra le cose con lo stesso formato fisso e offset del fuso orario per tutti (che è ciò che attualmente fa la piattaforma Stack Exchange).

Puoi vedere come se i dati di back-end non sono impostati correttamente, molto rapidamente diventerà complicato e confuso. Non consiglierei di seguire nessuno di questi percorsi perché finirai con ulteriori problemi lungo la linea.

Nota 1:

L'offset UTC di un fuso orario non è fisso: considera l'ora legale in cui l'offset UTC di una zona varia di più o meno di un'ora. Anche le date dell'ora legale delle zone variano regolarmente. Quindi usando datetimeoffset (o un composto di local time e UTC offset at that time) porta al massimo recupero delle informazioni.

Nota 2:

Si tratta di controllare gli input di dati. Anche se non esiste un modo infallibile per convalidare i valori in entrata, è meglio applicare uno standard semplice che non comporti calcoli. Se un'API pubblica prevede un tipo di dati che include un offset, tale requisito sarà chiaro al chiamante.

In caso contrario, il chiamante deve fare affidamento sulla documentazione (se la legge) o il calcolo viene eseguito in modo errato, ecc. Esistono meno modalità di errore/errore quando si richiede un offset, in particolare per un sistema distribuito ( o anche solo web/database su server separati come il caso qui).

La memorizzazione dell'offset uccide comunque due uccelli con una fava; e anche se ciò non è richiesto adesso, rende disponibile la possibilità in seguito, se necessario. È vero che occupa più spazio di archiviazione, ma penso che valga la pena compensare perché i dati vengono persi se non vengono mai registrati in primo luogo.

51
Jon Seigel

Ho sviluppato una soluzione completa per la conversione del fuso orario in SQL Server. Vedere Supporto fuso orario SQL Server su GitHub .

Gestisce correttamente le conversioni tra i fusi orari e verso e da UTC, inclusa l'ora legale.

È simile nel concetto alla soluzione "T-SQL Toolbox" descritta nella risposta di adss, ma utilizza i fusi orari IANA/Olson/TZDB più comuni invece di quelli di Microsoft e include utilità per mantenere i dati mantenuti come nuove versioni del TZDB esce.

Esempio di utilizzo (per rispondere al PO):

SELECT Tzdb.UtcToLocal(sysutcdatetime(), 'Asia/Riyadh') as CurrentTimeInSaudiArabia

Vedi il file Leggimi su GitHub per API aggiuntive e spiegazioni dettagliate.

Inoltre, si noti che poiché si tratta di una soluzione basata su UDF, non è progettata con le prestazioni come obiettivo primario. Sarebbe comunque meglio se questa funzionalità fosse integrata in SQL Server, in modo simile a come il CONVERT_TZ La funzione esiste in Oracle e MySQL.

15

Ho sviluppato e pubblicato il progetto "T-SQL Toolbox" su codeplex per aiutare chiunque abbia difficoltà a gestire il datetime e il fuso orario in SQL Server. È open source e completamente gratuito da usare.

Offre UDF di conversione datetime semplici utilizzando T-SQL semplice con tabelle di configurazione aggiuntive pronte all'uso.

Nel tuo esempio, puoi usare il seguente esempio:

SELECT [DateTimeUtil].[UDF_ConvertLocalToLocalByTimezoneIdentifier] (
    'GMT Standard Time', -- the original timezone in which your datetime is stored
    'Middle East Standard Time', -- the target timezone for your user
    '2014-03-30 01:55:00' -- the original datetime you want to convert
)

Ciò restituirà il valore datetime convertito per il tuo utente.

Un elenco di tutti i fusi orari supportati è disponibile nella tabella "DateTimeUtil.Timezone" fornita anche nel database T-SQL Toolbox.

7
adss

SQL Server ha apportato modifiche dal 2005 in poi in cui il fuso orario interno è stato salvato in UTC. Ciò è dovuto in gran parte alla replica geografica e ai proiettori HA che comportano la spedizione dei registri e che i tempi di consegna dei registri salvati in diversi fusi orari hanno reso impossibile per il vecchio metodo ripristinarli.

Pertanto, il salvataggio di tutto internamente in tempo UTC ha consentito a SQL Server di funzionare bene a livello globale. Questo è uno dei motivi per cui l'ora legale è una seccatura da affrontare in Windows, perché anche altri prodotti MS come Outlook salvano la data/ora internamente come UTC e creano un offset che deve essere patchato.

Lavoro in una società in cui abbiamo migliaia di server (non MS SQL Server, ma tutti i tipi di server) sparsi in tutto il mondo, e se non forzassimo specificamente tutto per andare in UTC, diventeremmo tutti pazzi molto velocemente.

6
Ali Razeghi

Potrei mancare qualcosa di ovvio, ma se tutto ciò che vuoi fare è visualizzare la data utilizzando il fuso orario dell'utente e il formato della lingua, il modo più semplice è archiviare sempre le date in UTC nel database e consentire all'applicazione client di convertire da UTC a locale fuso orario e utilizzare le impostazioni internazionali dell'utente per formattare la data di conseguenza.

1
20c