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

org.specs2.time.Timer.scala Maven / Gradle / Ivy

The newest version!
package org.specs2
package time

import java.util.Calendar

import text.Plural._
import control.Exceptions._
import org.specs2.control.eff.{Eff, NoFx}
import org.specs2.control.origami.Fold

import scalaz.Scalaz._

/**
 * This trait provides Timer functionalities based on the Java Calendar milliseconds
 */
trait HmsTimer[T <: HmsTimer[T]] {
  /** elapsed times since for each stop */
  protected val elapsedTimes: List[Long] = Nil
  /** each time the timer is started we add the current time to this list of times number of millis when instantiating the object using this Trait */
  val startedTimestamps: List[Long] = Nil

  def copy(elapsed: List[Long], started: List[Long]): T
  /**
   * starts the with new elapsed time
   */
  def start = copy(Nil, getTime :: startedTimestamps)

  /**
   * restarts the Timer with no elapsed time
   */
  def restart = copy(Nil, Nil)

  /**
   * Stop the timer, store the number of elapsed millis and return a String representing the time as hour/minute/second/ms
   * @return the elapsed time as a String
   */
  def stop = copy((getTime - lastTimestamp) :: elapsedTimes, startedTimestamps.drop(1))

  /** add 2 timers together */
  def add(t: HmsTimer[T]) =
    copy((elapsedTimes ++ t.elapsedTimes).filterNot(_ == 0), startedTimestamps ++ t.startedTimestamps)

  /** @return true if this timer has been started */
  def isStarted = startedTimestamps.nonEmpty
  /** @return true if this timer has never been started */
  def neverStarted = !isStarted && elapsedTimes.isEmpty

  def totalMillis =
    if (isStarted) lastTimestamp - firstTimestamp
    else           elapsedTimes.sorted.lastOption.getOrElse(0L)

  private def lastTimestamp = startedTimestamps.sorted.lastOption.getOrElse(0L)
  private def firstTimestamp = startedTimestamps.sorted.headOption.getOrElse(0L)
  /**
   * @return a tuple with the elapsed hours, minutes, seconds and millis
   */
  def hourMinutesSecondsMillis = {
    val hours = totalMillis / 1000 / 3600
    val totalMillis1 = totalMillis - hours * 3600 * 1000
    val minutes = totalMillis1 / 1000 / 60
    val totalMillis2 = totalMillis1 - minutes * 60 * 1000
    val seconds = totalMillis2 / 1000
    val millis = totalMillis2 - seconds * 1000
    (hours, minutes, seconds, millis)
  }

  /**
   * @return a formatted string showing the hours, minutes and seconds
   */
  def hms: String = {
    val (hours, minutes, seconds, millis) = hourMinutesSecondsMillis
    List(hours.toInt.strictlyPositiveOrEmpty("hour"),
         minutes.toInt.strictlyPositiveOrEmpty("minute"),
         seconds.toInt.qty("second")).filter(_.nonEmpty).mkString(" ")
  }

  /**
   * @return a formatted string showing the hours, minutes, seconds and millis
   */
  def time: String = {
    val (_, _, _, millis) = hourMinutesSecondsMillis
    (if (hms != "0 second") hms + ", " else "") +
    millis + " ms"
  }

  /**
   * this method can be overriden for testing
   */
  protected def getTime = Calendar.getInstance.getTime.getTime
}

class SimpleTimer extends HmsTimer[SimpleTimer] {
  def copy(e: List[Long] = Nil, m: List[Long] = Nil) =
    new SimpleTimer {
      override protected val elapsedTimes = e
      override val startedTimestamps = m
    }

  override def toString = hms

  override def equals(a: Any) = a match {
    case s: SimpleTimer => true
    case other          => false
  }

  override def hashCode =
    elapsedTimes.hashCode
}

object SimpleTimer {
  def fromString(s: String) = new SimpleTimer {
    override protected val elapsedTimes = tryOrElse(List(java.lang.Long.parseLong(s)))(Nil)
  }

  def timerFold[T] = new Fold[NoFx, T, SimpleTimer] {
    type S = SimpleTimer
    def start = Eff.pure((new SimpleTimer).start)
    def fold: (S, T) => S = (s, t) => s
    def end(s: S) =  Eff.pure(s.stop)
  }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy