Java或Scala使用java.time快速解析具有许多不同格式的日期

我希望有一个通用的快速解析器,用于随机格式的日期,如:

> 2018年
> 2018-12-31
> 2018/12/31
> 2018年12月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之前)或者不关注性能和许多不同的格式.

最佳答案 不,没有好的/神奇的方法可以做到这一点,主要有两个原因:

>数据格式存在变化和含糊之处,使得通用解析器非常困难.例如11/11/11
>您正在寻找非常高的性能,它排除了任何暴力方法.每个日期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
}

正如您所看到的,一旦包含所有可能的日期,它将变得非常毛茸茸.但是如果正则表达式引擎可以处理它,那么它应该是高效的,因为正则表达式应该编译为一次查看每个字符的状态机.

点赞