.NET DateTime.Now返回时区更改时的错误时间

时间:2008-11-17 21:05:29

标签: .net datetime timezone dst

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

4 个答案:

答案 0 :(得分:46)

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

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

答案 1 :(得分:3)

最常见的建议是存储DateTime.UtcNow,并且当您想向用户显示本地化时间时,转换为本地时间会计以节省夏令时。

.NET提供了涉及DaylightTimeTimeZone类夏令时的计算,ToLocalTime方法可以将UTC转换为本地会计以获取夏令时。

答案 2 :(得分:1)

上面的完全限定类略有偏差,但可能在.NET 3.5中有所改变。

System.Globalization.CultureInfo.CurrentCulture.ClearCachedData()

也不要忘记包含(在C#.NET中)或导入(使用VB.NET)库引用System.Globalization.CultureInfo

在使用DateTime.Now之前调用它。虽然最好在Global.asax文件的启动事件中调用它。

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

答案 3 :(得分: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