Created
May 12, 2017 11:11
-
-
Save P7h/2565c2379e4d32103441e12c8c905690 to your computer and use it in GitHub Desktop.
DateTime difference between 2 timestamps. Granularity from centuries to nanos.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.time.LocalDateTime | |
import scala.annotation.tailrec | |
object Stopwatch { | |
def main(args: Array[String]): Unit = { | |
val from = LocalDateTime.of(2001, 9, 11, 8, 46, 40, 250) | |
val to = LocalDateTime.now() | |
println(s"Time diff is [approach#1]: ${elapsedTime(from, to)}") | |
println(s"Time diff is [approach#2]: ${elapsedTimeApproach2(from, to)}") | |
} | |
// Original approach based on my requirements. | |
// The granularity with this approach is from centuries to nanos. | |
def elapsedTime(from: LocalDateTime, to: LocalDateTime): String = { | |
import java.time.temporal.ChronoUnit | |
import java.time.temporal.ChronoUnit._ | |
@tailrec | |
def elapsedTimeRec(fromRec: LocalDateTime, units: List[ChronoUnit], accum: String): String = { | |
units match { | |
case Nil => accum.trim | |
case head :: tail => | |
val (fromRecalc, newAccum) = { | |
val diff = fromRec.until(to, head) | |
diff match { | |
// If the diff is 0, don't display this unit and label. | |
case 0 => (fromRec, "") | |
case _ => val label = { | |
val tempLabel = head.toString | |
// If the diff is 1, strip off 's' from the label; aesthetics. | |
if (diff == 1) { | |
tempLabel.substring(0, tempLabel.length - 1) | |
} else { | |
tempLabel | |
} | |
} | |
(fromRec.plus(diff, head), s"$diff $label ") | |
} | |
} | |
elapsedTimeRec(fromRecalc, tail, accum + newAccum) | |
} | |
} | |
val reqdUnits = List[ChronoUnit]( | |
CENTURIES, | |
DECADES, | |
YEARS, | |
MONTHS, | |
WEEKS, | |
DAYS, | |
HOURS, | |
MINUTES, | |
SECONDS, | |
MILLIS, | |
MICROS, | |
NANOS) | |
elapsedTimeRec(from, reqdUnits, "") | |
} | |
// Approach#2 based on: https://gist.github.com/krishnanraman/0a17ef012c1cb28edf3e44214f5d4e83 | |
// The granularity with this approach is only from days to seconds. | |
def elapsedTimeApproach2(from: LocalDateTime, to: LocalDateTime): String = { | |
import java.time.ZoneOffset | |
import java.util.concurrent.TimeUnit._ | |
val units = List( | |
(DAYS, "Days"), | |
(HOURS, "Hours"), | |
(MINUTES, "Minutes"), | |
(SECONDS, "Seconds") | |
) | |
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, MILLISECONDS) | |
val str = if (res > 0) human + " " + res + " " + name else human | |
val diff = rest - MILLISECONDS.convert(res, unit) | |
(str, diff) | |
}._1 | |
} | |
val t1 = from.atZone(ZoneOffset.UTC).toInstant().toEpochMilli() | |
val t2 = to.atZone(ZoneOffset.UTC).toInstant().toEpochMilli() | |
humanReadable(t2 - t1).trim | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment