この問題は、サマータイムの変更中に発生しました。変更が発生した後、サーバー アプリケーションが誤った時刻をログに書き込み始めたことに気付きました。これは、.NET がタイム ゾーン オフセットをキャッシュしていることを意味します。この問題を解決するには、アプリケーションを再起動する必要がありました。この問題を再現する簡単なアプリケーションを作成しました。アプリケーションの実行中にタイム ゾーンを変更すると、DateTime.Now プロパティは古いタイム ゾーンで時刻を生成し続けます。アプリケーションを再起動する以外に、この問題の回避策があるかどうかを知っている人はいますか?
4 に答える
はい、現在のタイム ゾーンがキャッシュされます。正当な理由により、DateTime.Now を使用して経過時間測定を実装する壊れたコードによる問題を回避します。このようなコードは、時間が突然 1 時間以上変わると心臓発作を起こす傾向があります。
System.Globalization.CultureInfo.ClearCachedData() を呼び出して、キャッシュされた値をリセットする必要があります。次に DateTime.Now を呼び出すと、新しいローカル タイムが返されます。.NET 3.5 TimeZoneInfo クラスを使用する場合は、その ClearCachedData() メソッドも呼び出す必要があります。SystemEvents.TimeChanged イベントをトリガーとして使用できます。
最も一般的な推奨事項は、DateTime.UtcNow を格納し、ローカライズされた時間をユーザーに表示する場合は、夏時間を考慮して現地時間に変換することです。
.NET は、DaylightTimeおよびTimeZoneクラスを使用して夏時間を含む計算を提供し、ToLocalTimeメソッドは、UTC を夏時間のローカル アカウンティングに変換できると思われます。
上記の完全修飾クラスは少しずれていましたが、.NET 3.5 で変更された可能性があります。
System.Globalization.CultureInfo.CurrentCulture.ClearCachedData()
また、ライブラリ リファレンスをインクルード (C#.NET の場合) またはインポート (VB.NET の場合) することも忘れないでください。System.Globalization.CultureInfo
を使用する直前に呼び出しDateTime.Now
ます。ただし、Global.asax ファイルのスタートアップ イベントで呼び出すのがおそらく最善です。
========== また、IIS Web サーバーが実行されている場所に応じて、Windows Server 自体、またはローカル マシンのタイムゾーンを確認していることを確認してください。
私のプロジェクトでは、時間 (またはタイムゾーン) が変更された場合、一連の変数をリセットする必要がありました。このイベントが発生したという事実を取得できるように、WindowsMessageFilter を使用することになりました。
私は .Net 2.0 を使用しているため、ClearCachedData を使用できませんでした (または、間違った場所を探している可能性があります)。
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