
java.time.Duration.scala Maven / Gradle / Ivy
package java.time
import scala.collection.JavaConverters._
import java.time.temporal._
final class Duration private (seconds: Long, nanos: Int)
extends TemporalAmount with Comparable[Duration]
with java.io.Serializable {
import Preconditions.requireDateTime
import Constants._
import ChronoUnit._
requireDateTime(nanos >= 0 && nanos <= 999999999,
"nanos must be >= 0 and <= 999999999")
private val (normalizedSeconds, normalizedNanos) =
if (seconds < 0 && nanos > 0) (seconds + 1, nanos - NANOS_IN_SECOND)
else (seconds, nanos)
def get(unit: TemporalUnit): Long = unit match {
case SECONDS => seconds
case NANOS => nanos
case _ =>
throw new UnsupportedTemporalTypeException(s"Unit not supported: $unit")
}
def getUnits(): java.util.List[TemporalUnit] =
Seq[TemporalUnit](SECONDS, NANOS).asJava
def isZero(): Boolean = seconds == 0 && nanos == 0
def isNegative(): Boolean = seconds < 0
def getSeconds(): Long = seconds
def getNano(): Int = nanos
def withSeconds(seconds: Long): Duration =
new Duration(seconds, nanos)
def withNanos(nanosOfSecond: Int): Duration =
new Duration(seconds, nanosOfSecond)
def plus(duration: Duration): Duration = {
val seconds1 = duration.getSeconds
val sumNanos = nanos + duration.getNano
if (seconds1 >= 0) {
val sumSeconds = Math.addExact(seconds, seconds1)
if (sumNanos >= NANOS_IN_SECOND)
new Duration(Math.incrementExact(sumSeconds),
sumNanos - NANOS_IN_SECOND)
else
new Duration(sumSeconds, sumNanos)
} else {
val sumSeconds = Math.addExact(seconds, seconds1 + 1)
if (sumNanos >= NANOS_IN_SECOND)
new Duration(sumSeconds, sumNanos - NANOS_IN_SECOND)
else
new Duration(Math.decrementExact(sumSeconds), sumNanos)
}
}
def plus(amount: Long, unit: TemporalUnit): Duration = {
if (!unit.isDurationEstimated || unit == DAYS)
plus(unit.getDuration.multipliedBy(amount))
else
throw new UnsupportedTemporalTypeException(s"Unit not supported: $unit")
}
def plusDays(days: Long): Duration = plus(days, DAYS)
def plusHours(hours: Long): Duration = plus(hours, HOURS)
def plusMinutes(minutes: Long): Duration = plus(minutes, MINUTES)
def plusSeconds(seconds: Long): Duration = plus(seconds, SECONDS)
def plusMillis(millis: Long): Duration = plus(millis, MILLIS)
def plusNanos(nanos: Long): Duration = plus(nanos, NANOS)
def minus(duration: Duration): Duration = {
if (duration == Duration.Min)
plus(Duration.Max).plusNanos(1)
else
plus(duration.negated())
}
def minus(amount: Long, unit: TemporalUnit): Duration = {
if (!unit.isDurationEstimated || unit == DAYS)
minus(unit.getDuration.multipliedBy(amount))
else
throw new UnsupportedTemporalTypeException(s"Unit not supported: $unit")
}
def minusDays(days: Long): Duration = minus(days, DAYS)
def minusHours(hours: Long): Duration = minus(hours, HOURS)
def minusMinutes(minutes: Long): Duration = minus(minutes, MINUTES)
def minusSeconds(seconds: Long): Duration = minus(seconds, SECONDS)
def minusMillis(millis: Long): Duration = minus(millis, MILLIS)
def minusNanos(nanos: Long): Duration = minus(nanos, NANOS)
def multipliedBy(multiplicand: Long): Duration = {
val (prodNanosQuot, prodNanosRem) = {
try {
val prodNanos = Math.multiplyExact(normalizedNanos, multiplicand)
(prodNanos / NANOS_IN_SECOND, (prodNanos % NANOS_IN_SECOND).toInt)
} catch {
case _: ArithmeticException =>
val prodNanos = BigInt(normalizedNanos) * multiplicand
((prodNanos / NANOS_IN_SECOND).toLong, (prodNanos % NANOS_IN_SECOND).toInt)
}
}
val prodSeconds = Math.multiplyExact(normalizedSeconds, multiplicand)
val newSeconds =
if (prodNanosRem >= 0) Math.addExact(prodSeconds, prodNanosQuot)
else Math.addExact(prodSeconds, prodNanosQuot - 1)
val newNanos =
if (prodNanosRem >= 0) prodNanosRem
else prodNanosRem + NANOS_IN_SECOND
new Duration(newSeconds, newNanos)
}
def dividedBy(divisor: Long): Duration = divisor match {
case 1 => this
case -1 => negated
case _ =>
val secondsQuot = normalizedSeconds / divisor
val secondsRem = normalizedSeconds % divisor
val nanos = {
try {
val total = Math.addExact(
Math.multiplyExact(secondsRem, NANOS_IN_SECOND),
normalizedNanos)
total / divisor
} catch {
case _: ArithmeticException =>
val total = BigInt(secondsRem) * NANOS_IN_SECOND + normalizedNanos
(total / divisor).toLong
}
}
Duration.ofSeconds(secondsQuot).plusNanos(nanos)
}
def negated(): Duration = multipliedBy(-1)
def abs(): Duration = if (isNegative()) negated() else this
def addTo(temporal: Temporal): Temporal = {
val t1 =
if (seconds == 0) temporal
else temporal.plus(seconds, SECONDS)
if (nanos == 0) t1
else t1.plus(nanos, NANOS)
}
def subtractFrom(temporal: Temporal): Temporal = {
val t1 =
if (seconds == 0) temporal
else temporal.minus(seconds, SECONDS)
if (nanos == 0) t1
else t1.minus(nanos, NANOS)
}
def toDays(): Long = seconds / SECONDS_IN_DAY
def toHours(): Long = seconds / SECONDS_IN_HOUR
def toMinutes(): Long = seconds / SECONDS_IN_MINUTE
def toMillis(): Long = {
val millis1 = Math.multiplyExact(seconds, MILLIS_IN_SECOND)
val millis2 = nanos / NANOS_IN_MILLI
Math.addExact(millis1, millis2)
}
def toNanos(): Long =
Math.addExact(
Math.multiplyExact(seconds, NANOS_IN_SECOND), nanos)
def compareTo(that: Duration): Int = {
val secCmp = seconds.compareTo(that.getSeconds)
if (secCmp == 0) nanos.compareTo(that.getNano)
else secCmp
}
override def equals(that: Any): Boolean = that match {
case that: Duration =>
seconds == that.getSeconds && nanos == that.getNano
case _ => false
}
override def hashCode(): Int = 31 * seconds.hashCode + nanos
override def toString(): String = {
val mins = normalizedSeconds / 60
val secsOfMin = normalizedSeconds % 60
val hours = mins / 60
val minsOfHour = mins % 60
val hourPart = if (hours == 0) "" else hours.toString + "H"
val minPart = if (minsOfHour == 0) "" else minsOfHour.toString + "M"
val nanos1 = math.abs(normalizedNanos)
val decimals = f"$nanos1%09d".reverse.dropWhile(_ == '0').reverse
val decimalPart = if (decimals.isEmpty) "" else "." + decimals
val secsPart = secsOfMin match {
case 0 if seconds != 0 && nanos == 0 => ""
case 0 if seconds < 0 => "-0" + decimalPart + "S"
case n => n.toString + decimalPart + "S"
}
"PT" + hourPart + minPart + secsPart
}
}
object Duration {
import Constants._
final val ZERO = new Duration(0, 0)
private[time] final val Min = new Duration(Long.MinValue, 0)
private[time] final val Max = new Duration(Long.MaxValue, 999999999)
private[time] final val OneNano = new Duration(0, 1)
private[time] final val OneMicro = new Duration(0, NANOS_IN_MICRO)
private[time] final val OneMilli = new Duration(0, NANOS_IN_MILLI)
private[time] final val OneSecond = new Duration(1, 0)
private[time] final val OneMinute = new Duration(SECONDS_IN_MINUTE, 0)
private[time] final val OneHour = new Duration(SECONDS_IN_HOUR, 0)
private[time] final val OneDay = new Duration(SECONDS_IN_DAY, 0)
private[time] final val OneWeek = new Duration(SECONDS_IN_WEEK, 0)
private[time] final val OneMonth = new Duration(SECONDS_IN_MONTH, 0)
private[time] final val OneYear = OneMonth.multipliedBy(12)
def ofDays(days: Long): Duration = OneDay.multipliedBy(days)
def ofHours(hours: Long): Duration = OneHour.multipliedBy(hours)
def ofMinutes(minutes: Long): Duration = OneMinute.multipliedBy(minutes)
def ofSeconds(seconds: Long): Duration = new Duration(seconds, 0)
def ofSeconds(seconds: Long, nanoAdjustment: Long): Duration =
ofSeconds(seconds).plusNanos(nanoAdjustment)
def ofMillis(millis: Long): Duration = OneMilli.multipliedBy(millis)
def ofNanos(nanos: Long): Duration = OneNano.multipliedBy(nanos)
def of(amount: Long, unit: TemporalUnit): Duration = {
if (!unit.isDurationEstimated || unit == ChronoUnit.DAYS)
unit.getDuration.multipliedBy(amount)
else
throw new UnsupportedTemporalTypeException(s"Unit not supported: $unit")
}
def from(amount: TemporalAmount): Duration = {
amount.getUnits.asScala.foldLeft(ZERO) { (d, u) =>
d.plus(amount.get(u), u)
}
}
// Not implemented
// def parse(text: CharSequence): Duration
def between(start: Temporal, end: Temporal): Duration = {
try {
val nanos = start.until(end, ChronoUnit.NANOS)
Duration.ofNanos(nanos)
} catch {
case _:DateTimeException | _:ArithmeticException =>
val seconds = start.until(end, ChronoUnit.SECONDS)
val nanos = {
try {
end.get(ChronoField.NANO_OF_SECOND) -
start.get(ChronoField.NANO_OF_SECOND)
} catch {
case _: DateTimeException => 0
}
}
Duration.ofSeconds(seconds, nanos)
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy