.NET DateTime.Now restituisce l'ora errata quando il fuso orario viene modificato
Domanda
Questo problema si è verificato durante il cambio dell'ora legale. Dopo che è avvenuta la modifica, abbiamo notato che la nostra applicazione server ha iniziato a scrivere nel registro l'ora errata - un'ora avanti, il che significa che .NET memorizza nella cache il fuso orario. Abbiamo dovuto riavviare la nostra applicazione per risolvere questo problema. Ho scritto una semplice applicazione per riprodurre questo problema. Quando cambio il fuso orario mentre l'applicazione è in esecuzione, la proprietà DateTime.Now continua a produrre l'ora nel vecchio fuso orario. Qualcuno sa se esiste una soluzione alternativa per questo problema oltre al riavvio dell'applicazione?
Soluzione
Sì, il fuso orario corrente viene memorizzato nella cache. Per una buona ragione, evita problemi con il codice non funzionante che utilizza DateTime.Now per implementare la misurazione del tempo trascorso. Tale codice tende a subire un attacco di cuore quando il tempo cambia improvvisamente di un'ora o più.
Dovrai chiamare System.Globalization.CultureInfo.ClearCachedData () per ripristinare il valore memorizzato nella cache. La prossima chiamata a DateTime.Now ora fornirà la nuova ora locale. Se usi la classe TimeZoneInfo .NET 3.5, dovrai anche chiamare il suo metodo ClearCachedData (). È possibile utilizzare l'evento SystemEvents.TimeChanged come trigger.
Altri suggerimenti
La raccomandazione più comune è quella di memorizzare DateTime.UtcNow e, quando si desidera mostrare all'utente l'ora locale, convertirla in contabilità dell'ora locale per l'ora legale.
.NET fornisce calcoli che prevedono l'ora legale con DaylightTime e TimeZone e le ToLocalTime può presumibilmente convertire UTC in contabilità locale per l'ora legale .
La classe pienamente qualificata sopra era leggermente disattivata, ma forse è cambiata in .NET 3.5.
System.Globalization.CultureInfo.CurrentCulture.ClearCachedData()
inoltre, non dimenticare di includere (in C # .NET) o importare (con VB.NET) il riferimento alla libreria System.Globalization.CultureInfo
Chiamalo subito prima di usare DateTime.Now
. Sebbene sia probabilmente meglio chiamarlo nell'evento di avvio del tuo file Global.asax.
========== Assicurati inoltre di controllare il fuso orario su Windows Server stesso o sul tuo computer locale a seconda di dove è in esecuzione il server Web IIS.
Nel mio progetto avevo bisogno di ripristinare una serie di variabili se il Time (o Timezone) fosse cambiato. Per poter capire il fatto che questo evento si sia verificato, ho finito con un filtro WindowsMessage.
Sto usando .Net 2.0 quindi non ho potuto usare (o forse sto cercando nei posti sbagliati) ClearCachedData, quindi ho usato questo approccio con l'aiuto di un piccolo riflesso.
Private mTZChangeFilter As WindowsMessageFilter
mTZChangeFilter = New WindowsMessageFilter()
AddHandler mTZChangeFilter.TimeChanged, AddressOf onTimeChanged
Application.RemoveMessageFilter(mTZChangeFilter)
Public Class WindowsMessageFilter
Implements IMessageFilter
<System.Diagnostics.DebuggerStepThrough()> _
Public Function PreFilterMessage(ByRef m As System.Windows.Forms.Message) As Boolean Implements System.Windows.Forms.IMessageFilter.PreFilterMessage
' Debug.Print(m.Msg.ToString)
If m.Msg = 30 Then
ResetTimeZone()
RaiseEvent TimeChanged(Me)
End If
End Function
Private Sub ResetTimeZone()
Dim tz As Type = GetType(System.TimeZone)
Dim mth As System.Reflection.MethodInfo
Try
mth = tz.GetMethod("ResetTimeZone", BindingFlags.NonPublic Or BindingFlags.Static)
mth.Invoke(mth, Nothing)
Catch ex As Exception
Debug.Print(ex.ToString)
End Try
End Sub
end class