All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.velocidi.apso.time.IterableInterval.scala Maven / Gradle / Ivy

There is a newer version: 0.19.6
Show newest version
package com.velocidi.apso.time

import com.github.nscala_time.time.Imports._
import org.joda.time.ReadableInterval

/** A view of a time interval as an indexed sequence of `DateTimes`.
  */
trait IterableInterval extends IndexedSeq[DateTime] {

  /** The period of time between consecutive `DateTimes`.
    */
  val step: Period

  /** Returns an iterable interval with the same time range and with the given step.
    * @param step
    *   the step of the interval to return
    * @return
    *   an iterable interval with the same time range and with the given step.
    */
  def by(step: Period): IterableInterval
}

/** A view of a `ReadableInterval` as an indexed sequence of `DateTimes`.
  * @param interval
  *   the `ReadableInterval` to view as an indexed sequence
  * @param step
  *   the period of time between consecutive `DateTimes` in the sequence
  */
case class SteppedInterval(interval: ReadableInterval, step: Period) extends IterableInterval {

  lazy val length: Int = {
    var i = (interval.toDurationMillis / step.toDurationFrom(interval.getStart).millis).toInt
    if (apply(i) < interval.getEnd) {
      while (apply(i) <= interval.getEnd) { i += 1 }
      i
    } else {
      while (apply(i) > interval.getEnd) { i -= 1 }
      i + 1
    } // FIXME more intelligent code for this?
  }

  def apply(idx: Int) = interval.getStart + step.multipliedBy(idx)

  def by(newStep: Period) = new SteppedInterval(interval, newStep)
}

/** An iterable time interval with no elements.
  * @param step
  *   the period of time between consecutive `DateTimes`. Does not affect an empty interval
  */
case class EmptySteppedInterval(step: Period) extends IterableInterval {

  def length = 0
  def apply(idx: Int) = throw new IndexOutOfBoundsException
  def by(newStep: Period) = new EmptySteppedInterval(newStep)
}

/** Companion object containing a facotry for iterable time intervals.
  */
object IterableInterval {

  /** Creates a new iterable time interval from a `ReadableInterval`.
    * @param interval
    *   the `ReadableInterval` to view as an indexed sequence
    * @param step
    *   the period of time between consecutive `DateTimes`
    * @param lastInclusive
    *   `true` if the upper bound of the interval is to be included in the sequence
    * @return
    *   an iterable time interval with the given step.
    */
  def apply(interval: ReadableInterval, step: Period, lastInclusive: Boolean = true): IterableInterval =
    if (lastInclusive) SteppedInterval(interval, step)
    else if (interval.millis == 0) EmptySteppedInterval(step)
    else SteppedInterval(interval.getStart to interval.getEnd - 1.millis, step)
}

/** A view of a time interval as an indexed sequence of `LocalDate`.
  */
case class LocalDateInterval(i: IterableInterval) extends IndexedSeq[LocalDate] {
  def apply(idx: Int): LocalDate = i(idx).toLocalDate
  def by(newStep: Period) = LocalDateInterval(i.by(newStep))
  def length = i.length
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy