我正在开发一个允许用户安排事件的应用程序。用户使用Time Zone Picker来提供Olson时区,并通过asp日历选择器和第三方ajax时间选择器来提供该事件的日期和时间(因此提供的DateTime
始终处于相同的模式)。我将用户所需的时间和用户提供的时区与我们服务器的时间及其时区进行比较,并在用户希望将其触发时立即触发事件。
据我了解,阅读this link at the nodatime google group后,将一个ZonedDateTime
转换为另一个时区(使用WithZone
)是非常简单的(显然,一旦将用户事件从LocalDateTime
映射到ZonedDateTime
,就很容易了)。我无需担心偏移量,并且可以适当考虑菲尼克斯和芝加哥之间的夏令时差异。
我最初将服务器的时间(DateTime.Now
)转换为ZonedDateTime
,并以此方式进行比较,但是在阅读this link on SO之后,我切换为使用IClock
。
到目前为止,在测试中一切正常,但是我担心我可能没有进行测试的极端情况。根据NodaTime的文档:
最大的“陷阱”是将LocalDateTime
转换为ZonedDateTime
-您需要考虑一些极端情况。
我已经仔细阅读了文档,并假定此错误是针对一年中没有发生或发生过两次的时间。这些时间永远不会设置为我们用户的事件时间,但是我确实将LenientResolver
用于他们。还有其他陷阱吗?-当我从LocalDateTime
转换为ZonedDateTime
时,我会丢失任何东西吗?还是夏时制会困扰我?
另外,我是否需要在比较之前将用户的ZonedDateTime
转换为服务器时区(我现在正在这样做),或者这是否是不必要的(甚至是错误的)步骤?如果我将事件的未转换ZonedDateTime
(而不是转换为服务器时区后的事件ZonedDateTime
)与当前服务器ZonedDateTime
进行比较,NodaTime是否能够正确比较(没有夏令时问题)?下面,倒数第三行)?单步执行代码时,我可以看到时间和偏移量,但是我担心这样做可能会过分简化,从而带来问题。
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
最佳答案
听起来您在正确的轨道上。
关于LenientResolver
,请确保您了解其行为。它使用ReturnStartOfIntervalAfter
表示前移间隙,使用ReturnLater
表示后退重叠。
恕我直言,这不是安排未来事件的最佳配置。 (请参见Issue #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
进行比较。关于.net - 比较Nodatime中不同时区的LocalDateTime,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/25123884/