.NET DateTime.Now возвращает неверное время при изменении часового пояса
эта проблема возникла во время изменения летнего времени. После изменения мы заметили, что наше серверное приложение начало записывать в журнал неправильное время-на час вперед, что означает, что .NET кэширует смещение часового пояса. Нам пришлось перезапустить приложение, чтобы решить эту проблему. Я написал простое приложение, чтобы воспроизвести эту проблему. Когда я изменяю часовой пояс во время работы приложения, DateTime.Теперь свойство продолжает производить время в старом часовом поясе. Делает кто-нибудь знает, есть ли обходной путь для этой проблемы, кроме перезапуска приложения?
4 ответов
да, текущий часовой пояс кэшируется. По веской причине это позволяет избежать проблем с разбитым кодом, который использует DateTime.Теперь для реализации измерения прошедшего времени. Такой код имеет тенденцию страдать сердечным приступом, когда время внезапно меняется на час или более.
вам придется вызвать систему.Глобализация.Свойство CultureInfo.ClearCachedData () для сброса кэшированного значения. Следующий вызов DateTime.Теперь теперь дадим новое местное время. Если вы вообще используете класс .NET 3.5 TimeZoneInfo вам также нужно будет вызвать его метод ClearCachedData (). Вы можете использовать SystemEvents.Событие TimeChanged в качестве триггера.
наиболее распространенная рекомендация-хранить DateTime.UtcNow и, если вы хотите показать пользователю локализованное время, конвертируйте в местное время учет летнего времени.
.NET обеспечивает расчеты с использованием летнего времени с DaylightTime и часовой пояс классов, и ToLocalTime метод предположительно может конвертировать UTC в локальный учет для летнего времени.
полный класс выше был немного выключен, но, возможно, он изменился в .NET 3.5.
System.Globalization.CultureInfo.CurrentCulture.ClearCachedData()
также не забудьте включить (в C#.NET) или импорт (с VB.NET) справочник по библиотеке System.Globalization.CultureInfo
вызовите его непосредственно перед использованием DateTime.Now
. Хотя, вероятно, лучше всего назвать это в событии запуска вашего Global.файл asax.
========== Также убедитесь, что вы проверить часовой пояс на Windows сервере или локальном компьютере, в зависимости от того, где веб-сервер 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