Reputation: 324
I have a method as follows:
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
}
Here, I am trying to identify the date format of an input string. The way I go about it is to iterate over all dateFormats
and try to parse the string using SimpleDateFormat
. If it is correctly parsed, then I return the format, else I let the catch
block handle it. This method works great for most cases except for if I try to parse:
val inputStr = "02/02/2017"
val dateFormat = checkDateFormat(inputStr)
In this case, for some reason inputStr
is parsed by yyyy/MM/dd
instead of getting handled by catch
(I want it to be parsed by MM/dd/yyyy
instead). Is there a different way I should be parsing these strings (eg. only through regex pattern matching) or is there another way I can get the example correctly parsed?
Edit: I would prefer not to use regex
as I would like to add more formats into dateFormats
and it would be tedious, but if there is no other option, I'm open to it.
Upvotes: 1
Views: 565
Reputation: 27356
Here is a simpler way to write this function:
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)
}
Using find
means that this will return as soon as a working format is found.
If you want the actual date, try this:
def parseDate(dateStr: String): Option[Date] = {
dateFormats
.view
.map(df => Try{new SimpleDateFormat(df).parse(dateStr)})
.find(_.isSuccess)
.flatMap(_.toOption)
}
In this case, using view
ensures that parsing stops as soon as a valid format is found.
Upvotes: 1
Reputation: 22449
I would recommend using the more reliable java.time
API and replacing try-catch
with Try
as follows:
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!
Upvotes: 0
Reputation: 375495
From the java docs:
For parsing, if the number of pattern letters is more than 2, the year is interpreted literally, regardless of the number of digits. So using the pattern "MM/dd/yyyy", "01/11/12" parses to Jan 11, 12 A.D.
In this case it's intepreted as year 2AD:
@ new SimpleDateFormat("YYYY/MM/dd").parse(inputStr)
res8: java.util.Date = Sun Jan 01 00:00:00 PST 2
One option is to regex pattern match before doing these tests.
Upvotes: 0