Сравнение LocalDateTime для разных часовых поясов в Nodatime
Я работаю над приложением, которое позволяет пользователю планировать событие. Пользователь предоставляет часовой пояс Олсона с помощью средства выбора часового пояса, а также дату и время для указанного события с помощью средства выбора календаря asp и стороннего средства выбора времени ajax (поэтому DateTime
поставляется всегда будет в том же порядке). Я сравниваю время, которое хочет пользователь, и часовой пояс, который пользователь предоставляет, с временем нашего сервера и его часовым поясом, и запускаю событие в тот момент, когда пользователь ожидает его запуска.
Из того, что я понимаю, прочитав эту ссылку в группе Google nodatime, преобразовав один ZonedDateTime
в другой часовой пояс (используя WithZone
) довольно просто (как только у меня будет отображено событие пользователя из LocalDateTime
к ZonedDateTime
очевидно). Мне не нужно беспокоиться о смещениях, и разница в летнем времени между, скажем, Pheonix и Chicago будет должным образом учтена.
Я изначально конвертировал время сервера (DateTime.Now
) к ZonedDateTime
и сравнил таким образом, но после прочтения этой ссылки на SO я перешел на использование IClock
,
Пока что в тестировании все работает, но меня беспокоят угловые случаи, которые я не могу тестировать. Согласно документации для NodaTime:
Самая большая "гоча" - это конвертация
LocalDateTime
вZonedDateTime
- у него есть несколько угловых случаев, которые вы должны рассмотреть.
Я внимательно прочитал документацию и полагаю, что эта ошибка относится к тем временам года, которые либо не происходят, либо происходят дважды. Эти времена никогда не будут установлены как время событий для наших пользователей, но я использую LenientResolver
для них. Есть ли другие ошибки - когда я конвертирую из LocalDateTime
в ZonedDateTime
, я что- то упускаю или летнее время будет преследовать меня?
Кроме того, мне нужно конвертировать пользователя ZonedDateTime
перед сравнением с часовым поясом сервера (что я сейчас и делаю) или это ненужный (или даже ошибочный) шаг? Сможет ли NodaTime сравнивать должным образом (без проблем с переходом на летнее время), если бы я сравнивал необращенные события ZonedDateTime
(вместо события ZonedDateTime
после преобразования в часовой пояс сервера) на текущий сервер ZonedDateTime
(см. код ниже, с третьей до последней строки)? При просмотре кода я вижу время и смещения, но я боюсь, что это может быть упрощением, которое создает проблемы.
Protected Function EventIsReady(ByVal insTimeZone As String, ByVal eventDate As DateTime) As Boolean
Dim clock As IClock = SystemClock.Instance
Dim now As Instant = clock.Now
'server time zone (America/Chicago), unfortunately not UTC
Dim zone = DateTimeZoneProviders.Tzdb("America/Chicago")
Dim serverZonedDateTime = now.InZone(zone)
'user time zone
Dim userTimeZone As NodaTime.DateTimeZone = NodaTime.DateTimeZoneProviders.Tzdb.GetZoneOrNull(insTimeZone)
Dim userEventLocalDateTime = LocalDateTime.FromDateTime(eventDate)
Dim eventZonedDateTime = userTimeZone.ResolveLocal(userEventLocalDateTime, Resolvers.LenientResolver)
Dim eventTimeInServerTimeZone = eventZonedDateTime.WithZone(zone)
Dim isReady As Boolean = False
If eventTimeInServerTimeZone >= serverZonedDateTime Then
isReady = True
End If
Return isReady
End Function
1 ответ
Похоже, вы на правильном пути.
относительно LenientResolver
Убедитесь, что вы знаете о его поведении. Оно использует ReturnStartOfIntervalAfter
для пружинного зазора, и ReturnLater
для резервного дублирования.
ИМХО, это не лучшая конфигурация для планирования будущих событий. (См. Выпуск № 295) и попробуйте вместо этого:
VB.NET
Public Shared ReadOnly SchedulingResolver As ZoneLocalMappingResolver = _
Resolvers.CreateMappingResolver(Resolvers.ReturnEarlier, _
AddressOf ReturnForwardShifted)
Public Shared Function ReturnForwardShifted(local As LocalDateTime, _
zone As DateTimeZone, before As ZoneInterval, after As ZoneInterval) _
As ZonedDateTime
Dim newLocal As LocalDateTime = local.PlusTicks(after.Savings.Ticks)
Return New ZonedDateTime(newLocal, zone, after.WallOffset)
End Function
C#
public static readonly ZoneLocalMappingResolver SchedulingResolver =
Resolvers.CreateMappingResolver(Resolvers.ReturnEarlier, ReturnForwardShifted);
public static ZonedDateTime ReturnForwardShifted(LocalDateTime local,
DateTimeZone zone, ZoneInterval before, ZoneInterval after)
{
LocalDateTime newLocal = local.PlusTicks(after.Savings.Ticks);
return new ZonedDateTime(newLocal, zone, after.WallOffset);
}
Что касается часового пояса сервера - вы должны исключить это из своего кода. Ваш код не должен заботиться о часовом поясе сервера. Вместо этого позвоните ToInstant()
на ZonedDateTime
(ваш eventZonedDateTime
переменной), затем сравните это с Instant
вернулся из clock.Now
,