Подтвердить что ты не робот

.NET DateTime.Now возвращает неправильное время, когда изменяется часовой пояс

Эта проблема возникла при изменении времени перехода на летнее время. После произошедшего изменения мы заметили, что наше серверное приложение начало записывать в журнал неправильное время - на один час вперед, что означает, что .NET кэширует временное смещение. Для решения этой проблемы нам пришлось перезапустить наше приложение. Я написал простое приложение для воспроизведения этой проблемы. Когда я изменяю часовой пояс во время работы приложения, свойство DateTime.Now сохраняет время в старом часовом поясе. Кто-нибудь знает, есть ли обходной путь для этой проблемы, помимо перезапуска приложения?

4b9b3361

Ответ 1

Да, текущий часовой пояс кэшируется. По уважительной причине, это позволяет избежать проблем с сломанным кодом, который использует DateTime.Now для реализации прошедшего времени измерения. Такой код имеет тенденцию страдать от сердечного приступа, когда время внезапно изменяется на час или более.

Вам нужно будет вызвать значение System.Globalization.CultureInfo.ClearCachedData() в reset кэшированное значение. Следующий вызов DateTime.Now теперь даст новое местное время. Если вы вообще используете класс .NET 3.5 TimeZoneInfo, вам также необходимо вызвать его метод ClearCachedData(). Вы можете использовать событие SystemEvents.TimeChanged как триггер.

Ответ 2

Наиболее распространенной рекомендацией является сохранение DateTime.UtcNow и, когда вы хотите показать локализованное время для пользователя, конвертируйте в локальное время учет летнего времени.

.NET обеспечивает вычисления с использованием летнего времени с DaylightTime и TimeZone, а метод ToLocalTime якобы может преобразовывать UTC в локальный учет для летнего времени.

Ответ 3

Полноценный класс выше был слегка выключен, но, возможно, он изменился в .NET 3.5.

System.Globalization.CultureInfo.CurrentCulture.ClearCachedData()

также не забудьте включить (в С#.NET) или импортировать (с VB.NET) ссылку на библиотеку System.Globalization.CultureInfo

Вызовите его непосредственно перед использованием DateTime.Now. Хотя, вероятно, лучше всего назвать это в событии запуска вашего файла Global.asax.

========== Также убедитесь, что вы проверяете часовой пояс на самом сервере Windows или на своем локальном компьютере в зависимости от того, где работает веб-сервер IIS.

Ответ 4

В моем проекте мне понадобилось Reset серию переменных, если было изменено Time (или Timezone). Чтобы я мог узнать, произошло ли это событие, я закончил использование 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