6

I'm looking for a nice way to validate and then compare a date string passed from a REST service.

If I get 2012-12-25 (year-month-day) passed as a string, what would be an elegant way to confirm it's a valid date, and then to say that the date is in the future or in the past?

To work with dates in Scala, one can obviously use existing Java libraries. But, working with dates in Java has always been like serving the dark side, so I don't want to drag too much of that legacy into my current coding style. Looking at the Scala Dates example on langref.org, it feels that I'll be back to coding Java if I follow this style of programming.

Jack
  • 15,582
  • 17
  • 86
  • 162
  • 2
    I'm not a Scala expert by any means, but maybe the [Joda Time wrapper by the name of 'Scala Time'](https://github.com/jorgeortiz85/scala-time) could work for you... – Patryk Ćwiek Dec 05 '12 at 20:10

4 Answers4

5

JodaTime is fine, fine, fine, don't worry about the dark side, it doesn't exist (or at least not in this particular Java library).

// "20121205".to_date
class String2Date(ymd: String) {
  def to_date = {  
    try{ Some(ymdFormat.parseDateTime(ymd)) } 
    catch { case e:Exception => None }
  }
  val ymdFormat = org.joda.time.format.DateTimeFormat.forPattern("yyyyMMdd")
}
@inline implicit final def string2Date(ymd: String) = new String2Date(ymd)

def dater(ymd: String) = {
  val other = new JodaTime
  ymd.to_date map{d=>
    if(d.isBefore other) ...
    else ...
  } getOrElse("bad date format")
}

Can do virtually anything date/time related with JodaTime; it's absurd how good this library is: unequivocal thumbs up.

virtualeyes
  • 10,859
  • 6
  • 49
  • 89
  • Looks like a good option, thanks. Would you normally use the scala-time (https://github.com/jorgeortiz85/scala-time) project? – Jack Dec 06 '12 at 05:58
  • no, have not found a need for ScalaTime, JodaTime as is is quite concise; i.e. the DSL enhancements that ScalaTime tacks on are not essential for my needs. JodaTime works seamlessly with Scala, Java interop proof in action ;-) – virtualeyes Dec 06 '12 at 12:55
4

You can do this using the standard Java SimpleDateFormat library:

def parseDate(value: String) = {
  try {
    Some(new SimpleDateFormat("yyyy-MM-dd").parse(value))
  } catch {
    case e: Exception => None
  }
} 

And then used it like so:

parseDate("2012-125")   // None
parseDate("2012-12-05") // Some(Wed Dec 05 00:00:00 EST 2012)

Then you can have a function for testing future dates:

def isFuture(value: Date) = value.after(new Date)
Dominic Bou-Samra
  • 13,072
  • 26
  • 92
  • 146
1

Although there are some downsides to using the java date libraries such as a lack of thread safety (Why is Java's SimpleDateFormat not thread-safe?) and a hard to use API, you could use implicits to make things a little more palatable:

implicit def stringToDate(date: String) = new {
  def parse(implicit format: String) = parse0(date)(format)
  private def parse0(date: String)(implicit format: String) = {
    val sdf = new SimpleDateFormat(format)
    sdf.setLenient(false)
    sdf.parse(date)
  }
  def isValid(implicit format: String) = try { parse0(date)(format); true } catch { case _ => false }
  def beforeNow(implicit format: String) = parse0(date)(format) before new Date()
  def afterNow(implicit format: String) = parse0(date)(format) after new Date()
} 

Then you could use it like this:

implicit val format = "yyyy-MM-dd"
"2012-12-02" isValid // true
"2012-12-02" beforeNow // ?
"2012-12-25" afterNow // ? 

Or, you could use scala-time:

import org.joda.time.format.ISODateTimeFormat._
import org.joda.time.DateTime
for(date <- date.parseOption("2012-12-02")) yield date < new DateTime // Option(?)

With this approach, you get a Scala-friendly interface, and you don't have to create and parse a new SimpleDateFormat object or store it in a thread local to avoid threading issues.

Community
  • 1
  • 1
yakshaver
  • 2,332
  • 1
  • 16
  • 20
1

If you really want to avoid using any date time library at all, you can use a suitable regular expression (such as the one in this answer: https://stackoverflow.com/a/7221570/227019) to validate that the string is indeed a valid ISO 8601 formatted date, and then use the fact that such dates can be lexicographically compared to determine their temporal ordering (simply format the current date in the same format and compare it with the other date using regular string comparison).

Community
  • 1
  • 1
Odd
  • 409
  • 3
  • 4