.NET DateTime.Now returns incorrect time when time zone is changed

时光毁灭记忆、已成空白 提交于 2019-11-27 00:37:45
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.

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.

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.

.NET provides for calculations involving daylight savings time with the DaylightTime and TimeZone classes, and the ToLocalTime method supposedly can convert UTC to local accounting for daylight savings time.

MacGyver

The fully qualified class above was slightly off, but perhaps it changed in .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

Call it just before using DateTime.Now. Although it's probably best to call it in the startup event of your Global.asax file.

========== 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.

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.

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.

    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
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!