Monday 8 April 2013

Extended Joda DateTime Formatter to format by Quarter

This is just a simple wrapper for the Joda DateTimeFormatter which allows the formatting of quarter as follows:

 Q = 2
 QQ = 02
 QQQ = Q2
 QQQQ = second quarter

I have only hard-coded the English for this, and have only ported the formatter functions I needed.


import org.joda.time.format.{DateTimeFormat, DateTimeFormatter}
import org.joda.time.{DateTimeZone, DateTime}

object ExtendedDateTimeFormat {
  val regex =  """^([^Q]*)(|Q{1,4})([^Q]*)$""".r

  def forPattern(pattern:String) = pattern match {
    case ExtendedDateTimeFormat.regex(beginning, quarter, end) => ExtendedDateTimeFormatter(
      DateTimeZone.getDefault,
      if (beginning.isEmpty) None else Some(DateTimeFormat.forPattern(beginning)),
      if (quarter.isEmpty) None else Some(quarter.length),
      if (end.isEmpty) None else Some(DateTimeFormat.forPattern(end))
    )
    case _ => throw new Exception("Invalid dateFormat")
  }
}

case class ExtendedDateTimeFormatter(dateTimeZone:DateTimeZone, s:Option[DateTimeFormatter], q:Option[Int], e:Option[DateTimeFormatter]) {

  def print(dt:Long):String = print(new DateTime(dt, dateTimeZone))
  def print(dt:DateTime):String =
    s.map(_.print(dt)).getOrElse("") + q.map{
      case 1 => getQuarter(dt).toString
      case 2 => "0" + getQuarter(dt)
      case 3 => "Q" + getQuarter(dt)
      case 4 => getQuarter(dt) match {
        case 1 => "first quarter"
        case 2 => "second quarter"
        case 3 => "third quarter"
        case 4 => "fourth quarter"
      }
    }.getOrElse("") + e.map(_.print(dt)).getOrElse("")

  def getQuarter(dt:DateTime) = dt.withZone(dateTimeZone).getMonthOfYear / 3  + 1

  def withZone(newDateTimeZone:DateTimeZone) = ExtendedDateTimeFormatter(newDateTimeZone, s.map(_.withZone(newDateTimeZone)), q, e.map(_.withZone(newDateTimeZone)))
}