问题描述
我工作的一个应用程序,允许用户安排一个事件。用户提供使用时区选择器的Olson时区,以及日期和时间表示,通过ASP日历选择器和第三方AJAX时间选择器事件(故的DateTime
供应将始终以相同的模式)。我比较用户希望的时间和时区的用户提供我们的服务器的时间和时区,并触发事件的用户期望它被解雇的时刻。
据我所知,有阅读此链接在nodatime谷歌组,(使用 WithZone
)将一个 ZonedDateTime
至另一时区是相当简单的(一旦我有从 LocalDateTime
用户的事件映射到一个 ZonedDateTime
,很明显)。我并不需要担心偏移和之间,也就是说,凤凰和芝加哥会得到妥善占夏令时间差。
我原本转换服务器的时间(<$ C C $> DateTime.Now )到 ZonedDateTime
相比这种方式,但看完后,this在SO链接我转向使用 IClock
。
到目前为止,测试一切正常,但我很担心其他的情况,我可能不会检测为。根据对NodaTime文档:
我已经通过文件读取彻底我认为这个疑难杂症是在参考了当年的那些时间,要么不发生或出现两次。这些时间将永远不会被设置为活动时间为我们的用户,但我确实使用了 LenientResolver
他们。是否有任何其他陷阱 - 当我从 LocalDateTime
转换为 ZonedDateTime
,我失去了什么或将夏令时结束纠缠着我?
此外,我需要用户的 ZonedDateTime
到服务器时时间段之前比较转换(我现在所做的),或者是这样的不必要的(甚至是错误的)一步?将NodaTime能够恰当地比较(不夏令问题)如果我是比较活动的,而不是未转化 ZonedDateTime
(事件的 ZonedDateTime
转换到服务器时区后),以当前的服务器 ZonedDateTime
(见下面code,第三至最后一行)?当通过code踩着我可以看到的时间和偏移,但我很担心,这样做可能是引入的问题过于简单化了。
受保护的功能EventIsReady(BYVAL insTimeZone作为字符串,BYVAL EVENTDATE为DATETIME)作为布尔
昏暗的时钟作为IClock = SystemClock.Instance
现在灰暗即时= clock.Now
服务器时区(美国/芝加哥),不幸的是没有UTC
昏暗区= DateTimeZoneProviders.Tzdb(美国/芝加哥)
昏暗的serverZonedDateTime = now.InZone(区)
用户时区
昏暗userTimeZone作为NodaTime.DateTimeZone = NodaTime.DateTimeZoneProviders.Tzdb.GetZoneOrNull(insTimeZone)
昏暗userEventLocalDateTime = LocalDateTime.FromDateTime(EVENTDATE)
昏暗eventZonedDateTime = userTimeZone.ResolveLocal(userEventLocalDateTime,Resolvers.LenientResolver)
昏暗eventTimeInServerTimeZone = eventZonedDateTime.WithZone(区)
昏暗isReady由于布尔= FALSE
如果eventTimeInServerTimeZone&GT; = serverZonedDateTime然后
isReady = TRUE
结束如果
返回isReady
端功能
这听起来像你在正确的轨道上。
关于 LenientResolver
,一定要意识到自己的行为。它使用 ReturnStartOfIntervalAfter
的春天正向差距, ReturnLater
秋季回重叠。
IMHO,这不是对于未来事件的调度的最佳配置。 (见问题#295 ),和试试这个:
VB.NET
公共共享只读SchedulingResolver作为ZoneLocalMappingResolver = _ Resolvers.CreateMappingResolver(Resolvers.ReturnEarlier,_ AddressOf ReturnForwardShifted)公共共享功能ReturnForwardShifted(local作为LocalDateTime,_ 区作为DateTimeZone,作为ZoneInterval之前,作为ZoneInterval后)_ 作为ZonedDateTime 昏暗newLocal作为LocalDateTime = local.PlusTicks(after.Savings.Ticks) 返回新ZonedDateTime(newLocal,区,after.WallOffset)端功能
C#
公共静态只读ZoneLocalMappingResolver SchedulingResolver = Resolvers.CreateMappingResolver(Resolvers.ReturnEarlier,ReturnForwardShifted);公共静态ZonedDateTime ReturnForwardShifted(LocalDateTime地方, DateTimeZone区,ZoneInterval之前,ZoneInterval后){ LocalDateTime newLocal = local.PlusTicks(after.Savings.Ticks); 返回新ZonedDateTime(newLocal,区,after.WallOffset);}
对于服务器的时区 - 你应该离开那个从你的code。您的code的不应该关心的是服务器的时区。相反,叫 ToInstant()
在 ZonedDateTime
(你的 eventZonedDateTime
变量),然后比较,与即时
从返回 clock.Now
。
I am working on an application that allows a user to schedule an event. The user supplies an Olson time zone by using a Time Zone Picker, and a date and time for said event through an asp calendar picker and third-party ajax time picker (so the DateTime
supplied will always be in the same pattern). I compare the time the user wants and the time zone the user supplies with our server's time and its time zone, and fire the event the instant the user expects it to be fired.
From what I understand, having read this link at the nodatime google group, converting one ZonedDateTime
to another time zone (using WithZone
) is fairly straightforward (once I have the user's event mapped from LocalDateTime
to a ZonedDateTime
, obviously). I don't need to worry about offsets, and daylight savings time differences between, say, Pheonix and Chicago will be properly accounted for.
I had originally converted the server's time (DateTime.Now
) to a ZonedDateTime
and compared this way, but after reading this link on SO I switched to using IClock
.
So far in testing everything is working out, but I am worried about corner cases that I might not be testing for. According to the documentation for NodaTime:
I have read through the documentation thoroughly and I assume that this gotcha is in reference to those times of the year that either do not occur or that occur twice. These times will never be set as event times for our users but I do use the LenientResolver
for them. Are there any other gotchas - when I convert from LocalDateTime
to ZonedDateTime
, am I missing anything or will daylight savings time end up haunting me?
Also, do I need to convert the user's ZonedDateTime
to the server time zone before comparison (which I am doing now) or is this an unnecessary (or even erroneous) step? Will NodaTime be able to compare properly (without daylight savings problems) if I were to compare the event's unconverted ZonedDateTime
(instead of the event's ZonedDateTime
after conversion to the server time zone) to the current server ZonedDateTime
(see code below, third to last line)? When stepping through the code I can see the times and offsets, but I'm worried that doing this might be an oversimplification that introduces problems.
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
It sounds like you're on the right track.
Regarding LenientResolver
, make sure you are aware of its behavior. It uses ReturnStartOfIntervalAfter
for the spring-forward gap, and ReturnLater
for the fall-back overlap.
IMHO, that isn't the best configuration for scheduling of future events. (See Issue #295), and try this instead:
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);
}
Regarding the server's time zone - you should leave that out of your code. Your code should not care what the time zone of the server is. Instead, call ToInstant()
on the ZonedDateTime
(your eventZonedDateTime
variable), then compare that with the Instant
returned from clock.Now
.
这篇关于比较LocalDateTime不同时区的Nodatime的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!