【问题标题】:.NET DateTime.Now returns incorrect time when time zone is changed.NET DateTime.Now 在时区更改时返回不正确的时间
【发布时间】:2010-09-22 18:04:50
【问题描述】:

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

【问题讨论】:

    标签: .net datetime timezone dst


    【解决方案1】:

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

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

    【讨论】:

    • 感谢 ClearCachedData() - 提示。打电话的最佳时机是什么时候?也许存在一些系统范围的广播事件?感谢您提供信息。
    • SystemEvents.TimeChanged += (sender, args) => System.Globalization.CultureInfo.CurrentCulture.ClearCachedData();
    • 将 Windows 的区域设置更改为不同的国家/地区,与前一个不同的时区,不会影响 TimeZone.CurrentTimeZone,即使在清除缓存数据之后也是如此?
    【解决方案2】:

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

    .NET 使用 DaylightTimeTimeZone 类提供涉及夏令时的计算,并且 ToLocalTime 方法据说可以将 UTC 转换为夏令时的本地会计。

    【讨论】:

    • 你打败了我..我会删除我的答案.. ;)
    • 感谢您的回答。我忘了提到我知道 DateTime.UtcNow 属性是一种解决方法。我希望有其他方法来解决这个问题。它看起来像 .NET 框架中的错误。也许,我应该编辑我的问题。
    【解决方案3】:

    上面的完全限定类略有不同,但可能在 .NET 3.5 中发生了变化。

    System.Globalization.CultureInfo.CurrentCulture.ClearCachedData()
    

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

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

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

    【讨论】:

    • 检测到网络应用假设
    【解决方案4】:

    在我的项目中,如果时间(或时区)发生更改,我需要重置一系列变量。 为了让我知道发生此事件的事实,我最终使用了 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
    

    【讨论】:

      猜你喜欢
      • 2019-02-05
      • 2014-05-11
      • 2014-07-05
      • 2010-11-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-03-23
      相关资源
      最近更新 更多