猿问

Java 8 DateTimeFormatter解析可选部分

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

  • 19861221235959Z

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

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

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

好像可选部分没有被评估为可选...


茅侃侃
浏览 309回答 3
3回答

慕姐4208626

问题在于您的模式正在将整个字符串视为年份。您可以将.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),并引发异常。

扬帆大鱼

基于模式的DateTimeFormatter不够智能,无法同时处理可选部分和具有两个不分隔的数字字段的可能性。当确实需要数字字段不带分隔符时,不问任何问题,则模式会理解,模式字母从u更改为M意味着它需要对数字进行计数才能知道哪个数字是哪个字段的一部分。但是,如果这不是确定性的,那么模式就不会尝试这种方式。它看到一个完整描述的数字字段,而不是紧随其后的是另一个数字字段。因此,没有理由计算数字。所有数字都是应该在此处表示的字段的一部分。为此,您不应该尝试使用模式来构建DateTimeFormatter,而应该使用Builder。从DateTimeFormatter.BASIC_ISO_DATE附近以及其他人那里获取灵感。
随时随地看视频慕课网APP

相关分类

Java
我要回答