I am trying to write a parsing method that will take several date patterns and will try to parse string into java.sql.date using one of them. I managed to make it work for several patterns but I struggling to make it work for 'ddMMMyyyy' pattern. This is my method:
def parseDateFromString(
dateString: String,
patterns: Seq[String] = Seq("yyyy-MM-dd HH:mm:ss.nnnnnn", "yyyy-MM-dd HH:mm:ss[.SSS]", "ddMMMyyyy")
): Option[java.sql.Date] = {
import java.time.format.{DateTimeFormatter, DateTimeFormatterBuilder}
import java.time.LocalDate
def appendPatternsToFormatter(dateTimeFormatterBuilder: DateTimeFormatterBuilder, patterns: Seq[String]): DateTimeFormatterBuilder = {
patterns match {
case head :: tail =>
appendPatternsToFormatter(dateTimeFormatterBuilder.appendOptional(DateTimeFormatter.ofPattern(head)), tail)
case Nil =>
dateTimeFormatterBuilder
}
}
if (dateString.isEmpty) return None
val formatter = appendPatternsToFormatter(new DateTimeFormatterBuilder(), patterns).toFormatter
val localDate = LocalDate.parse(dateString, formatter)
Some(java.sql.Date.valueOf(localDate.toString))
}
It properly parse values like: "2019-06-17 23:31:19.673", "2019-06-17 23:31:19.673123", "2019-06-17 23:31:19" but it fails for "01JAN2020". I am not sure why. Previously when I used joda.time it worked fine (but I had to port it over to java.time because joda.time didn't allow to parse "yyyy-MM-dd HH:mm:ss.nnnnnn"). Any ideas? Is my pattern good or am I missing something?
Test case:
"ParseDateFromString" should "parse date string if date is in right format" in {
val dateString = "01JAN2020"
val expected = Some(java.sql.Date.valueOf("2020-01-01"))
val result = parseDateFromString(dateString)
result shouldBe expected
}
Exception I am getting:
- should parse date string if date is in right format *** FAILED *** (140 milliseconds)
java.time.format.DateTimeParseException: Text '01JAN2020' could not be parsed, unparsed text found at index 0
at java.time.format.DateTimeFormatter.parseResolved0(DateTimeFormatter.java:1952)
at java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1851)
at java.time.LocalDate.parse(LocalDate.java:400)
at com.company.ProjectParsingUtils$.parseDateFromString(ProjectParsingUtils.scala:42)
at com.company.ProjectParsingUtilsTest$$anonfun$1.apply(ProjectParsingUtilsTest.scala:16)
at com.company.ProjectParsingUtilsTest$$anonfun$1.apply(ProjectParsingUtilsTest.scala:12)
at org.scalatest.OutcomeOf$class.outcomeOf(OutcomeOf.scala:85)
at org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104)
at org.scalatest.Transformer.apply(Transformer.scala:22)
at org.scalatest.Transformer.apply(Transformer.scala:20)
Solution: By default dateTimeFormatter is case sensitive and it allows only to parse values like 01Jan2020. You can add .parseCaseInsensitive to change this behavior.
def parseDateFromString(
dateString: String,
patterns: Seq[String] = Seq("yyyy-MM-dd HH:mm:ss.nnnnnn","yyyy-MM-dd HH:mm:ss.nnnnn", "yyyy-MM-dd HH:mm:ss.nnnn", "yyyy-MM-dd HH:mm:ss[.SSS]", "ddMMMyyyy", "''ddMMMyyyy''", "ddMMMyyyy:HH:mm:ss.nnnnnnnnn", "''ddMMMyyyy:HH:mm:ss.nnnnnnnnn''")
): Option[java.sql.Date] = {
import java.time.format.{DateTimeFormatter, DateTimeFormatterBuilder}
import java.time.LocalDate
def appendPatternsToFormatter(dateTimeFormatterBuilder: DateTimeFormatterBuilder, patterns: Seq[String]): DateTimeFormatterBuilder = {
patterns match {
case head :: tail =>
appendPatternsToFormatter(dateTimeFormatterBuilder.appendOptional(DateTimeFormatter.ofPattern(head)), tail)
case Nil =>
dateTimeFormatterBuilder
}
}
if (dateString.isEmpty) return None
val formatter = appendPatternsToFormatter(new DateTimeFormatterBuilder().parseCaseInsensitive, patterns).toFormatter
val localDate = LocalDate.parse(dateString, formatter)
Some(java.sql.Date.valueOf(localDate.toString))
}