我具有以下实现方式:
val dateFormats = Seq("dd/MM/yyyy", "dd.MM.yyyy")
implicit def dateTimeCSVConverter: CsvFieldReader[DateTime] = (s: String) => Try {
val elem = dateFormats.map {
format =>
try {
Some(DateTimeFormat.forPattern(format).parseDateTime(s))
} catch {
case _: IllegalArgumentException =>
None
}
}.collectFirst {
case e if e.isDefined => e.get
}
if (elem.isDefined)
elem.get
else
throw new IllegalArgumentException(s"Unable to parse DateTime $s")
}
所以基本上我正在做的是,我在Seq上运行并尝试解析不同格式的DateTime。然后,我收集成功的第一个,如果不成功,我将抛出异常。
我对代码不完全满意。有没有更好的方法可以简化它?我需要将异常消息传递给调用者。
答案 0 :(得分:6)
这是迭代所有选项的可能解决方案
val dateFormats = Seq("dd/MM/yyyy", "dd.MM.yyyy")
val dates = Vector("01/01/2019", "01.01.2019", "01-01-2019")
dates.foreach(s => {
val d: Option[Try[DateTime]] = dateFormats
.map(format => Try(DateTimeFormat.forPattern(format).parseDateTime(s)))
.filter(_.isSuccess)
.headOption
d match {
case Some(d) => println(d.toString)
case _ => throw new IllegalArgumentException("foo")
}
})
这是一种替代解决方案,如果成功,该解决方案将返回 first 成功转换
val dateFormats = Seq("dd/MM/yyyy", "dd.MM.yyyy")
val dates = Vector("01/01/2019", "01.01.2019", "01-01-2019")
dates.foreach(s => {
dateFormats.find(format => Try(DateTimeFormat.forPattern(format).parseDateTime(s)).isSuccess) match {
case Some(format) => println(DateTimeFormat.forPattern(format).parseDateTime(s))
case _ => throw new IllegalArgumentException("foo")
}
})
答案 1 :(得分:5)
您的代码的一个问题是,无论日期是否已解析,它都会尝试所有模式。您可以使用像Stream这样的惰性集合来解决此问题:
def dateTimeCSVConverter(s: String) = Stream("dd/MM/yyyy", "dd.MM.yyyy")
.map(f => Try(DateTimeFormat.forPattern(format).parseDateTime(s))
.dropWhile(_.isFailure)
.headOption
jwvh提出的带有find(您不必致电headOption
)的解决方案更好:
def dateTimeCSVConverter(s: String) = Stream("dd/MM/yyyy", "dd.MM.yyyy")
.map(f => Try(DateTimeFormat.forPattern(format).parseDateTime(s))
.find(_.isSuccess)
如果没有模式匹配则返回None
。如果您想在这种情况下引发异常,则可以使用getOrElse
来包装选项:
...
.dropWhile(_.isFailure)
.headOption
.getOrElse(throw new IllegalArgumentException(s"Unable to parse DateTime $s"))
重要的是,当任何验证成功时,它不会继续进行,但会立即返回解析的日期。
答案 2 :(得分:3)
我现在就这样变得甜蜜了!我更喜欢这个!如果要收集所有成功和所有失败,请使用此选项。请注意,当您一旦发现成功就需要退出循环时,这可能会有点效率低下!
implicit def dateTimeCSVConverter: CsvFieldReader[DateTime] = (s: String) => Try {
val (successes, failures) = dateFormats.map {
case format => Try(DateTimeFormat.forPattern(format).parseDateTime(s))
}.partition(_.isSuccess)
if (successes.nonEmpty)
successes.head.get
else
failures.head.get
}