繁体   English   中英

Java 8 DateTimeFormatter解析可选部分

[英]Java 8 DateTimeFormatter parsing optional sections

我需要将日期时间解析为两种不同格式的字符串:

  • 19861221235959Z
  • 1986-12-21T23:59:59Z

以下dateTimematmat模式正确解析第一种日期字符串

DateTimeFormatter.ofPattern ("uuuuMMddHHmmss[,S][.S]X")

但是第二个失败,因为没有预期破折号,冒号和T.

我的尝试是使用如下可选部分:

DateTimeFormatter.ofPattern ("uuuu[-]MM[-]dd['T']HH[:]mm[:]ss[,S][.S]X")

出乎意料的是,这解析了第二种日期字符串(带有破折号的日期字符串),但不是第一种,抛出一个

java.time.format.DateTimeParseException: Text '19861221235959Z' could not be parsed at index 0

就像可选部分没有被评估为可选部分一样......

正如彼得在评论中所说,问题在于你的模式正在考虑整个字符串作为年份。 您可以使用.appendValue(ChronoField.YEAR, 4)将其限制为四个字符:

DateTimeFormatter formatter = new DateTimeFormatterBuilder()
    .appendValue(ChronoField.YEAR, 4)
    .appendPattern("[-]MM[-]dd['T']HH[:]mm[:]ss[,S][.S]X")
    .toFormatter();

这可以用你的两个例子正确解析。

如果你想要更加冗长,你可以这样做:

DateTimeFormatter formatter = new DateTimeFormatterBuilder()
    .appendValue(ChronoField.YEAR, 4)
    .optionalStart().appendLiteral('-').optionalEnd()
    .appendPattern("MM")
    .optionalStart().appendLiteral('-').optionalEnd()
    .appendPattern("dd")
    .optionalStart().appendLiteral('T').optionalEnd()
    .appendPattern("HH")
    .optionalStart().appendLiteral(':').optionalEnd()
    .appendPattern("mm")
    .optionalStart().appendLiteral(':').optionalEnd()
    .appendPattern("ss")
    .optionalStart().appendPattern("X").optionalEnd()
    .toFormatter();

从文档中不清楚,但我的猜测是以下是发生的事情。

在格式模式字符串中使用uuuuMMddHHmmss时,格式化程序可以很容易地看到有几个相邻的数字字段,因此使用字段宽度来分隔字段。 前4位数字表示年份,依此类推。

相反,当您使用uuuu[-]MM[-]dd['T']HH[:]mm[:]ss ,格式化程序不会将其视为相邻的数字字段。 我同意Peter Lawrey的评论,因此它需要更长时间的数字运行,最后溢出最大年份(999999999)并抛出异常。

解决方案? 请参考Michael的回答

基于模式的DateTimeFormatter不够智能,无法处理可选节和可能有两个数字字段而不分离。 当你确实需要你的数字字段没有分隔符时,没有问题,那么模式理解模式字母从u到M的变化意味着它需要计算数字以知道哪个数字是哪个字段的一部分。 但是当这不确定时,那么模式就不会尝试。 它会看到一个完整描述的数字字段,而不会立即跟随另一个数字字段。 因此,没有理由计算数字。 所有数字都是应该在此处表示的字段的一部分。

要做到这一点,你不应该尝试使用模式构建DateTimeFormatter,而是使用Builder。 DateTimeFormatter.BASIC_ISO_DATE和附近的其他人那里获取灵感。

乍一看,您的第二种格式应适用于这两种情况。 不知道为什么不这样做。 顺便说一句,我很好奇你为什么用'u'而不是'y'一年。 所以我也会尝试使用'y'来看看它是否有所作为。 但总的来说,你正在触及一个有趣的观点 - 如何解析未知格式的日期(想象一下,你处理未知数量的格式而不是2种可能的格式)。 我实际上曾经写过一次这样的解析器。 我用来解决这个问题的想法在我的文章Java 8 java.time包中有所描述:解析迄今为止的任何字符串 您可能会发现这个想法很有用。 简而言之,我们的想法是拥有包含所有支持格式的外部文件,并尝试逐个应用每种格式,直到一个工作。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM