使用Noda Time解析不明确的日期时间

6

我使用Noda Time,并且有以下代码:

var pattern = ZonedDateTimePattern.CreateWithInvariantCulture(
    "yyyy-MM-dd HH:mm:ss z", 
    DateTimeZoneProviders.Tzdb);

var parsed = pattern.Parse("2017-11-05 01:00:00 America/Los_Angeles");
Console.WriteLine(parsed.Value);

这将导致一个UnparsableValueException,并显示以下信息:

目标时区存在歧义的本地日期/时间

问题在于,由于夏令时的影响,特定的时间可能会出现两次。在02:00时,时钟被调回一小时到01:00。NodaTime不知道字符串所指的01:00的哪个版本,因此抛出异常。
对我来说,解析结果中的时间版本并不重要,我只是想避免异常,并获得尽可能接近实际的日期。多一小时或少一小时都可以。有什么更好的方法吗?
我唯一能想到的方法是拆分字符串并逐个解析部分,然后再添加一小时,但这感觉完全不对。是否有更好的解决方案?
2个回答

7
ZonedDateTimePattern 类有一个 Resolver 属性。解析器的作用是执行到带时区的日期/时间的映射,并处理被跳过和模糊的时间 - 由于 DST,这些时间无法映射为它们将会发生 never (被跳过) 或 more than once (模糊)。 ZonedDateTimePattern 源代码 显示默认解析器是 Resolvers.StrictResolver。正如您已经发现的那样,如果映射是模糊或被跳过,此解析器将抛出异常。
有多种解析器可用。最适合你的“请给我一个有效的日期和时间!”需求的可能是{{link2: LenientResolver }},其行为如下:

通过返回较早的事件来处理歧义,并且跳过的时间将向前移动间隔的持续时间。

我们可以通过在ZonedDateTimePattern实例上附加对WithResolver()的调用来指定此解析器(Resolver属性没有公共setter):
var pattern = ZonedDateTimePattern.CreateWithInvariantCulture(
    "yyyy-MM-dd HH:mm:ss z",
    DateTimeZoneProviders.Tzdb).WithResolver(Resolvers.LenientResolver);

var parsed = pattern.Parse("2017-11-05 01:00:00 America/Los_Angeles");
Console.WriteLine(parsed.Value);

输出:

2017-11-05T01:00:00 美国/洛杉矶时区 (-07)


1
哇,这真的很简单!感谢您还详细解释了一下 :) - TheQ

3
根据https://github.com/nodatime/nodatime/blob/2.2.x/src/NodaTime.Web/Markdown/2.0.x/zoneddatetime-patterns.md(或生成到其他位置的文件),如果模式不包含偏移规范符(“o<...>”),则文本表示的本地日期和时间将根据与该模式相关联的ZoneLocalMappingResolver进行解释。可以使用WithResolver方法从现有模式创建一个新模式,只是具有不同的解析器。如果解析器抛出SkippedTimeException或AmbiguousTimeException,则这些将转换为UnparsableValueException结果。请注意,没有偏移规范符的模式始终会导致潜在的数据丢失,当使用不是单个固定偏移的时区时,由于通常会出现夏令时的常规问题。建议使用。
var lenientpattern = ZonedDateTimePattern
                    .CreateWithInvariantCulture("yyyy-MM-dd HH:mm:ss z", DateTimeZoneProviders.Tzdb)
                    .WithResolver(Resolvers.LenientResolver); //or any of the other resolvers
var parsed = lenientpattern.Parse("2017-11-05 01:00:00 America/Los_Angeles");
Console.WriteLine(parsed.Value);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接