Skip to content

Instantly share code, notes, and snippets.

@hussachai
Last active July 18, 2016 15:16
Show Gist options
  • Save hussachai/7cb359711a84c97afe1d000093921c8d to your computer and use it in GitHub Desktop.
Save hussachai/7cb359711a84c97afe1d000093921c8d to your computer and use it in GitHub Desktop.
import java.time.LocalDate
import java.time.format.DateTimeFormatter
import java.time.temporal.TemporalAccessor
import org.scalameter.{Key, Warmer, _}
import scala.annotation.tailrec
import scala.util.{Failure, Success, Try}
/**
* Created by Hussachai on 7/15/2016.
*/
object ParsingDateString extends App {
val dateFormats = List(
"dd/MM/uuuu",
"MMM dd, uuuu",
"dd MMMM uuuu",
"dd MMM uuuu",
"dd-MM-uuuu"
).map(p => (p, DateTimeFormatter.ofPattern(p))) ++ (1 to 1000).map{ i =>
val p = "dd-MM-uuuu."+i
(p, DateTimeFormatter.ofPattern("dd-MM-uuuu"+p))
}
//Eager collection - It's bad because it tries all the patterns
def normalizeDate(dateStr: String): Option[String] = {
val trimmedDate = dateStr.trim
if(trimmedDate.isEmpty) None
else {
dateFormats.map { case (pattern, fmt) =>
Try(fmt.parse(trimmedDate))
}.find(_.isSuccess).map{ t =>
DateTimeFormatter.ISO_LOCAL_DATE.format(t.get) }
}
}
//Lazy collection
def normalizeDate1(dateStr: String): Option[String] = {
val trimmedDate = dateStr.trim
if(trimmedDate.isEmpty) None
else {
dateFormats.toStream.map { case (pattern, fmt) =>
Try(fmt.parse(trimmedDate))
}.find(_.isSuccess).map{ t =>
DateTimeFormatter.ISO_LOCAL_DATE.format(t.get) }
}
}
//Tail-recursion
def normalizeDate2(dateStr: String): Option[String] = {
val trimmedDate = dateStr.trim
@tailrec
def normalize(patterns: List[(String, DateTimeFormatter)]): Try[TemporalAccessor] = patterns match {
case head::tail => {
val resultTry = Try(head._2.parse(trimmedDate))
if(resultTry.isSuccess) resultTry
else normalize(tail)
}
case _ => Failure(new RuntimeException("no match found"))
}
if(trimmedDate.isEmpty) None
else {
normalize(dateFormats).map(DateTimeFormatter.ISO_LOCAL_DATE.format(_)).toOption
}
}
//Imperative
def normalizeDate3(dateStr: String): Option[String] = {
val trimmedDate = dateStr.trim
if(trimmedDate.isEmpty) None
else {
for((pattern, fmt) <- dateFormats) {
val dateTry = Try(fmt.parse(trimmedDate))
if(dateTry.isSuccess){
return Some(DateTimeFormatter.ISO_LOCAL_DATE.format(dateTry.get))
}
}
None
}
}
//collectFirst with extractor
def normalizeDate4(dateStr: String): Option[String] = {
object DateExtractor {
def unapply(t: (String, DateTimeFormatter)): Option[TemporalAccessor] = Try(t._2.parse(dateStr)).toOption
}
dateFormats.collectFirst{
case DateExtractor(t) => t
}.map { d =>
DateTimeFormatter.ISO_LOCAL_DATE.format(d)
}
}
val standardConfig = config(
Key.exec.minWarmupRuns -> 100,
Key.exec.maxWarmupRuns -> 500,
Key.exec.benchRuns -> 10000
) withWarmer(new Warmer.Default) withMeasurer(new Measurer.IgnoringGC)
println(s"Collection size: ${dateFormats.size}")
val time = standardConfig measure {
normalizeDate("12 January 2012")
}
println(s"Eager-Collection: $time ms")
val time1 = standardConfig measure {
normalizeDate1("12 January 2012")
}
println(s"Lazy-Collection: $time1 ms")
val time2 = standardConfig measure {
normalizeDate2("12 January 2012")
}
println(s"Tail recursion: $time2 ms")
val time3 = standardConfig measure {
normalizeDate3("12 January 2012")
}
println(s"Imperative: $time3 ms")
val time4 = standardConfig measure {
normalizeDate4("12 January 2012")
}
println(s"collectFirst with extractor: $time4 ms")
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment