【问题标题】:Unable to parse optional microseconds in localTime无法解析本地时间中的可选微秒
【发布时间】:2020-01-09 03:46:05
【问题描述】:

我收到的时间戳格式为:HHmmss 后跟毫秒和微秒。'.' 之后的微秒是可选的

例如:“时间戳”:“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

【问题讨论】:

  • 请分享您到达那里的异常的堆栈跟踪,因为代码对我来说看起来是正确的。还共享初始化日期时间的确切字符串值。
  • 如果有的话,点后是否总是正好有 6 位数字?还是位数会有所不同?

标签: java datetime


【解决方案1】:

有很多选项,具体取决于您需要解析的字符串的可能变化。

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);

这个sn-p的输出是:

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 in Peanuts,凭记忆)

如果您可以不用微秒,请忽略它们:

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 是一个接口,所以理论上我们可以为此开发自己的 nano of milli 类。我曾经尝试开发一个实现TemporalUnit 的类,但放弃了,我无法让它工作。

链接

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-08-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多