.NET DateTime.Now 在时区更改时返回不正确的时间
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/296918/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
.NET DateTime.Now returns incorrect time when time zone is changed
提问by GregK
This problem occurred during daylight saving time change. After the change occurred, we've noticed that our server application started writing into the log incorrect time - one hour ahead which means that .NET caches time zone offset. We had to restart our application to resolve this problem. I wrote a simple application to reproduce this problem. When I change the time zone while application is running, DateTime.Now property keeps producing the time in the old time zone. Does anybody know if there is a workaround for this problem apart from restarting the application?
此问题发生在夏令时更改期间。更改发生后,我们注意到我们的服务器应用程序开始写入日志的时间不正确 - 提前一小时,这意味着 .NET 缓存时区偏移。我们不得不重新启动我们的应用程序来解决这个问题。我写了一个简单的应用程序来重现这个问题。当我在应用程序运行时更改时区时,DateTime.Now 属性会继续生成旧时区的时间。除了重新启动应用程序之外,有人知道是否有解决此问题的方法吗?
回答by Hans Passant
Yes, the current time zone is cached. For a good reason, it avoids trouble with broken code that uses DateTime.Now to implement elapsed time measurement. Such code tends to suffer a heart-attack when the time suddenly changes by an hour or more.
是的,当前时区已缓存。有一个很好的理由,它避免了使用 DateTime.Now 实现经过时间测量的损坏代码的麻烦。当时间突然改变一个小时或更长时间时,这样的代码往往会遭受心脏病发作。
You will have to call System.Globalization.CultureInfo.ClearCachedData() to reset the cached value. The next call to DateTime.Now will now give the new local time. If you use the .NET 3.5 TimeZoneInfo class at all then you'll also need to call its ClearCachedData() method. You can use the SystemEvents.TimeChanged event as a trigger.
您必须调用 System.Globalization.CultureInfo.ClearCachedData() 来重置缓存值。对 DateTime.Now 的下一次调用现在将给出新的本地时间。如果您完全使用 .NET 3.5 TimeZoneInfo 类,那么您还需要调用其 ClearCachedData() 方法。您可以使用 SystemEvents.TimeChanged 事件作为触发器。
回答by GregK
The most common recommendation is to store DateTime.UtcNow and, when you want to show localized time to the user, convert to local time accounting for daylight savings.
最常见的建议是存储 DateTime.UtcNow,当您想向用户显示本地化时间时,转换为本地时间以考虑夏令时。
.NET provides for calculations involving daylight savings time with the DaylightTimeand TimeZoneclasses, and the ToLocalTimemethod supposedly can convert UTC to local accounting for daylight savings time.
.NET 通过DaylightTime和TimeZone类提供涉及夏令时的计算,并且ToLocalTime方法据说可以将 UTC 转换为夏令时的本地会计。
回答by MacGyver
The fully qualified class above was slightly off, but perhaps it changed in .NET 3.5.
上面的完全限定类略有偏差,但可能在 .NET 3.5 中发生了变化。
System.Globalization.CultureInfo.CurrentCulture.ClearCachedData()
also don't forget to include (in C#.NET) or import (with VB.NET) the library reference System.Globalization.CultureInfo
也不要忘记包含(在 C#.NET 中)或导入(使用 VB.NET)库引用 System.Globalization.CultureInfo
Call it just before using DateTime.Now. Although it's probably best to call it in the startup event of your Global.asax file.
在使用之前调用它DateTime.Now。尽管最好在 Global.asax 文件的启动事件中调用它。
========== Also make sure you're checking the timezone on Windows Server itself, or your local machine depending on where the IIS web server is running.
========== 还要确保您正在检查 Windows Server 本身或本地计算机上的时区,具体取决于 IIS Web 服务器的运行位置。
回答by Paul Farry
In my project I needed to Reset a series of variables if the Time (or Timezone) was changed. So that I could get the fact this event occurred I ended up using a WindowsMessageFilter.
在我的项目中,如果时间(或时区)发生变化,我需要重置一系列变量。为了了解这个事件发生的事实,我最终使用了 WindowsMessageFilter。
I'm using .Net 2.0 so I couldn't use (or maybe i'm looking in the wrong places for) the ClearCachedData so I used this approach with the help of a little reflection.
我正在使用 .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

