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

Java 使用可选的尾部截断零将字符串解析为LocalDateTime,java,string,parsing,datetime-format,Java,String,Parsing,Datetime Format,从API传递的字符串通常遵循格式yyyy-MM-dd HH:MM:ss.SSS,但当时间戳中有尾随的0时,它们会被截断,例如,2019-07-16 13:29:15.100转换为2019-07-16 13:29:15.1,2019-07-16 13:29:15.110转换为2019-07-16 13:29:15.11。我有一个有效的解决方案,它只是用零填充结尾,但这感觉像是可以通过DateTimeFormatter字符串中的可选部分来解决的问题。最接近工作解决方案的方法如下: String to

从API传递的字符串通常遵循格式
yyyy-MM-dd HH:MM:ss.SSS
,但当时间戳中有尾随的0时,它们会被截断,例如,
2019-07-16 13:29:15.100
转换为
2019-07-16 13:29:15.1
2019-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传递的内容。

这些可选括号中的毫秒并不完美,但您可以使用

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

    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位或更多小数的异常,则需要使用Deadpool答案中的
appendFraction()

它在
DateTimeFormatter.ISO\u LOCAL\u TIME
的文档中:

格式包括:

  • 两位数字表示一天中的小时。这是预先填充的零,以确保两位数字
  • 冒号
  • 两位数字表示小时分钟。这是预先填充的零,以确保两位数字
  • 如果第二分钟不可用,则格式已完成
  • 冒号
  • 两位数字表示一分钟的第二位。这是预先填充的零,以确保两位数字
  • 如果nano of second为零或不可用,则格式已完成
  • 小数点
  • 一到九个数字表示纳秒。将根据需要输出尽可能多的数字
为什么方括号在这里不起作用 <>你不能把方括号放在同一格式字母重复串的中间。代码>[[S[S]]]被理解为可选的点,可选地后跟一位数的秒分数,可选地后跟一位数的秒分数,可选地后跟一位数的秒分数。正如Sweeper在注释中所指出的,当分数为
.111
时,它可以毫无例外地运行,但它可能会被理解为
.1
,其中
1
被指定三次。如果三位数字不相等,则将断开。相反,您可能会使用
[[SSS][SS][S]]
作为可选小数点,后跟3、2或1个小数点。你需要把3个小数放在第一位

链接

我无法复制。我可以成功运行你的代码…@Sweeper代码没有给出完全正确的结果。预计:
2019-07-16T13:29:15.111
。在我的Java 11上观察到:
2019-07-16T13:29:15.100
。有关解释,请参见我的答案。@OleV.V。啊。。。我实际上没有检查解析的结果。我只是指出没有得到提到的例外。哇,我不知道方括号能打破重复模式!学到了一些新东西,这很有效!我试着用括号来装腔作势,但这似乎是一个更健壮的解决方案。
    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);