如何用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 个可能的选项:
- 简单地从文本值中去除偏移部分并继续使用
LocalDatePattern.IsoPattern
。
- 将
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
函数来正确处理它。
我必须处理 XML 由各种外部系统发送的还包含一些日期的文档。 xs:date
允许向日期添加 "time zone",即偏移量。例如。 "2017-06-02+03:00"
是一个有效值。此外,偏移量在单个 XML 文档中的使用不一致。有些日期有偏移量,大多数没有。
LocalDatePattern.IsoPattern
不处理带有偏移量的值,我对自定义模式的尝试也没有结果。
将这些值解析为 LocalDate
的最佳方法是什么?
我讨论了 2 个可能的选项:
- 简单地从文本值中去除偏移部分并继续使用
LocalDatePattern.IsoPattern
。 - 将
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
函数来正确处理它。