Существует множество опций, в зависимости от возможных вариаций строк, которые необходимо проанализировать.
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
один раз, но сдался, я не смог заставить его работать.
Ссылки