使用可选的尾随截断零将字符串解析为 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.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.
传递的内容
对于毫秒级的这些可选括号,我并不是很完美,但是你总是可以创建 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()
,如 Deadpool 的回答。
在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
从 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.
传递的内容对于毫秒级的这些可选括号,我并不是很完美,但是你总是可以创建 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()
,如 Deadpool 的回答。
在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 位小数。