我收到以下格式的时间戳:HHmmss,后跟毫秒和微秒。“。”后的微秒是可选的
例如:“ timestamp”:“ 152656375.489991”为15:26:56:375.489991。
下面的代码引发异常:
final DateTimeFormatter FORMATTER = new DateTimeFormatterBuilder()
.appendPattern("HHmmssSSS")
.appendFraction(ChronoField.MICRO_OF_SECOND, 0, 6, true)
.toFormatter();
LocalTime.parse(dateTime,FORMATTER);
有人可以用DateTimeformatter帮助我在Java中获取LocalTime吗?
这是上面代码中的异常的堆栈跟踪:
java.time.format.DateTimeParseException: Text '152656375.489991' could not be parsed: Conflict found: NanoOfSecond 375000000 differs from NanoOfSecond 489991000 while resolving MicroOfSecond
at java.base/java.time.format.DateTimeFormatter.createError(DateTimeFormatter.java:1959)
at java.base/java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1894)
at java.base/java.time.LocalTime.parse(LocalTime.java:463)
at com.ajax.so.Test.main(Test.java:31)
Caused by: java.time.DateTimeException: Conflict found: NanoOfSecond 375000000 differs from NanoOfSecond 489991000 while resolving MicroOfSecond
at java.base/java.time.format.Parsed.updateCheckConflict(Parsed.java:329)
at java.base/java.time.format.Parsed.resolveTimeFields(Parsed.java:462)
at java.base/java.time.format.Parsed.resolveFields(Parsed.java:267)
at java.base/java.time.format.Parsed.resolve(Parsed.java:253)
at java.base/java.time.format.DateTimeParseContext.toResolved(DateTimeParseContext.java:331)
at java.base/java.time.format.DateTimeFormatter.parseResolved0(DateTimeFormatter.java:1994)
at java.base/java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1890)
... 3 more
最佳答案
有很多选项,取决于您需要解析的字符串的可能变化。
1.修改字符串,因此不需要格式化程序
String timestampString = "152656375.489991";
timestampString = timestampString.replaceFirst(
"^(\\d{2})(\\d{2})(\\d{2})(\\d{3})(?:\\.(\\d*))?$", "$1:$2:$3.$4$5");
System.out.println(timestampString);
LocalTime time = LocalTime.parse(timestampString);
System.out.println(time);
该代码段的输出为:
15:26:56.375489991
replaceFirst()
调用将您的字符串修改为15:26:56.375489991
(LocalTime
的默认格式(ISO 8601)),因此无需任何显式格式化程序就可以对其进行解析。为此,我使用了可能不太可读的正则表达式。 (…)
在替换字符串中包含我用作$1
,$2
等的组。 (?:…)
表示非捕获组,即不能在替换字符串中使用。我在其后放置?
,以指定该组在原始字符串中是可选的。该解决方案接受点后的1到6位小数,也完全没有小数部分。
2.使用更简单的字符串修改和格式化程序
我想修改字符串,以便可以使用此格式化程序:
private static DateTimeFormatter fullParser
= DateTimeFormatter.ofPattern("HHmmss.[SSSSSSSSS][SSS]");
这就要求该点必须在秒之后,而不是毫秒之后。因此,将其向左移动三个位置:
timestampString = timestampString.replaceFirst("(\\d{3})(?:\\.|$)", ".$1");
LocalTime time = LocalTime.parse(timestampString, fullParser);
15:26:56.375489991
再次,我使用的是非捕获组,这一次是要说(捕获的)三位数字组之后必须是点或字符串的末尾。
3.与更灵活的解析器相同
上面的格式化程序指定小数点后必须有9或3位数字,这可能太严格了。如果您也想接受介于两者之间的内容,那么构建器可以构建更灵活的格式化程序:
private static DateTimeFormatter fullParser = new DateTimeFormatterBuilder()
.appendPattern("HHmmss")
.appendFraction(ChronoField.NANO_OF_SECOND, 3, 9, true)
.toFormatter();
我认为这将是我最喜欢的方法,再次取决于确切的要求。
4.仅解析字符串的一部分
没有那么大而可怕的问题,它不能简单地逃跑
来自(花生中的Linus,来自记忆)
如果没有微秒,您可以忽略它们:
private static DateTimeFormatter partialParser
= DateTimeFormatter.ofPattern("HHmmssSSS");
要使用此格式化程序仅解析字符串的一部分,直到该点:
TemporalAccessor parsed
= partialParser.parse(timestampString, new ParsePosition(0));
LocalTime time = LocalTime.from(parsed);
15:26:56.375
如您所见,它忽略了小数点后的部分,我觉得不太满意。
您的代码出了什么问题?
小数点后的6位数字表示纳秒。微秒只能是毫秒后的3位小数。要使用
appendFraction()
解析这些内容,您需要一个毫秒级的TemporalUnit
。 ChronoUnit
枚举提供的是毫微秒和毫微秒。 TemporalUnit
是一个接口,因此理论上我们可以为此目的开发自己的毫微级毫微级。我曾经尝试开发一个实现TemporalUnit
的类,但是放弃了,但我无法使其正常工作。链接
Wikipedia article: ISO 8601
Regular expressions in Java - Tutorial
关于java - 无法解析localTime中的可选微秒,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/59656959/