我正在开发一个允许用户安排事件的应用程序。用户使用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/

10-12 21:34