此问题发生在夏令时更改期间。更改发生后,我们注意到我们的服务器应用程序开始写入日志的时间不正确 - 提前一小时,这意味着 .NET 缓存时区偏移量。我们不得不重新启动我们的应用程序来解决这个问题。我写了一个简单的应用程序来重现这个问题。当我在应用程序运行时更改时区时,DateTime.Now 属性会继续生成旧时区的时间。有谁知道除了重新启动应用程序之外是否有解决此问题的方法?
4 回答
是的,当前时区被缓存。有一个很好的理由,它避免了使用 DateTime.Now 来实现经过时间测量的损坏代码的麻烦。当时间突然改变一个小时或更长时间时,这样的代码往往会遭受心脏病发作。
您必须调用 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 文件的启动事件中调用它。
========== 还要确保检查 Windows Server 本身或本地计算机上的时区,具体取决于 IIS Web 服务器的运行位置。
在我的项目中,如果时间(或时区)发生更改,我需要重置一系列变量。为了让我知道发生了这个事件,我最终使用了 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