2009-08-30 23 views
47

Sto memorizzando tutte le mie date nel formato UTC nel mio database. Chiedo all'utente il loro fuso orario e voglio usare il loro fuso orario più quello che ritengo sia il tempo del server per capire l'UTC per loro.Problemi di conversione del mio DateTime in UTC

Una volta ottenuto, desidero eseguire una ricerca per visualizzare l'intervallo nel database utilizzando la data UTC appena convertita.

ma ottengo sempre questa eccezione.

System.ArgumentException was unhandled by user code 
Message="The conversion could not be completed because the 
supplied DateTime did not have the Kind property set correctly. 
For example, when the Kind property is DateTimeKind.Local, 
the source time zone must be TimeZoneInfo.Local. 
Parameter name: sourceTimeZone" 

Non so perché sto ottenendo questo.

ho provato 2 modi

TimeZoneInfo zone = TimeZoneInfo.FindSystemTimeZoneById(id); 
// I also tried DateTime.UtcNow 
DateTime now = DateTime.SpecifyKind(DateTime.Now, DateTimeKind.Local); 
var utc = TimeZoneInfo.ConvertTimeToUtc(now , zone); 

questo non è riuscito quindi mi stanco

DateTime now = DateTime.SpecifyKind(DateTime.Now, DateTimeKind.Local); 
var utc = TimeZoneInfo.ConvertTimeBySystemTimeZoneId(now, 
              ZoneId, TimeZoneInfo.Utc.Id); 

Questo anche fallito entrambi con lo stesso errore. Che cosa sto facendo di sbagliato?

Modifica sarebbe questo lavoro?

DateTime localServerTime = DateTime.SpecifyKind(DateTime.Now, DateTimeKind.Local); 
TimeZoneInfo info = TimeZoneInfo.FindSystemTimeZoneById(id); 

var usersTime = TimeZoneInfo.ConvertTime(localServerTime, info); 

var utc = TimeZoneInfo.ConvertTimeToUtc(usersTime, userInfo); 

Edit 2 @ Jon Skeet

Ya Stavo solo pensando che io non potrei nemmeno bisogno di fare tutto questo. Le cose del tempo mi confondono in questo momento, ecco perché il post potrebbe non essere chiaro come dovrebbe essere. Non so mai cosa diavolo DateTime.Now sta ottenendo (ho provato a cambiare il mio fuso orario in un altro fuso orario e ha continuato a ottenere il mio fuso orario locale).

Questo è quello che volevo fare. L'utente arriva sul sito aggiunge un avviso e ora viene salvato come utc (prima era DateTime.Ora qualcuno suggeriva di memorizzare tutto UTC).

Quindi, prima che un utente arrivasse al mio sito e dipendesse dal mio server di hosting, potrebbe essere il giorno successivo. Quindi, se l'avviso fosse stato mostrato il 30 agosto (il loro tempo), ma con la differenza di fuso orario del server potevano arrivare il 29 agosto e l'avviso sarebbe stato mostrato.

Quindi volevo combatterlo. Quindi ora non sono sicuro di dover archiviare l'ora locale quindi utilizzare questo materiale offset? O semplicemente memorizzare l'ora UTC. Con la sola memorizzazione dell'ora UTC potrebbe ancora essere sbagliato, poiché l'utente probabilmente penserebbe ancora in ora locale e non sono sicuro di come l'UTC funzioni davvero potrebbe comunque finire una differenza di tempo.

Edit3

var info = TimeZoneInfo.FindSystemTimeZoneById(id) 

DateTimeOffset usersTime = TimeZoneInfo.ConvertTime(DataBaseUTCDate, 
              TimeZoneInfo.Utc, info); 
+0

'DateTime.Now.Kind' è già' Locale'; non è necessario chiamare 'SpecifyKind' su di esso. – SLaks

+0

@Edit 2: memorizza gli avvisi in UTC e li mostra nel fuso orario fornito dall'utente come mostrato nella mia risposta. – dtb

+0

Quindi, come funzionerebbe? Ottengo DateTime.UtcNow quindi filtro gli avvisi dal db? quindi convertire i risultati trovati nel loro tempo locale? – chobo2

risposta

30

La struttura DateTime supporta solo due fusi orari:.

  • Il locale fuso orario la macchina è in funzione in
  • e UTC.

Dai un'occhiata alla struttura DateTimeOffset.

var info = TimeZoneInfo.FindSystemTimeZoneById("Tokyo Standard Time"); 

DateTimeOffset localServerTime = DateTimeOffset.Now; 

DateTimeOffset usersTime = TimeZoneInfo.ConvertTime(localServerTime, info); 

DateTimeOffset utc = localServerTime.ToUniversalTime(); 

Console.WriteLine("Local Time: {0}", localServerTime); 
Console.WriteLine("User's Time: {0}", usersTime); 
Console.WriteLine("UTC:   {0}", utc); 

uscita:

Local Time: 30.08.2009 20:48:17 +02:00 
User's Time: 31.08.2009 03:48:17 +09:00 
UTC:   30.08.2009 18:48:17 +00:00 
+0

Sembra funzionare. Le cose del tempo confondono Devo leggere su questo DAteTimeOffSet e perché funziona e che la conversione non lo fa. Ma mi sto chiedendo non posso semplicemente DateTime.UtcNow? come quando lo faccio converte il tempo del mio server in data utc, che è lo stesso se ho fatto il tuo roba dataoffSet (usando West Africa Time). O sarebbero diversi? – chobo2

+1

Come dice Jon Skeet, se vuoi solo l'ora corrente in UTC, usa "DateTime.UtcNow" o "DateTimeOffset.UtcNow". – dtb

+0

Mi chiedo perché DateTime non fornisce una proprietà TimeZoneInfo, quindi potremmo specificare una data e l'ora insieme al fuso orario !? – brighty

85

è necessario impostare il Kind-Unspecified, in questo modo:

DateTime now = DateTime.SpecifyKind(DateTime.Now, DateTimeKind.Unspecified); 
var utc = TimeZoneInfo.ConvertTimeToUtc(now , zone); 

DateTimeKind.Local significa che il fuso orario locale e non qualsiasi altro fuso orario. Ecco perché stavi ricevendo l'errore.

+0

Ok, ci proverò. Funzionerebbe quello che ho appena modificato? Sembra essere spento (TimeZone Africa occidentale era spento di circa 10 minuti) quando si passa da un fuso orario a un altro, ma l'ora UTC era l'ora esatta. – chobo2

+0

Hmm quindi non funziona perché non conosce il fuso orario giusto? Poi sto ancora cercando qualcosa, perché penso di aver sbagliato volte. – chobo2

+0

Ho letto male il tuo codice; in realtà funzionerà. – SLaks

6

Come dice dtb, è necessario utilizzare DateTimeOffset se si desidera memorizzare una data/ora con un fuso orario specifico.

Tuttavia, non è affatto chiaro dal tuo post che è davvero necessario. Fornisci esempi solo usando DateTime.Now e dici che stai indovinando che stai utilizzando l'ora del server. A che ora vuoi veramente? Se si desidera solo l'ora corrente in UTC, utilizzare DateTime.UtcNow o DateTimeOffset.UtcNow. Non è necessario conoscere il fuso orario per conoscere l'ora UTC corrente, proprio perché è universale.

Se si ottiene una data/ora dall'utente in qualche altro modo, si prega di fornire maggiori informazioni - in questo modo saremo in grado di capire cosa è necessario fare. Altrimenti stiamo solo supponendo.

+0

vedi il mio post originale Edit2 – chobo2

2

UTC è solo un fuso orario che tutti hanno concordato come fuso orario standard. Nello specifico, è un fuso orario che contiene Londra, Inghilterra. EDIT: nota che non è lo stesso fuso orario; ad esempio, UTC non ha il DST. (Grazie, Jon Skeet)

L'unica cosa speciale di UTC è che è molto più facile da utilizzare in .Net rispetto a qualsiasi altro fuso orario (DateTime.UtcNow, DateTime.ToUniversalTime e altri membri).

Pertanto, come altri hanno già detto, la cosa migliore da fare per voi è il negozio tutte le date in UTC all'interno del database, poi convertire in ora locale dell'utente (scrivendo TimeZoneInfo.ConvertTime(time, usersTimeZone) prima di visualizzare.


Se si vuole essere più elaborato, è possibile geolocate gli indirizzi IP degli utenti di indovinare automaticamente i loro fusi orari

+0

Quelle saranno le versioni future lol. Devo prima capire le basi. – chobo2

+0

Allora cosa vuoi sapere adesso? – SLaks

+0

Quindi questo non darebbe un tempo diverso allora. Come prima ottenere tutti gli avvisi da UTC, quindi cambiarli in ora locale una volta trovato non causerà alcun avviso da perdere? Come il loro non sarà un po 'che dove solo un po' come quando un paio di minuti o qualcosa del genere? – chobo2

5

Ognuno risposta di altro sembra troppo complesso ho avuto un requisito specifico e questo ha funzionato bene per me:..

void Main() 
{ 
    var startDate = DateTime.Today; 
    var StartDateUtc = TimeZoneInfo.ConvertTimeBySystemTimeZoneId(DateTime.SpecifyKind(startDate.Date, DateTimeKind.Unspecified), "Eastern Standard Time", "UTC"); 
    startDate.Dump(); 
    StartDateUtc.Dump(); 
} 

quali uscite (da LINQPad) what I expected:

12/20/2013 12:00:00 AM

12/20/2013 5:00:00 AM

puntelli a Slaks per il suggerimento gentile non specificato. Questo è quello che mi mancava. Ma tutti i discorsi sul fatto che ci siano solo due tipi di date (locale e UTC) hanno confuso il problema per me.

FYI - il computer su cui l'ho eseguito era nel fuso orario centrale e l'ora legale non era in vigore.

Problemi correlati