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