Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save krishnanraman/0a17ef012c1cb28edf3e44214f5d4e83 to your computer and use it in GitHub Desktop.
Save krishnanraman/0a17ef012c1cb28edf3e44214f5d4e83 to your computer and use it in GitHub Desktop.
human readable time difference java scala
scala> import java.util.concurrent.TimeUnit
import java.util.concurrent.TimeUnit
scala> val units = List((TimeUnit.DAYS,"days"),(TimeUnit.HOURS,"hours"), (TimeUnit.MINUTES,"minutes"), (TimeUnit.SECONDS,"seconds"))
units: List[(java.util.concurrent.TimeUnit, String)] = List((DAYS,days), (HOURS,hours), (MINUTES,minutes), (SECONDS,seconds))
scala> def humanReadable(timediff:Long):String = {
| val init = ("", timediff)
| units.foldLeft(init){ case (acc,next) =>
| val (human, rest) = acc
| val (unit, name) = next
| val res = unit.convert(rest,TimeUnit.MILLISECONDS)
| val str = if (res > 0) human + " " + res + " " + name else human
| val diff = rest - TimeUnit.MILLISECONDS.convert(res,unit)
| (str,diff)
| }._1
| }
humanReadable: (timediff: Long)String
scala> humanReadable((2 *24*60*60+ 5 *60*60+ 7 *60+ 9 )*1000)
res0: String = " 2 days 5 hours 7 minutes 9 seconds"
@MrCitron
Copy link

👍

with a little improvement on line 16 add .replaceFirst(" ", "") to remove the first useless string

@hugo-vrijswijk
Copy link

I've written something similar in a slightly (IMO) more functional way to work with a Scala Duration using foldLeft and without the TimeUnit->String tuple:

import java.util.concurrent.TimeUnit
import scala.concurrent.duration._

object DurationExtensions {
  implicit class HumanReadableExtension(duration: Duration) {
    final def toHumanReadable: String = {
      val units = Seq(TimeUnit.DAYS, TimeUnit.HOURS, TimeUnit.MINUTES, TimeUnit.SECONDS)

      val timeStrings = units
        .foldLeft((Seq.empty[String], duration.toMillis))({ case ((humanReadable, rest), unit) =>
          val name = unit.toString().toLowerCase()
          val result = unit.convert(rest, TimeUnit.MILLISECONDS)
          val diff = rest - TimeUnit.MILLISECONDS.convert(result, unit)
          val str = result match {
            case 0    => humanReadable
            case 1    => humanReadable :+ s"1 ${name.init}" // Drop last 's'
            case more => humanReadable :+ s"$more $name"
          }
          (str, diff)
        })
        ._1

      timeStrings.size match {
        case 0 => ""
        case 1 => timeStrings.head
        case _ => timeStrings.init.mkString(", ") + " and " + timeStrings.last
      }
    }
  }
}

// REPL

@ 462.seconds.toHumanReadable
res4: String = "7 minutes and 42 seconds"

@ 4462.seconds.toHumanReadable
res6: String = "1 hour, 14 minutes and 22 seconds"

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment