39

此问题发生在夏令时更改期间。更改发生后,我们注意到我们的服务器应用程序开始写入日志的时间不正确 - 提前一小时,这意味着 .NET 缓存时区偏移量。我们不得不重新启动我们的应用程序来解决这个问题。我写了一个简单的应用程序来重现这个问题。当我在应用程序运行时更改时区时,DateTime.Now 属性会继续生成旧时区的时间。有谁知道除了重新启动应用程序之外是否有解决此问题的方法?

4

4 回答 4

48

是的,当前时区被缓存。有一个很好的理由,它避免了使用 DateTime.Now 来实现经过时间测量的损坏代码的麻烦。当时间突然改变一个小时或更长时间时,这样的代码往往会遭受心脏病发作。

您必须调用 System.Globalization.CultureInfo.ClearCachedData() 来重置缓存值。对 DateTime.Now 的下一次调用现在将提供新的本地时间。如果您完全使用 .NET 3.5 TimeZoneInfo 类,那么您还需要调用其 ClearCachedData() 方法。您可以使用 SystemEvents.TimeChanged 事件作为触发器。

于 2008-11-17T22:24:19.623 回答
3

最常见的建议是存储 DateTime.UtcNow,当您想向用户显示本地时间时,转换为本地时间以考虑夏令时。

.NET 使用DaylightTimeTimeZone类提供涉及夏令时的计算,并且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 文件的启动事件中调用它。

========== 还要确保检查 Windows Server 本身或本地计算机上的时区,具体取决于 IIS Web 服务器的运行位置。

于 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 回答