Come gestire correttamente TimeZone in SQL Server?


34

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?


Conversione efficace delle date tra l'ora UTC e l'ora locale (es. PST) in SQL 2005 http://stackoverflow.com/questions/24797/effectiveively-converting-dates-b
mehdi

Si tratta di un'applicazione web o un'applicazione desktop o ...? Il modo in cui questo viene implementato varia notevolmente a seconda del meccanismo di consegna del cliente, perché ciò di cui hai bisogno dipende dal lato client.
Jon Seigel,

Questo Web e il cellulare nativo. Sì, questo effetto differisce clienti diversi.
user960567

1
Sembra che la tua domanda non riguardi solo il database stesso, ma coinvolge anche lo sviluppo di applicazioni. Questa domanda di StackTranslate.it è una lettura obbligata per te quindi: Ora legale e Best practice per il fuso orario
Gan

Risposte:


48

Purtroppo non esiste una soluzione rapida per questo. L'internazionalizzazione di un'applicazione dovrebbe essere 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 essere sulla buona strada di Do It It Right, è essenziale memorizzare le informazioni sul fuso orario con il tempo . In altre parole, rendendosi conto che la data / ora 20130407 14:50è insignificante senza (a) includendo l'offset UTC allora corrente del fuso orario (nota 1) , oppure (b) assicurando che tutta la logica che inserisce questi valori converta prima in un determinato offset fisso ( molto probabilmente 0). Senza una di queste cose, due valori di tempo dati sono incomparabili e i dati sono corrotti . (A proposito , quest'ultimo metodo sta giocando con il fuoco (nota 2) ; non farlo.)

In SQL Server 2008+, è possibile memorizzare l'offset con l'ora direttamente utilizzando il datetimeoffsettipo di dati. (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 l'utilizzo datetimeoffset(o un composto di local timee 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 / bug 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 ora , 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.


3
Da quanto ho capito, uno scostamento non è lo stesso del fuso orario ... i tempi memorizzati in datetimeoffset perdono informazioni come la consapevolezza dell'ora legale ... Maggiori informazioni: stackoverflow.com/tags/timezone/info
Peter McEvoy

1
@PeterMcEvoy DST non ha rilevanza qui. datetimeoffsetsignifica "questa è l'ora locale dell'utente / del computer quando accadde la cosa" - non abbiamo bisogno di sapere se l'ora legale era in vigore o meno, perché l'offset UTC dato è sempre presente (incorporato nel datetimeoffsetvalore).
Dai

12

Ho sviluppato una soluzione completa per la conversione del fuso orario in SQL Server. Vedere Supporto fuso orario di 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 utility 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

Consulta 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, analogamente a come CONVERT_TZesiste la funzione in Oracle e MySQL.


6

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 in modo specifico tutto per andare in UTC, diventeremmo tutti pazzi molto velocemente.


5

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.


Un tale toolkit sembrerebbe essere di grande aiuto per uno sviluppatore. Tuttavia, una funzione scalare è una casella nera per Query Optimizer. Significa che quando applico la tua funzione a una colonna, le tabelle di configurazione che stai citando verranno colpite tante volte quante sono le righe nel set di risultati (supponendo che io utilizzi la funzione solo nella clausola SELECT). Non sembra una bella prospettiva in termini di prestazioni. Non ho ancora testato il tuo toolkit, quindi, non posso dirlo con certezza, è solo una preoccupazione generale basata su ciò che so.
Andriy M,

Andriy, certo, hai ragione dal punto di vista delle prestazioni. Le tabelle di query UDF non sono progettate per operazioni su dati di massa, ma per un facile utilizzo. Tuttavia, eseguono abbastanza bene fino a circa 100.000 dischi sulla mia macchina.
adss

2
Se uno deve elaborare più record nel suo caso d'uso e le prestazioni contano, è meglio pensare a dati precalcolati persistenti. Ma anche in questo caso, questi UDF potrebbero aiutare a mantenere i valori del datatime nei timzoni richiesti.
adss

Dal mio punto di vista, questo problema non riguarda le prestazioni, e altro ancora sull'ottenere le funzionalità di base. Essere in grado di restituire informazioni accurate da una query è la prima cosa. Elaborare alcune tabelle temporanee per memorizzare nella cache cose e quindi fare riferimento a quello nella query o comunque lo gestisci per migliorare le prestazioni diventa secondario.
Azione Dan

1

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.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.