Невозможно проанализировать дополнительные микросекунды в localTime - PullRequest
1 голос
/ 09 января 2020

Я получаю метку времени в формате: ЧЧммсс, затем миллисекунды и микросекунды. Микросекунды после «.» являются необязательными

Например: «метка времени»: «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, чтобы получить LocalTime в java.

Вот трассировка стека из исключения из кода выше:

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 Ответ

0 голосов
/ 10 января 2020

Существует множество опций, в зависимости от возможных вариаций строк, которые необходимо проанализировать.

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, et c., В строку замены. (?:…) обозначает группу без захвата, то есть не может использоваться в строке замены. Я поставил ? после него, чтобы указать, что эта группа является необязательной в исходной строке.

Это решение принимает от 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. Разбор только части строки

Нет такой большой и ужасной проблемы, от которой нельзя просто убежать (Линус в Арахис , из памяти)

Если вы можете жить без микросекунд, игнорируйте их:

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 один раз, но сдался, я не смог заставить его работать.

Ссылки

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...