2009-05-07 6 views
28

Sto lavorando su un progetto di "sistema di promemoria online" (ASP.NET 2.0 (C#)/SQL Server 2005)Come lavorare con i fusi orari in ASP.NET?

come questo è un servizio di promemoria che invierà la posta agli utenti su un particolare date. Ma il problema è che gli utenti non provengono da paesi specifici, provengono da tutto il mondo e da diversi fusi orari. Ora, quando mi registro, chiedo il fuso orario degli utenti nello stesso modo in cui Windows chiede il nostro fuso orario al momento dell'installazione.

Ma non sto ottenendo se l'utente ha selezionato (+5.30) o qualcosa di fuso orario quindi come gestire questo fuso orario nella mia applicazione asp.net. Come lavorare in base al fuso orario.

E si prega di suggerire se c'è un modo migliore per gestire i fusi orari in questa applicazione ??

Grazie

+0

Questa domanda potrebbe essere vecchia e avere una risposta accettata, ma è piuttosto ampia e le risposte riguardano solo un aspetto del problema. La risposta è anche errata, in quanto la soluzione consigliata non copre l'ora legale e utilizza 'TimeZoneInfo' - che non era disponibile in .NET 2.0 (che come requisito di questa domanda). Raccomando che questa domanda sia chiusa o cancellata. –

risposta

27

La prima cosa è quello di assicurarsi che il fuso orario i dati sono in. Vorrei raccomandare facendo in modo che qualsiasi DateTime di conservare, viene memorizzato in ora UTC (utilizzare il DateTime.ToUniversalTime() per entrare in possesso di esso) .

Quando si memorizza un promemoria per un utente, è necessario l'ora UTC corrente, aggiungere o rimuovere la differenza di fuso orario dell'utente e convertire tale nuovo tempo in UTC; questo è ciò che vuoi memorizzare nel DB.

Quindi, quando si desidera verificare l'invio di promemoria, è sufficiente cercare nel database i promemoria da inviare ora, in base all'ora UTC; in sostanza ottenere tutti i promemoria che hanno un timestamp che è prima di DateTime.Now.ToUniversalTime().

Aggiornamento con alcune specifiche di implementazione: È possibile ottenere un elenco dei fusi orari del metodo di TimeZoneInfo.GetSystemTimeZones(); è possibile utilizzare quelli per mostrare un elenco di fusi orari per l'utente. Se si memorizza la proprietà Id dal fuso orario selezionato, è possibile creare un'istanza di classe TimeZoneInfo da esso, e calcolare il tempo UTC per un dato valore di data/ora locale:

TimeZoneInfo tzi = TimeZoneInfo.FindSystemTimeZoneById("<the time zone id>"); 
// May 7, 08:04:00 
DateTime userDateTime = new DateTime(2009, 5, 7, 8, 4, 0); 
DateTime utcDateTime = userDateTime.Subtract(tzi.BaseUtcOffset); 
+0

Ok, la tua idea sembra buona, ma mi sento un problema lì. Hai detto "occorrerà l'ora UTC corrente, aggiungere o rimuovere la differenza di fuso orario dell'utente e riconvertire quella nuova ora in UTC". ma ora quando eseguirò il mio processo che invierà i promemoria. Mi trovo nel fuso orario indiano (IST), quindi quando dovrei eseguire i promemoria in modo che il promemoria venga inviato agli utenti al momento giusto. – Prashant

+0

Invece di archiviare in UTC, ho pensato: avrò tre colonne nella mia tabella reminder_schedule che sarà "Original_DateTime", "UTC_DateTime" e "IST_DateTime". Ora Data ora Original_DateTime memorizzerà la data esatta impostata dall'utente. UTC_DateTime memorizzerà l'UTC DateTime sulla base del fuso orario degli utenti. e l'ultimo "IST_DateTime" memorizzerà il datetime in base a Indian Timezone convertendo UTC_DateTime in Indian TimeZone. Quindi, infine, eseguirò i miei promemoria inviando il processo seguendo le indicazioni di INdian tmezone e quindi tutti i promemoria verranno inviati in tempo esatto. – Prashant

+0

Non sono sicuro che l'idea che ho dato sopra sia perfetta ma questi sono i miei pensieri, per favore dimmi come devo procedere ulteriormente? – Prashant

0

In sostanza, tutto quello che dovete fare è aggiungere l'offset (ore + minuti) all'ora locale inserita dall'utente. L'aggiunta dell'offset ti dà fondamentalmente un DateTime nel fuso orario UTC (fondamentalmente GMT).

In genere è più semplice standardizzare tutti i tempi in UTC, in modo che la logica dell'applicazione non debba occuparsi degli scostamenti.

Questa pagina ha un paio di buoni esempi: http://msdn.microsoft.com/en-us/library/bb546099.aspx

2

Si consiglia di guardare con la struttura DateTimeOffset invece del DateTime se siete su framework 2.0 o versione successiva.

DateTimeOffset rappresenta un punto nel tempo relativo all'ora UTC, quindi in questo caso dovrebbe essere più semplice lavorare.

18

consiglierei di sempre uso UTC (GMT) sul lato server (in code-behind, database, ecc), e convertire il tempo da UTC a ora locale per scopi di visualizzazione solo. Ciò significa che tutte le manipolazioni temporali, compreso il risparmio di tempo nel database, l'esecuzione di calcoli, ecc., Dovrebbero essere eseguite utilizzando l'UTC.

Il problema è: come fa il code-behind a sapere qual è il fuso orario del browser client? Supponiamo che l'utente inserisca un determinato valore data/ora (ad esempio 12/30/2009 14:30) nel modulo e lo invii al server. Supponendo che l'utente abbia inviato l'ora locale, come fa il server a sapere come convertire questo valore in UTC?

L'applicazione può chiedere all'utente di specificare il fuso orario (e salvarlo in un cookie o database persistente), ma richiede uno sforzo extra da parte dell'utente e l'app dovrà implementare la logica e gli schermi per questo . Sarebbe più bello se l'app potesse determinare automaticamente il fuso orario del client.

Ho risolto questo problema con l'aiuto della funzione JavaScript getTimezoneOffset, che è l'unica API in grado di comunicare al server la differenza di orario tra ora locale sul client e GMT. Poiché si tratta di un'API lato client, ho eseguito le seguenti operazioni: sul lato server, verificare la presenza di un cookie di sessione personalizzato contenente il valore dell'offset temporale e, se non è disponibile, ricaricare la pagina (solo durante GET e non POST, chiamate) con alcune logiche JavaScript aggiunte per generare l'offset temporale e salvarlo nel cookie. Dal lato client questo è quasi trasparente (una volta durante la sessione ricarico una pagina su GET). Una volta che ho l'offset nel cookie, lo applico alle funzioni di gestione del tempo a seconda della direzione della conversione del tempo (da UTC a ora locale o da ora locale a UTC).

Questo può sembrare un po 'complicato, e lo è, ma dopo che ho scritto funzioni di aiuto, integrando questa funzionalità nel sito era una questione di fare un singola chiamata in Page_Load (di pagine che avevano bisogno di tempo di conversione), e utilizzando le routine di conversione del tempo durante l'invio e il recupero dei valori temporali da e verso il browser. Ecco un esempio di come può essere utilizzato:

using My.Utilities.Web; 
... 

// Derive the form class from BaseForm instead of Page. 
public class WebForm1: BaseForm 
{ 
... 
private void Page_Load(object sender, System.EventArgs e) 
{ 
    // If we only want to load the page to generate the time 
    // zone offset cookie, we do not need to do anything else. 
    if (InitializeLocalTime()) 
    return; 

    // Assume that txtStartDate is a TextBox control. 
    if (!IsPostback) 
    { 
    // To display a date-time value, convert it from GMT (UTC) 
    // to local time. 
    DateTime startDate = GetStartDateFromDB(...); 
    txtStartDate.Text = FormatLocalDate(startDate); 
    ... 
    } 
    else 
    { 
    // To save a date-time value, convert it from local 
    // time to GMT (UTC). 
    DateTime tempDate = DateTime.Parse(txtStartDate.Text); 
    DateTime startDate = ConvertLocalTimeToUtc(tempDate); 
    SaveStartDateInDB(startDate, ...); 
    ... 
    } 
} 
... 
} 

Se avete bisogno di più specifiche, controlla l'articolo It’s About Time: Localizing Time in ASP.NET Applications (mi dispiace, ma non ho un collegamento diretto con l'articolo sul sito dell'editore, dal momento che asp .netPRO limita l'accesso solo agli abbonati pagati, tuttavia ci sono collegamenti alle copie PDF. Vorrei poter postare il campione dell'articolo, ma non voglio violare il copyright; tuttavia, ecco uno project to build a helper library che ha tutte le funzionalità e la documentazione necessarie (ignora solo le cose che non ti servono).

AGGIORNAMENTO: L'articolo è stato pubblicato online con il progetto di esempio del nuovo editore here.

+0

Non sono d'accordo con l'affermazione che la tua app dovrebbe determinare automaticamente il fuso orario dell'utente. Gli utenti possono impostare qualsiasi fuso orario/data/ora desiderato nel proprio sistema operativo e ignorare le regole aziendali. Non fidarti mai dell'input dell'utente. – BrunoSalvino

+4

Non capisco il tuo punto, Bruno. Innanzitutto, non ci sono regole aziendali associate ai fusi orari. È un problema di usabilità. Potremmo aver utilizzato GMT, ma non è conveniente per gli utenti, quindi usiamo l'ora locale. Se l'utente cambia l'orologio di sistema (o in qualsiasi modo utilizzi per specificare il fuso orario), a chi importa? Non vedo un problema qui. Inoltre, non sto seguendo una transizione dalla prima affermazione alla seconda affermazione. Non ti piace la parte "automatica" o non ti piace affatto l'idea di utilizzare l'ora locale (se non viene eseguita automaticamente, l'utente deve essere in grado di cambiarla in qualche modo, giusto)? –

+0

+1. @BrunoSalvino, come suggeriresti di passare i dati del fuso orario? L'altro modo in cui posso pensare di fare questo è fornire un input esplicito da parte dell'utente. Quest'ultimo è ancora meno affidabile della soluzione automatica proposta qui, poiché l'utente ha maggiori probabilità di sbagliare. Dal punto di vista dell'utente ciò richiederà input del fuso orario, che non sono user-friendly soprattutto quando la pagina non richiede nemmeno informazioni sulla data, ma deve ancora mantenere la data e l'ora di determinate interazioni dell'utente (come il tempo in cui l'utente ha caricato alcuni file o ha fatto una transazione finanziaria). –

3

Il problema con tutte le risposte finora è che non tengono conto di ciò che Prashant sta cercando di raggiungere. Se l'utente del suo sistema il giorno prima della modifica dell'ora legale ha un offset di +12 e imposta un promemoria per il giorno successivo, il suo offset quando il promemoria dovrebbe essere attivato sarà invece di +13.

Ecco perché è possibile utilizzare solo l'offset corrente per qualcosa che sta accadendo ora. Anche se sono d'accordo con tutti gli altri sul fatto che tutte le volte lato server (tranne forse quelle usate solo per la visualizzazione) dovrebbero essere memorizzate in UTC.

0

Il problema è che l'offset da UTC varierà in diversi periodi dell'anno - ogni fuso orario ha le proprie regole. (Ho imparato questo nel modo più duro quando si sviluppa sala riunioni di pianificazione app.)

Sembra che ci sia built-in supporto qui: http://msdn.microsoft.com/en-us/library/system.timezoneinfo.converttime.aspx

non ho provato io stesso, ma sembra promettere la conversione corretta, contabilità per l'ora legale.

Se no, ecco un (costoso) strumento commerciale che ho usato: http://www.worldtimeserver.com/time_zone_guide/

1

Ci sono 2 fasi:

  • Rileva fuso orario differente al lato client utilizzando Javascript:

    var dt = new Date(); 
    var diffInMinutes = -dt.getTimezoneOffset(); 
    
  • Quindi sul lato server, codice C# per convertire l'ora del server in ora client in base all'offset fuso orario rilevato sopra:

------------------------;

string queryStr = Request.QueryString["diffInMinutes"]; 
int diffInMinutes = 0; 
if (Int32.TryParse(queryStr, out diffInMinutes)) 
{ 
    clientTime = serverTime.ToUniversalTime().AddMinutes(diffInMinutes); 
} 
+0

Funziona per me. Buon esempio. Il problema non è archiviare la data come UTC come è stato mostrato che esiste già un metodo "ToUniveralTime()" per la conversione in UTC, se necessario. Il vero problema è ottenere il fuso orario locale sfalsato dove si trova il client. Questo esempio funziona egregiamente anche per MVC dove gli oggetti JSON vengono passati al controller. –