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

StackOverflow https://stackoverflow.com/questions/296918

  •  08-07-2019
  •  | 
  •  

Вопрос

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

Это было полезно?

Решение

Да, текущий часовой пояс кэшируется. По уважительной причине он позволяет избежать проблем с неработающим кодом, который использует 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.

В моем проекте мне нужно было сбросить ряд переменных, если время (или часовой пояс) было изменено. Чтобы я мог узнать, произошло ли это событие, я использовал 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
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top