根据我的理解,阅读this link at the nodatime google group,将一个ZonedDateTime转换为另一个时区(使用WithZone)是相当简单的(一旦我将用户的事件从LocalDateTime映射到ZonedDateTime,显然).我不需要担心抵消,比如Pheonix和芝加哥之间的夏令时差异将得到恰当的考虑.
我最初将服务器的时间(DateTime.Now)转换为ZonedDateTime并以此方式进行比较,但在阅读this link on SO之后,我切换到使用IClock.
到目前为止,在测试中一切正在发挥作用,但我担心我可能没有测试的极端情况.根据NodaTime的文档:
The biggest “gotcha” is converting
LocalDateTime
toZonedDateTime
– it has some corner cases you need to consider.
我已经仔细阅读了文档,并且我认为这个问题涉及一年中那些不会发生或发生两次的时间.这些时间永远不会被设置为我们用户的事件时间,但我确实使用了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,after.WallOffset); }
关于服务器的时区 – 您应该将其从代码中删除.您的代码不应该关心服务器的时区.相反,在ZonedDateTime(您的eventZonedDateTime变量)上调用ToInstant(),然后将其与从clock.Now返回的Instant进行比较.