我收到以下格式的时间戳: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.375489991LocalTime的默认格式(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()解析这些内容,您需要一个毫秒级的TemporalUnitChronoUnit枚举提供的是毫微秒和毫微秒。 TemporalUnit是一个接口,因此理论上我们可以为此目的开发自己的毫微级毫微级。我曾经尝试开发一个实现TemporalUnit的类,但是放弃了,但我无法使其正常工作。

链接


Wikipedia article: ISO 8601
Regular expressions in Java - Tutorial

关于java - 无法解析localTime中的可选微秒,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/59656959/

10-12 03:05