Best practice per memorizzare DateTime in base a TimeZone


16

Sviluppo di un'applicazione Web che dovrebbe consentire all'utente di pianificare un appuntamento in base al proprio fuso orario. E sto memorizzando il datetime pianificato dall'utente come datetime del server nel campo del database. Durante la visualizzazione delle informazioni sulla pianificazione, è stato recuperato il valore dal database e convertito in timzone dell'utente. elaborazione in base di codice Sto convertendo il DateTime in base al fuso orario dell'utente. Si prega di suggerire questa best practice o esiste un modo semplice?

Risposte:


33

Benvenuti in uno dei problemi più difficili nella programmazione non computazionale: rappresentare correttamente date e orari per gli utenti finali.

Realisticamente, i timestamp dovrebbero essere archiviati in una singola rappresentazione fissa indipendentemente da come verranno interpretati, perché non importa quanto ci si provi, si avranno sempre casi ambigui e non è possibile risolverli senza una rappresentazione fissa. E hai scelto uno dei peggiori casi d'uso: programmare un appuntamento. L'unico caso di utilizzo comune peggiore è il trasporto aereo, in cui un viaggio potrebbe iniziare in un fuso orario e terminare in un altro, possibile in un orario locale precedente.

Sempre, sempre, SEMPRE archiviare in UTC e visualizzare nel fuso orario preferito o esplicitamente specificato dall'utente. Se possibile, fai in modo che l'utente ti dica in quale fuso orario crede che sia il timestamp quando lo inserisce ( ad esempio , ha un campo di fuso orario esplicito e lo precompila con la sua zona preferita).


1
+1. Ed è flessibile. Avendo un tempo di riferimento standard comune, coerente e universale, qualsiasi "dereferenziazione" locale verrà eseguita correttamente.
radarbob,

In realtà, la pianificazione di un appuntamento è una delle poche volte in cui si potrebbe non memorizzare come UTC: Se la variazione regole relative all'ora legale (o l'offset da UTC), cosa succede al tempo di appuntamento? Nella maggior parte dei casi, si desidera che l'orario dell'appuntamento rimanga lo stesso localmente, il che significa che il valore UTC cambia. Molto probabilmente vorrai memorizzare un valore che rappresenta "TimeInTimeZone + TimeZone", da cui potresti facilmente ricavare UTC. La pianificazione del fuso orario (come le compagnie aeree) ha dei vincoli che probabilmente significano una combinazione di entrambi.
Clockwork-Muse

1
Oh, c'è di peggio. Ho regolarmente incontri con colleghi di altre nazioni le cui regole sul cambio di tempo differiscono dalle mie. Quando ciò accade, qual è la risposta giusta? In realtà, nessun computer può sapere :-(
Ross Patterson,

3

Il modo più semplice per gestire le informazioni sulla data / ora dipende dai requisiti dell'applicazione.

Se la data e l'ora vengono immesse dall'utente e il server non elabora con tali informazioni data / ora se non per memorizzarle in un database e non si prevede che l'ora immessa venga adattata alla posizione in cui viene visualizzata (ad esempio , l'utente ha inserito "20:00" e dovrebbe essere visualizzato come "20:00" indipendentemente dal luogo in cui viene visualizzato), quindi il modo più semplice è memorizzare DateTime come ora locale senza alcuna informazione sul fuso orario.

D'altra parte, se il server deve utilizzare DateTime immesso come trigger per fare qualcosa o se l'ora deve essere regolata correttamente sul fuso orario corrente, l'opzione migliore è archiviare DateTime come ora UTC e regolarlo su locale time (per la posizione corrente dell'utente) ogni volta che lo leggi dal database.


-1 per "archiviarlo nell'ora locale", +1 per "archiviarlo nell'ora UTC".
Ross Patterson,

@RossPatterson: puoi spiegare '-1 per "archiviarlo nell'ora locale"? Sono curioso di sapere perché dovrebbe essere una cattiva idea, date le condizioni che mi hanno dato.
Bart van Ingen Schenau,

1
Ad esempio, l'utilizzo dell'ora locale dell'utente significa che ogni valore è effettivamente una delle diverse decine di tipi di dati diversi. Ciò significa che non è possibile eseguire operazioni su database interessanti come "TIMESTAMP> '2013-08-27T12: 00: 00'". Significa anche che non puoi sapere quando e se applicare le conversioni di ora legale.
Ross Patterson,

@RossPatterson: grazie. Concordo sul fatto che l'ora locale non è la soluzione giusta nella maggior parte dei casi.
Bart van Ingen Schenau,

2

È importante non confondere due concetti correlati.

Se stai manipolando un momento reale, ovvero un'ora specifica in un giorno specifico, l'unico modo per farlo è utilizzare sempre il valore orario universale UTC. Non tentare mai di archiviarlo come valore rilevante per il fuso orario. Quando si visualizza questo valore temporale per un utente, convertire sempre nel fuso orario dell'utente in quel momento. (E non dimenticare che l'ora e la data dipendono dal fuso orario.)

L'altro concetto è quello di una "espressione del tempo" come "20:00 ogni martedì". Hai menzionato espressamente il permesso alle persone di pianificare appuntamenti e, se hai appuntamenti ricorrenti, hai bisogno di un'espressione del genere. Non conosco alcun linguaggio di espressione standard, ma qualunque cosa tu usi, sarà relativa al fuso orario della persona che lo ha specificato. Sarebbe meglio renderlo esplicito, ad esempio "20:00 ogni martedì nel fuso orario del Pacifico". Nel caso di un'espressione temporale, la memorizzi sempre come stringa e non coinvolgi mai alcun formato orario del sistema.

Vedi altre discussioni di questo sul mio blog


1

Molte risposte qui indicano la memorizzazione come UTC. Ma stai molto attento con questo. Ad esempio, se pianifichi un appuntamento alle 12:00 ma l'appuntamento avviene dopo il passaggio all'ora legale, cosa accadrà? UTC non conserva alcuna informazione sull'attivazione di dst al momento della memorizzazione dell'appuntamento. Molti grandi e famosi sistemi hanno commesso questo errore, in cui un utente invia un'email alle 9:00 in estate, e poi in inverno l'orario inviato mostra le 8:00, perché il calcolo indietro da UTC dipende da quando si guarda il datetime, non attivo al momento della registrazione del datetime.

Molto meglio è supporre che l'utente voglia avere i tempi che sceglie sempre. Nessuna conversione UTC, nessuna conversione dell'ora, nessuna informazione sul fuso orario, niente. Prendere un appuntamento dalle 08:00 alle 12:00 il 21 marzo 2016 è proprio questo. Non utilizzare né l'ora locale né l'ora UTC, ma l'ora non specificata (in json questo non ha né z né +, in sostanza, in .NET questo ha DateTime.Kind = DateTimeKind.Unspecified).

Naturalmente, se il tuo caso d'uso è che sei una società che tiene riunioni con qualcuno di fusi orari diversi e vuoi vedere queste informazioni, ad esempio, in un calendario aziendale, ma consenti agli utenti di vedere che ora è nel loro fuso orario, diventa più complicato. Il tempo deve essere corretto per persone diverse in fusi orari diversi (fornitore e cliente).

In questi casi, potresti persino voler registrare quando l'appuntamento è stato salvato nel database, in quale fuso orario e se incluso dst o meno. In questo modo, puoi sempre calcolare l'ora locale su qualsiasi altra cosa, a quello che sarebbe ora o a quello che doveva essere storicamente. Poiché i fusi orari non sono statici, il che rende le cose ancora più complicate.

Fortunatamente, qui entrano in gioco biblioteche come http://nodatime.org/ che sono altamente raccomandate. Lavorano con le date in modo molto più coerente. Anche allora consiglierei di racchiudere tutte le variabili e la logica del tuo datetime nei tuoi wrapper, usando le interfacce in modo che possano essere derise e quindi puoi comunque cambiare logica in seguito.


Non sono del tutto d'accordo con le tue conclusioni, ma un incontro a mezzogiorno programmato per un cambio di ora legale è una sfida speciale, come sarebbe un incontro settimanale a mezzogiorno prenotato diversi anni nel futuro.
Piegato il

" Naturalmente, se il tuo caso d'uso è che sei una società che tiene riunioni con qualcuno di fusi orari diversi e vuoi vedere queste informazioni, ad esempio, in un calendario aziendale, ma consenti agli utenti di vedere che ora è nel loro fuso orario, diventa più complicato "- è praticamente ogni azienda. Pochissime aziende al di fuori della Cina e dell'India possono ignorare gli appuntamenti cross-timezone.
Ross Patterson,

"In questo modo, puoi sempre calcolare nuovamente l'ora locale su qualsiasi altra cosa, a quello che sarebbe ora o a quello che avrebbe dovuto essere storicamente. Perché i fusi orari non sono molto statici, rendendo le cose ancora più complicate " . accetti di fare calcoli, devi davvero scegliere una singola rappresentazione per volta. UTC, EST (ma non EST5EDT), IST, qualunque cosa. Ma semplicemente non puoi avere valori basati su più fusi orari nello stesso campo e fare qualsiasi elaborazione aggregata legittima su di essi. Elaborazione del display, certo. Ma questa è la parte facile.
Ross Patterson,

Almeno puoi ancora, correttamente, convertire in UTC. È sempre possibile creare una tabella di calcolo o un valore da queste informazioni in retrospettiva. Ma non puoi mai andare dall'altra parte. Si noti che SQL 2016 inizia a supportarlo in modo nativo, anche se sfortunatamente si basa ancora, almeno storicamente, su dati di registro non del tutto corretti, ma rappresenta ancora un altro miglioramento.
Arwin,
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.