aboutsummaryrefslogblamecommitdiff
path: root/src/main/scala/xyz/driver/core/date.scala
blob: d3fd8a7302da54610a9807f8343df13ac4d1fced (plain) (tree)
1
2
3
4
5
6
7
8
9



                         




                            

             






                                                                                                 
                                

                















                                                                                











                                                                                                       

   




                                                                  









                                                                                         
                                                        


                                                                                      


       
 
package xyz.driver.core

import java.util.Calendar

import scala.util.Try

import scalaz.std.anyVal._
import scalaz.syntax.equal._

object date {

  object Day {
    def unapply(dayString: String): Option[Int] = {
      require(dayString.length === 2, s"ISO 8601 day string, DD, must have length 2: $dayString")
      Try(dayString.toInt).toOption
    }
  }

  type Month = Int @@ Month.type

  object Month {
    def apply(value: Int): Month = {
      require(0 to 11 contains value, "Month is zero-indexed: 0 <= value <= 11")
      value.asInstanceOf[Month]
    }
    val JANUARY   = Month(Calendar.JANUARY)
    val FEBRUARY  = Month(Calendar.FEBRUARY)
    val MARCH     = Month(Calendar.MARCH)
    val APRIL     = Month(Calendar.APRIL)
    val MAY       = Month(Calendar.MAY)
    val JUNE      = Month(Calendar.JUNE)
    val JULY      = Month(Calendar.JULY)
    val AUGUST    = Month(Calendar.AUGUST)
    val SEPTEMBER = Month(Calendar.SEPTEMBER)
    val OCTOBER   = Month(Calendar.OCTOBER)
    val NOVEMBER  = Month(Calendar.NOVEMBER)
    val DECEMBER  = Month(Calendar.DECEMBER)

    def unapply(monthString: String): Option[Month] = {
      require(monthString.length === 2, s"ISO 8601 month string, MM, must have length 2: $monthString")
      Try(monthString.toInt).toOption.map(isoM => apply(isoM - 1))
    }
  }

  object Year {
    def unapply(yearString: String): Option[Int] = {
      require(yearString.length === 4, s"ISO 8601 year string, YYYY, must have length 4: $yearString")
      Try(yearString.toInt).toOption
    }
  }

  final case class Date(year: Int, month: Month, day: Int) {
    override def toString = f"$year%04d-${month + 1}%02d-$day%02d"
  }

  object Date {
    implicit def dateOrdering: Ordering[Date] = Ordering.fromLessThan { (date1, date2) =>
      if (date1.year != date2.year) {
        date1.year < date2.year
      } else if (date1.month != date2.month) {
        date1.month < date2.month
      } else {
        date1.day < date2.day
      }
    }

    def fromString(dateString: String): Option[Date] = {
      dateString.split('-') match {
        case Array(Year(year), Month(month), Day(day)) => Some(Date(year, month, day))
        case _                                         => None
      }
    }
  }
}