39

この問題は、サマータイムの変更中に発生しました。変更が発生した後、サーバー アプリケーションが誤った時刻をログに書き込み始めたことに気付きました。これは、.NET がタイム ゾーン オフセットをキャッシュしていることを意味します。この問題を解決するには、アプリケーションを再起動する必要がありました。この問題を再現する簡単なアプリケーションを作成しました。アプリケーションの実行中にタイム ゾーンを変更すると、DateTime.Now プロパティは古いタイム ゾーンで時刻を生成し続けます。アプリケーションを再起動する以外に、この問題の回避策があるかどうかを知っている人はいますか?

4

4 に答える 4

48

はい、現在のタイム ゾーンがキャッシュされます。正当な理由により、DateTime.Now を使用して経過時間測定を実装する壊れたコードによる問題を回避します。このようなコードは、時間が突然 1 時間以上変わると心臓発作を起こす傾向があります。

System.Globalization.CultureInfo.ClearCachedData() を呼び出して、キャッシュされた値をリセットする必要があります。次に DateTime.Now を呼び出すと、新しいローカル タイムが返されます。.NET 3.5 TimeZoneInfo クラスを使用する場合は、その ClearCachedData() メソッドも呼び出す必要があります。SystemEvents.TimeChanged イベントをトリガーとして使用できます。

于 2008-11-17T22:24:19.623 に答える
3

最も一般的な推奨事項は、DateTime.UtcNow を格納し、ローカライズされた時間をユーザーに表示する場合は、夏時間を考慮して現地時間に変換することです。

.NET は、DaylightTimeおよびTimeZoneクラスを使用して夏時間を含む計算を提供し、ToLocalTimeメソッドは、UTC を夏時間のローカル アカウンティングに変換できると思われます。

于 2008-11-17T21:37:10.093 に答える
1

上記の完全修飾クラスは少しずれていましたが、.NET 3.5 で変更された可能性があります。

System.Globalization.CultureInfo.CurrentCulture.ClearCachedData()

また、ライブラリ リファレンスをインクルード (C#.NET の場合) またはインポート (VB.NET の場合) することも忘れないでください。System.Globalization.CultureInfo

を使用する直前に呼び出しDateTime.Nowます。ただし、Global.asax ファイルのスタートアップ イベントで呼び出すのがおそらく最善です。

========== また、IIS Web サーバーが実行されている場所に応じて、Windows Server 自体、またはローカル マシンのタイムゾーンを確認していることを確認してください。

于 2011-04-22T18:29:43.443 に答える
0

私のプロジェクトでは、時間 (またはタイムゾーン) が変更された場合、一連の変数をリセットする必要がありました。このイベントが発生したという事実を取得できるように、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
于 2009-06-26T07:37:59.490 に答える