Joda-timeで時間間隔を表現するのにどのクラスを使うべきなのかと考えて調べてみたのでメモ。
Interval
- 「時刻Aから時刻Bまでの間」
- 両端の時間が指定された時間軸の中で固定の範囲
-
contains(ReadableInstant instant)
によってある時刻がその範囲に含まれるか検出できる
Duration
- 「ミリ秒で表現される時間の長さ」
-
Interval#toDuration
で作ったりできる
Period
- 「時間単位(年、週、分など)で構成される時間の長さ」
-
Duration
とは違い、例えば「1年間」で表現されるPeriod
は計算時にうるう年をまたぐかどうかなどが考慮される
例: 2016年1月1日 -> 2017年1月1日では2月29日をまたぐため1年間の日数は366日
scala> import org.joda.time._
scala> val d = new LocalDate(2016,1,1)
d: org.joda.time.LocalDate = 2016-01-01
scala> val p = Period.years(1).withWeeks(5).withDays(10)
p: org.joda.time.Period = P1Y5W10D
scala> d.plus(p)
res1: org.joda.time.LocalDate = 2017-02-15
scala> d.plusYears(1)
res2: org.joda.time.LocalDate = 2017-01-01 // 一つの時間単位について計算するだけならこちらのメソッドでも可
scala> p.toDurationFrom(d.toDateTimeAtCurrentTime)
res21: org.joda.time.Duration = PT35510400S // 2016-01-01を基準にした時のDuration
scala> p.toDurationFrom(d.plusYears(1).toDateTimeAtCurrentTime)
res22: org.joda.time.Duration = PT35424000S // 2017-01-01を基準にした時のDuration
補足:Periodの比較は面倒
scala> val p2 = new Period(d, d.plus(p))
p2: org.joda.time.Period = P1Y1M2W // 2つの日付から差分を取る
scala> p.equals(p2)
res3: Boolean = false // 時間表現が異なるため同じとみなされない
scala> val p3 = new Period(d, d.plus(p), PeriodType.yearWeekDay)
p3: org.joda.time.Period = P1Y6W3D // 差分の計算方法を年週日にする
scala> p.equals(p3)
res4: Boolean = false // でもやっぱり合わない
scala> p.normalizedStandard.equals(p3)
res17: Boolean = false // 同じP1Y6W3Dになっても一致したとみなされない
scala> p.normalizedStandard.minus(p3).equals(Period.ZERO)
res19: Boolean = true // やっと一致判定した
一致判定は割にあわないですね…。