字符串在Scala中被错误地解析为日期时间格式

时间:2018-05-21 20:53:03

标签: scala datetime

我有一个方法如下:

def checkDateFormat(dateStr: String): Any = {
val dateFormats = List(
  "yyyy/MM/dd",
  "MM/dd/yyyy",
  "MMM dd, yyyy",
  "dd MMM yyyy",
  "yyyy-MM-dd"
)

dateFormats.foreach(format => {
  try {
      val date = new SimpleDateFormat(format).parse(dateStr)
      return format
  }
  catch {
    case e: Exception => {
      println("Exception")
      /* do nothing */
    }
  }
})
return
}

这里,我试图识别输入字符串的日期格式。我的方法是迭代所有dateFormats并尝试使用SimpleDateFormat解析字符串。如果它被正确解析,那么我返回格式,否则我让catch块处理它。这种方法适用于大多数情况,除非我尝试解析:

 val inputStr = "02/02/2017"
 val dateFormat = checkDateFormat(inputStr)

在这种情况下,出于某种原因,inputStr解析yyyy/MM/dd而不是由catch处理(我希望它由MM/dd/yyyy解析)。我是否应该以不同的方式解析这些字符串(例如,仅通过正则表达式模式匹配),还是有另一种方法可以正确解析示例?

编辑:我不想使用regex,因为我想在dateFormats中添加更多格式,这会很乏味,但如果没有其他选项,我会对此持开放态度

3 个答案:

答案 0 :(得分:1)

这是编写此函数的更简单方法:

def checkDateFormat(dateStr: String): Option[String] = {
  val dateFormats = List(
    "yyyy/MM/dd",
    "MM/dd/yyyy",
    "MMM dd, yyyy",
    "dd MMM yyyy",
    "yyyy-MM-dd"
  )

  def validFormat(df: String) =
    Try{new SimpleDateFormat(df).parse(dateStr)}.isSuccess

  dateFormats.find(validFormat)
}

使用find表示只要找到工作格式,就会立即返回。

如果您想要实际日期,请尝试以下方法:

def parseDate(dateStr: String): Option[Date] = {
  dateFormats
    .view
    .map(df => Try{new SimpleDateFormat(df).parse(dateStr)})
    .find(_.isSuccess)
    .flatMap(_.toOption)
}

在这种情况下,使用view可确保在找到有效格式后立即停止解析。

答案 1 :(得分:0)

来自java docs

  

对于解析,如果模式字母的数量大于2,则无论数字位数如何,都按字面解释年份。所以使用模式" MM / dd / yyyy"," 01/11/12"解析到公元12年1月11日

在这种情况下,它被解释为第2AD年:

@ new SimpleDateFormat("YYYY/MM/dd").parse(inputStr)
res8: java.util.Date = Sun Jan 01 00:00:00 PST 2

一种选择是在进行这些测试之前进行正则表达式模式匹配。

答案 2 :(得分:0)

我建议使用更可靠的java.time API并将try-catch替换为Try,如下所示:

def checkDateFormat(dateStr: String): String = {
  import java.time.LocalDate
  import java.time.format.DateTimeFormatter
  import scala.util.Try

  val dateFormats = List(
    "yyyy/MM/dd",
    "MM/dd/yyyy",
    "MMM dd, yyyy",
    "dd MMM yyyy",
    "yyyy-MM-dd"
  )

  dateFormats.dropWhile( format =>
    Try( LocalDate.parse(dateStr, DateTimeFormatter.ofPattern(format)) ).isFailure
  ).
  headOption match {
    case Some(fmt) => fmt
    case None => "No Match!"
  }
}

checkDateFormat("2018/05/21")
// res1: String = yyyy/MM/dd

checkDateFormat("05/21/2018")
// res2: String = MM/dd/yyyy

checkDateFormat("May 21, 2018")
// res3: String = MMM dd, yyyy

checkDateFormat("2018 05 21")
// res4: String = No Match!