如何用NodaTime解析xs:date?

How to parse xs:date with NodaTime?

我必须处理 XML 由各种外部系统发送的还包含一些日期的文档。 xs:date 允许向日期添加 "time zone",即偏移量。例如。 "2017-06-02+03:00" 是一个有效值。此外,偏移量在单个 XML 文档中的使用不一致。有些日期有偏移量,大多数没有。

LocalDatePattern.IsoPattern 不处理带有偏移量的值,我对自定义模式的尝试也没有结果。

将这些值解析为 LocalDate 的最佳方法是什么?

我讨论了 2 个可能的选项:

  1. 简单地从文本值中去除偏移部分并继续使用LocalDatePattern.IsoPattern
  2. OffsetDateTimePattern 与不包含时间部分的自定义模式一起使用,然后根据解析值手动构建 LocalDate

我最终选择了选项 1,因为我不需要任何转换的偏移量。

我会将值解析为 OffsetDateTimePattern,因为它最能代表您在文本中实际拥有的信息。我的经验是,最好以保留您需要的所有信息的形式进行解析,然后使用 Noda Time API 更改为您实际想要的格式...而不是这样做对字符串进行转换然后解析。

这样做的好处:

  • 它会验证所有文本,而不仅仅是您感兴趣的文本。值“2017-06-09-badger-badger”清楚地表明存在严重错误,但如果您使用的是子字符串方法你会错过的。
  • 它更健壮——你不太可能在代码中得到幻数,而且处理可变宽度格式之类的东西要容易得多(当然,在这种特定情况下不是问题)
  • 这让您更容易改变主意,因为决定权完全在 "date and time" 域,而不是 "text parsing" 域。

我通常对此做出的唯一例外是字符串目前无法解析 - 例如它包括一些不受支持的方面,如序数 ("June 3rd 2017")。

我们可以考虑将其添加为 LocalDate 的文本格式 - 我预计不会创建 OffsetDate 类型,除非有大量需求。

像这样的东西应该适合您的用例:

public static bool TryParseXsDate(string xsDate, out LocalDate localDate)
{
    // First try directly, since xsDate's offset is optional.
    var result1 = LocalDatePattern.Iso.Parse(xsDate);
    if (result1.Success)
    {
        localDate = result1.Value;
        return true;
    }

    // Now try with an offset
    var result2 = OffsetDatePattern.Parse(xsDate);
    if (result2.Success)
    {
        localDate = result2.Value.Date;
        return true;
    }

    // Failed parsing
    localDate = default(LocalDate);
    return false;
}

这将在所有情况下忽略偏移量。

如果您确实需要 偏移量,请记住xs:Date 将其定义为日期第一时刻的偏移量。因此,一旦应用到时区,午夜 可能会 在那天出现两次,或者这一天可能从 1:00 AM 开始。您需要一个自定义 ZoneLocalMappingResolver 函数来正确处理它。