Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Introduction to Minitime

Pishen Tsai
September 09, 2019

Introduction to Minitime

在 Java 裡,計算日期跟時間總是一件繁瑣的事,落落長的 code,可能只是為了算出兩個月又三天後的餅乾過期了沒。藉由 Scala 強大的 DSL 特性,我設計了一個簡潔版的 time library,只要透過單純的 + - * /,就可以做到原本要打一堆字才能做到的事。

Pishen Tsai

September 09, 2019
Tweet

More Decks by Pishen Tsai

Other Decks in Programming

Transcript

  1. LocalDate(2019,8,31) + 4.days LocalDate(2019,8,31) + 3.months LocalDate(2019,8,31) + 2.weeks LocalDate(2019,8,31)

    + 1.year LocalDate(2019,8,31) + (2.months + 3.days) Date Operations in Minitime
  2. Arithmetic Rules in Minitime LocalDate Period + = LocalDate LocalDate

    Period - = LocalDate Period Period + = Period Period Period - = Period LocalDate LocalDate - = Period Period Int * = Period
  3. Arithmetic Rules in Minitime LocalTime Duration + = LocalTime LocalDateTime

    Period - = LocalDateTime ZonedDateTime Duration + = ZonedDateTime Duration Duration + = Duration LocalDateTime LocalDateTime - = Duration Duration Int * = Duration Duration Int / = Duration LocalTime LocalTime - = Duration ZonedDateTime Period - = ZonedDateTime and more...
  4. Date Comparison in Minitime LocalDate(2019,8,13) > LocalDate(2019,8,12) LocalDate(2019,8,13) < LocalDate(2019,8,14)

    LocalDate(2019,8,13) >= LocalDate(2019,8,13) LocalDate(2019,8,13) <= LocalDate(2019,8,13)
  5. Date Ordering in Java Time Seq(date1, date2, date3).sorted Seq(date1, date2,

    date3).max Seq(date1, date2, date3).min ✘ ✘ ✘
  6. Date Ordering in Minitime (Fixed in Scala 2.13) ✔ ✔

    ✔ Seq(date1, date2, date3).sorted Seq(date1, date2, date3).max Seq(date1, date2, date3).min import minitime._
  7. scala.math.Ordering[T] trait Seq[A] { def sorted(implicit ord: Ordering[A]): Seq[A] }

    Seq(5,4,3,2,1).sorted implicit val intOrd: Ordering[Int] = ... (intOrd) (Included in Scala Standard Library)
  8. scala.math.Ordering[T] trait Ordering[T] { def compare(x: T, y: T): Int

    } implicit val dateOrd = new Ordering[LocalDate] { } Seq(date1,date2,date3).sorted (Included in Minitime) Typeclass override def compare(x: LocalDate, y: LocalDate) = { x.compareTo(y) } (dateOrd)
  9. minitime.Add[L, R] trait Add[L, R] { def apply(l: L, r:

    R): L } val add = new Add[LocalDate,Period] { override def apply(l: LocalDate, r: Period) = { l.plus(r) } } add.apply(LocalDate(2019,8,17), 3.days) // LocalDate(2019,8,20)
  10. minitime.Add[L, R] trait Add[L, R] { def apply(l: L, r:

    R): L } val add = new Add[LocalDate,Period] { override def apply(l: LocalDate, r: Period) = { l.plus(r) } } add(LocalDate(2019,8,17), 3.days) // LocalDate(2019,8,20) 這啥?要幹嘛?
  11. Implicit Classes implicit class Infix(l: LocalDateTime) { } LocalDateTime.now +

    3.days LocalDateTime.now + 3.minutes def +(r: Period) = l.plus(r) def +(r: Duration) = l.plus(r)
  12. Polymorphism? implicit class Infix(l: Temporal) { def +(r: TemporalAmount) =

    l.plus(r) } TemporalAmount Temporal Period Duration LocalDate LocalDateTime joda.time.LocalDate joda.time.Period ✘ ✘
  13. minitime.Add[L, R] implicit class Infix[L](l: L) { def +[R](r: R)(implicit

    add: Add[L,R]) = add(l,r) } implicit val ldp: Add[LocalDate,Period] = ... implicit val jda: Add[joda.time.LocalDate,Period] = ... LocalDate(2019,8,17) + 3.days new joda.time.LocalDate(2019,8,17) + 3.days
  14. One Implicit Class to Rule Them All implicit class Infix[L](l:

    L) { def +[R](r: R)(implicit add: Add[L,R]) = add(l,r) }
  15. One Implicit Class to Rule Them All implicit class Infix[L](l:

    L) { def +[R](r: R)(implicit add: Add[L,R]) = add(l,r) def -[R,C](r: R)(implicit sub: Subtract[L,R,C]) = sub(l,r) }
  16. One Implicit Class to Rule Them All implicit class Infix[L](l:

    L) { def +[R](r: R)(implicit add: Add[L,R]) = add(l,r) def -[R,C](r: R)(implicit sub: Subtract[L,R,C]) = sub(l,r) def *(s: Int)(implicit mul: Multiply[L]) = mul(l,s) }
  17. One Implicit Class to Rule Them All implicit class Infix[L](l:

    L) { def +[R](r: R)(implicit add: Add[L,R]) = add(l,r) def -[R,C](r: R)(implicit sub: Subtract[L,R,C]) = sub(l,r) def *(s: Int)(implicit mul: Multiply[L]) = mul(l,s) def /[R,C](r: R)(implicit div: Divide[L,R,C]) = div(l,r) }
  18. Arithmetic Rules in Minitime LocalTime Duration + = LocalTime LocalDateTime

    Period - = LocalDateTime ZonedDateTime Duration + = ZonedDateTime Duration Duration + = Duration LocalDateTime LocalDateTime - = Duration Duration Int * = Duration Duration Int / = Duration LocalTime LocalTime - = Duration ZonedDateTime Period - = ZonedDateTime
  19. Arithmetic Rules in Minitime implicit val a1: Add[LocalTime,Duration] LocalDateTime Period

    - = LocalDateTime ZonedDateTime Duration + = ZonedDateTime Duration Duration + = Duration LocalDateTime LocalDateTime - = Duration Duration Int * = Duration Duration Int / = Duration LocalTime LocalTime - = Duration ZonedDateTime Period - = ZonedDateTime
  20. Arithmetic Rules in Minitime implicit val a1: Add[LocalTime,Duration] ZonedDateTime Duration

    + = ZonedDateTime Duration Duration + = Duration LocalDateTime LocalDateTime - = Duration Duration Int * = Duration Duration Int / = Duration LocalTime LocalTime - = Duration ZonedDateTime Period - = ZonedDateTime implicit val s1: Subtract[LocalDateTime,Period,LocalDateTime]
  21. Arithmetic Rules in Minitime And everyone can add his own

    rules... implicit val a2: Add[ZonedDateTime,Duration] implicit val a3: Add[Duration,Duration] implicit val s2: Subtract[LocalDateTime,LocalDateTime,Duration implicit val m1: Multiply[Duration] implicit val d1: Divide[Duration,Int,Duration] implicit val s3: Subtract[LocalTime,LocalTime,Duration] implicit val s4: Subtract[ZonedDateTime,Period,ZonedDateTime] implicit val s1: Subtract[LocalDateTime,Period,LocalDateTime] implicit val a1: Add[LocalTime,Duration]
  22. minitime.TimeRange[T, S] // TimeRange( // 2019-08-23,2019-08-24,2019-08-25,2019-08-26,2019-08-27 // ) val dates:

    TimeRange[LocalDate,Period] = { } LocalDate(2019,8,23) to LocalDate(2019,8,27)
  23. minitime.TimeRange[T, S] // TimeRange( // 2019-08-23,2019-08-25,2019-08-27 // ) val dates:

    TimeRange[LocalDate,Period] = { } LocalDate(2019,8,23) to LocalDate(2019,8,27) by 2.days
  24. minitime.TimeRange[T, S] val dates: TimeRange[LocalDate,Period] = { } LocalDate(2019,8,23) to

    LocalDate(2019,8,27) by 2.days val dateSeq: Seq[LocalDate] = dates // Seq( // 2019-08-23,2019-08-25,2019-08-27 // )
  25. Question 1 在明年的聖誕節之前,還有幾個13號星期五? val dates = (LocalDate.now to LocalDate(2020,12,25)) .filter(d

    => d.getDayOfWeek == FRIDAY && d.getDayOfMonth == 13) // Seq(2019-09-13, 2019-12-13, 2020-03-13, 2020-11-13)
  26. Question 2 承上題,每個13號星期五彼此之間相隔幾天? dates.zip(dates.tail).map { case (a, b) => b

    - a } // Seq(P91D, P91D, P245D) 2019-09-13 2019-12-13 2020-03-13 2020-11-13 91 days 91 days 245 days
  27. Question 3 承上上題,有幾個13號星期五會出現在 下一個母親節 跟 下一個感恩節 之間? (五月的第二個星期日 ) (11月的第四個星期四)

    val mother = (LocalDate(2020,5,1) to LocalDate(2020,5,31)) .filter(_.getDayOfWeek == SUNDAY)(1) val turkey = (LocalDate(2019,11,1) to LocalDate(2019,11,30)) .filter(_.getDayOfWeek == THURSDAY)(3) dates.filter(d => d > turkey && d < mother) // Seq(2019-12-13, 2020-03-13)