Java или Scala - быстрый способ разбора дат в разных форматах с использованием java.time. - PullRequest
0 голосов
/ 03 февраля 2019

Я хотел бы иметь общий и быстрый парсер для дат, который поставляется в случайном формате, например:

  • 2018
  • 2018-12-31
  • 2018/ 12/31
  • 2018 декабрь 31
  • 20181231151617
  • 2018-12-31T15: 16: 17
  • 2018-12-31T15: 16: 17.123456
  • 2018-12-31T15: 16: 17.123456Z
  • 2018-12-31T15: 16: 17.123456 UTC
  • 2018-12-31T15: 16: 17.123456 + 01:00
  • ... так много возможностей

Есть ли хороший способ, которым "или" магическая "функция делает это?

В настоящее время я планирую использовать что-то вродеэто:

val formatter = new DateTimeFormatterBuilder()
  .appendPattern("[yyyy-MM-dd'T'HH:mm:ss]")
  .appendPattern("[yyyy-MM-dd]")
  .appendPattern("[yyyy]")
  // add so many things here
  .parseDefaulting(ChronoField.MONTH_OF_YEAR, 1)
  .parseDefaulting(ChronoField.DAY_OF_MONTH, 1)
  .parseDefaulting(ChronoField.HOUR_OF_DAY, 0)
  .parseDefaulting(ChronoField.MINUTE_OF_HOUR, 0)
  .parseDefaulting(ChronoField.SECOND_OF_MINUTE, 0)
  .parseDefaulting(ChronoField.MICRO_OF_SECOND, 0)
  .toFormatter()


val temporalAccessor = formatter.parse("2018")
val localDateTime = LocalDateTime.from(temporalAccessor)
localDateTime.getHour
val zonedDateTime = ZonedDateTime.of(localDateTime, ZoneId.systemDefault)
val result = Instant.from(zonedDateTime)

Но есть ли более разумный способ, чем указание сотен форматов?

Большинство ответов, которые я нашел, устарели (до Java8) или не фокусируются на производительности и значительном количестверазные форматы.

1 Ответ

0 голосов
/ 04 февраля 2019

Нет, нет никакого приятного / волшебного способа сделать это по двум основным причинам:

  1. Существуют различия и неоднозначности в форматах данных, которые делают общий анализатор очень трудным.например, 11/11/11

  2. Вы ищете очень высокую производительность, которая исключает любые методы грубой силы.1us на дату означает всего несколько тысяч инструкций для полного разбора.

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

Вотпример, который касается всех дат, которые вы перечислили:

val DateMatch = """(\d\d\d\d)[-/ ]?((?:\d\d)|(?:\w\w\w))?[-/ ]?(\d\d)?T?(\d\d)?:?(\d\d)?:?(\d\d)?[\.]*(\d+)?(.*)?""".r

date match {
  case DateMatch(year, month, day, hour, min, sec, usec, timezone) =>
    (year, Option(month).getOrElse("1"), Option(day).getOrElse(1), Option(hour).getOrElse(0), Option(min).getOrElse(0), Option(sec).getOrElse(0), Option(usec).getOrElse(0), Option(timezone).getOrElse(""))
  case _ =>
    throw InvalidDateException
}

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

...