Разбор строки в LocalDateTime с необязательными конечными усеченными нулями - PullRequest
2 голосов
/ 14 апреля 2020

Строка, которая передается из API, обычно соответствует формату yyyy-MM-dd HH:mm:ss.SSS, но когда в метке времени есть конечные 0, они обрезаются, например, 2019-07-16 13:29:15.100 преобразуется в 2019-07-16 13:29:15.1, а 2019-07-16 13:29:15.110 преобразуется до 2019-07-16 13:29:15.11. У меня есть рабочее решение, которое просто дополняет конец нулями, но это похоже на проблему, которую можно решить с помощью необязательных разделов в строке DateTimeFormatter. Самое близкое мне к рабочему решению следующее:

String toParse = "2019-07-16 13:29:15.111";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss[.[S[S[S]]]]");
LocalDateTime timestamp = LocalDateTime.parse(toParse, formatter);

, которое работает для всех случаев с усеченными конечными нулями, но не для случая, когда все цифры в миллисекундах отличны от нуля. Сообщение об ошибке:

java.time.format.DateTimeParseException: Text '2019-07-16 13:29:15.111' could not be parsed, unparsed text found at index 21

Это просто проблема с размещением скобок? Я использую Java 8, и мы не можем изменить то, что передается API.

Ответы [ 2 ]

1 голос
/ 16 апреля 2020

Использование встроенных деталей

Написание собственной строки шаблона формата не только иногда сложно, но и всегда подвержено ошибкам. Я рекомендую вместо этого собрать ваш форматтер из встроенных частей:

    String toParse = "2019-07-16 13:29:15.111";
    DateTimeFormatter formatter = new DateTimeFormatterBuilder()
            .append(DateTimeFormatter.ISO_LOCAL_DATE)
            .appendLiteral(' ')
            .append(DateTimeFormatter.ISO_LOCAL_TIME)
            .toFormatter();
    LocalDateTime timestamp = LocalDateTime.parse(toParse, formatter);

    System.out.println(timestamp);

Вывод:

2019-07-16T13: 29: 15.111

Это работает без десятичных знаков вообще (2019-07-16 13:29:15) и всего от одного десятичного знака (2019-07-16 13:29:15.1) до девяти десятичных знаков (2019-07-16 13:29:15.123456789). Он работает даже без секунд (2019-07-16 13:29).

Если вы хотите, чтобы сгенерировал исключение для 4 или более десятичных знаков, вам нужно использовать appendFraction(), как в ответе Deadpool.

Он находится в документации DateTimeFormatter.ISO_LOCAL_TIME:

Формат состоит из:

  • Две цифры для часа дня. Он дополняется нулями, чтобы обеспечить две цифры.
  • Двоеточие
  • Две цифры для минуты часа. Он дополняется нулями, чтобы обеспечить две цифры.
  • Если секунда минуты недоступна, то формат завершен.
  • Двоеточие
  • Две цифры за секунду. Он дополняется нулями, чтобы обеспечить две цифры.
  • Если нано секунды равен нулю или недоступен, то формат завершен.
  • Десятичная точка
  • От одной до девяти цифр для нано секунды. При необходимости будет выведено столько цифр, сколько потребуется.

Почему здесь не работают квадратные скобки

Вы не можете заключить квадратные скобки в середину строки повторений одного и того же формата шаблона письма. [.[S[S[S]]]] понимается как необязательно точка, за которой необязательно следуют одна-десятая git доли секунды, за которой, возможно, следует одна -ди git доля секунды, за которой, возможно, следует одна-ди git доля секунды. Как отметил Sweeper в комментарии, он может работать без исключения, если дробь равна .111, но, вероятно, будет восприниматься как .1, при этом 1 указывается три раза. И сломается, если три цифры не равны. Вместо этого вы могли бы сойти с [.[SSS][SS][S]] для необязательного десятичного знака, за которым следовали либо 3, 2, либо 1 десятичный знак. Сначала нужно поставить 3 знака после запятой.

Ссылка

0 голосов
/ 14 апреля 2020

Мне не совсем подходят эти дополнительные скобки для миллисекунд, но вы всегда можете создать DateTimeFormatter с дополнительными миллисекундами, используя DateTimeFormatterBuilder

DateTimeFormatter formatter1 = new DateTimeFormatterBuilder().appendPattern("yyyy-MM-dd HH:mm:ss")
                                    .optionalStart()
                                    .appendFraction(ChronoField.MILLI_OF_SECOND, 0, 3, true)
                                    .optionalEnd()
                                    .toFormatter();
...