使用可选的尾随截断零将字符串解析为 LocalDateTime

Parsing a String to LocalDateTime with optional trailing truncated zeros

从 API 传递的字符串通常遵循 yyyy-MM-dd HH:mm:ss.SSS 格式,但是当时间戳中有尾随 0 时,它们将被截断,例如 2019-07-16 13:29:15.100 被转换2019-07-16 13:29:15.12019-07-16 13:29:15.110 转换为 2019-07-16 13:29:15.11。我有一个可行的解决方案,它只是用零填充末尾,但这感觉就像是可以通过 DateTimeFormatter 字符串中的可选部分来解决的问题。我最接近的工作解决方案如下:

String toParse = "2019-07-16 13:29:15.111";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss[.[S[S[S]]]]");
LocalDateTime timestamp = LocalDateTime.parse(toParse, formatter);

这适用于尾随零被截断的所有情况,但不适用于显示的毫秒中所有数字均为非零的情况。错误信息是

java.time.format.DateTimeParseException: Text '2019-07-16 13:29:15.111' could not be parsed, unparsed text found at index 21

这只是支架放置的问题吗?我正在使用 Java 8,我们无法更改 API.

传递的内容

对于毫秒级的这些可选括号,我并不是很完美,但是你总是可以创建 DateTimeFormatter with optional milli seconds using DateTimeFormatterBuilder

DateTimeFormatter formatter1 = new DateTimeFormatterBuilder().appendPattern("yyyy-MM-dd HH:mm:ss")
                                    .optionalStart()
                                    .appendFraction(ChronoField.MILLI_OF_SECOND, 0, 3, true)
                                    .optionalEnd()
                                    .toFormatter();

使用内置部件

编写自己的格式模式字符串不仅有时很棘手,而且总是容易出错。我建议您 assemble 来自内置部件的格式化程序:

    String toParse = "2019-07-16 13:29:15.111";
    DateTimeFormatter formatter = new DateTimeFormatterBuilder()
            .append(DateTimeFormatter.ISO_LOCAL_DATE)
            .appendLiteral(' ')
            .append(DateTimeFormatter.ISO_LOCAL_TIME)
            .toFormatter();
    LocalDateTime timestamp = LocalDateTime.parse(toParse, formatter);

    System.out.println(timestamp);

输出:

2019-07-16T13:29:15.111

这适用于完全没有小数 (2019-07-16 13:29:15) 和从一位小数 (2019-07-16 13:29:15.1) 到九位小数 (2019-07-16 13:29:15.123456789) 的所有内容。它甚至可以在没有秒数的情况下工作 (2019-07-16 13:29)。

如果您想要 抛出 4 位或更多小数的异常,您需要使用 appendFraction(),如 D​​eadpool 的回答。

DateTimeFormatter.ISO_LOCAL_TIME的文档中:

The format consists of:

  • Two digits for the hour-of-day. This is pre-padded by zero to ensure two digits.
  • A colon
  • Two digits for the minute-of-hour. This is pre-padded by zero to ensure two digits.
  • If the second-of-minute is not available then the format is complete.
  • A colon
  • Two digits for the second-of-minute. This is pre-padded by zero to ensure two digits.
  • If the nano-of-second is zero or not available then the format is complete.
  • A decimal point
  • One to nine digits for the nano-of-second. As many digits will be output as required.

为什么方括号在这里不起作用

您不能将方括号放在一串重复的相同格式模式字母的中间。 [.[S[S[S]]]] 被理解为一个可选的点,可选地后跟一个秒的一位数小数,可选地后跟一个秒的一位数小数,可选地后跟一个秒的一位数小数。正如 Sweeper 在评论中指出的那样,当分数为 .111 时,它可能 运行 无一例外,但它可能会被理解为 .1 并且 1 被指定三次。如果三个数字不相等,则会中断。相反,您可能会使用 [.[SSS][SS][S]] 作为可选小数点后跟 3、2 或 1 位小数。您需要先输入 3 位小数。

Link