Scalaでstrtotime()関数を書いてみた

PHPにはstrtotime関数ってのがあって、

toshi@/home/toshi% php -r 'echo strtotime("now");'
1304350202%

こんな感じで時間を表すっぽい文字列を時間に変換してくれて便利。


pythonでもtimelibってのでおんなじことできる。

>>> import timelib
>>> timelib.strtotime("now")
1304350279


Scalaでやってみました。

import java.util.{Date, Locale}
import java.text.{SimpleDateFormat, DateFormat}
import scala.util.matching.Regex

trait Matcher {
  def test(description: String): Boolean
  val converter: PartialFunction[String, Date]
}

trait DateFormatMatcher extends Matcher{
  val dateFormat: DateFormat
}

trait RegexMatcher extends Matcher{
  val regex: Regex
  override def test(description: String): Boolean = {
    regex.findFirstIn(description.toLowerCase) match {
      case Some(e) => true
      case None => false
    }
  }
}

object RFC2822Matcher extends DateFormatMatcher {
  override val dateFormat = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss Z", Locale.ENGLISH)
  override def test(description: String): Boolean = {
    try {
      dateFormat.parse(description)
      true
    } catch {
      case e: Exception => false
    }
  }
  override val converter: PartialFunction[String, Date] = {
    case description if test(description) => dateFormat.parse(description)
  }
}

object NowMatcher extends RegexMatcher {
  override val regex = "now".r
  override val converter: PartialFunction[String, Date] = {
    case description if test(description) => new Date
  }
}

object YesterdayMatcher extends RegexMatcher {
  override val regex = "yesterday".r
  override val converter: PartialFunction[String, Date] = {
    case description if test(description) => {
      val date = new Date
      date.setTime(date.getTime - 24 * 60 * 60 * 1000)
      date
    }
  }
}

object DaysMatcher extends RegexMatcher {
  override val regex = "([0-9]+) day(s?) ago".r
  override val converter: PartialFunction[String, Date] = {
    case description if test(description) => {
      val regex(n_days_ago, _) = description
      val date = new Date
      date.setTime(date.getTime - n_days_ago.toInt * 24 * 60 * 60 * 1000)
      date
    }
  }
}

implicit def strtotime(description: String): Date = {
  val converter: Function[String, Date] = {
    List(NowMatcher, DaysMatcher, YesterdayMatcher, RFC2822Matcher)
    .map(_.converter).reduceLeft[PartialFunction[String, Date]](_ orElse _)
  }
  converter(description)
}


strtotime("Sun, 16 Jan 2011 01:14:51 +0900")
"Sun, 16 Jan 2011 01:14:51 +0900" getTime
strtotime("now")
strtotime("yesterday")
strtotime("10 days ago")

// res0: java.util.Date = Sun Jan 16 01:14:51 JST 2011
// res1: Long = 1295108091000
// res2: java.util.Date = Tue May 03 00:24:40 JST 2011
// res3: java.util.Date = Mon May 02 00:24:40 JST 2011
// res4: java.util.Date = Sat Apr 23 00:24:40 JST 2011

Matcherを足していけばいろいろ対応できるはず。