Reduce Duration API surface, add top-level docs
- toDuration(unit) extension instead of constructors - toDouble/Long/Int(unit) function instead of inUnits() - remove static factory functions - remove MIN_VALUE/MAX_VALUE constants
This commit is contained in:
@@ -20,7 +20,7 @@ public abstract class AbstractLongClock(protected val unit: DurationUnit) : Cloc
|
||||
|
||||
override fun mark(): ClockMark = object : ClockMark {
|
||||
val startedAt = read()
|
||||
override fun elapsed(): Duration = Duration(read() - startedAt, this@AbstractLongClock.unit)
|
||||
override fun elapsed(): Duration = (read() - startedAt).toDuration(this@AbstractLongClock.unit)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ public abstract class AbstractDoubleClock(protected val unit: DurationUnit) : Cl
|
||||
|
||||
override fun mark(): ClockMark = object : ClockMark {
|
||||
val startedAt = read()
|
||||
override fun elapsed(): Duration = Duration(read() - startedAt, this@AbstractDoubleClock.unit)
|
||||
override fun elapsed(): Duration = (read() - startedAt).toDuration(this@AbstractDoubleClock.unit)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,20 @@ import kotlin.math.abs
|
||||
|
||||
private val storageUnit = DurationUnit.NANOSECONDS
|
||||
|
||||
/**
|
||||
* Represents the amount of time one instant of time is away from another instant.
|
||||
*
|
||||
* A negative duration is possible in a situation when the second instant is earlier than the first one.
|
||||
* An infinite duration value [Duration.INFINITE] can be used to represent infinite timeouts.
|
||||
*
|
||||
* To construct a duration use either the extension function [toDuration],
|
||||
* or the extension properties [hours], [minutes], [seconds] and so on,
|
||||
* available on [Int], [Long] and [Double] numeric types.
|
||||
*
|
||||
* To get the value of this duration expressed in a particular [duration units][DurationUnit]
|
||||
* use the functions [toInt], [toLong] and [toDouble]
|
||||
* or the properties [inHours], [inMinutes], [inSeconds], [inNanoseconds] and so on.
|
||||
*/
|
||||
@Suppress("NON_PUBLIC_PRIMARY_CONSTRUCTOR_OF_INLINE_CLASS")
|
||||
public inline class Duration internal constructor(internal val _value: Double) : Comparable<Duration> {
|
||||
// TODO: backend fails on init block, wait for KT-28055
|
||||
@@ -19,48 +33,9 @@ public inline class Duration internal constructor(internal val _value: Double) :
|
||||
|
||||
companion object {
|
||||
val ZERO: Duration = Duration(0.0)
|
||||
val MAX_VALUE: Duration = Duration(Double.MAX_VALUE)
|
||||
val MIN_VALUE: Duration = Duration(-Double.MAX_VALUE)
|
||||
val INFINITE: Duration = Duration(Double.POSITIVE_INFINITY)
|
||||
|
||||
|
||||
// constructing from number of units
|
||||
// option 1: static-like constructor functions
|
||||
|
||||
fun days(value: Int) = Duration(value, DurationUnit.DAYS)
|
||||
fun days(value: Long) = Duration(value, DurationUnit.DAYS)
|
||||
fun days(value: Double) = Duration(value, DurationUnit.DAYS)
|
||||
fun hours(value: Int) = Duration(value, DurationUnit.HOURS)
|
||||
fun hours(value: Long) = Duration(value, DurationUnit.HOURS)
|
||||
fun hours(value: Double) = Duration(value, DurationUnit.HOURS)
|
||||
fun minutes(value: Int) = Duration(value, DurationUnit.MINUTES)
|
||||
fun minutes(value: Long) = Duration(value, DurationUnit.MINUTES)
|
||||
fun minutes(value: Double) = Duration(value, DurationUnit.MINUTES)
|
||||
fun seconds(value: Int) = Duration(value, DurationUnit.SECONDS)
|
||||
fun seconds(value: Long) = Duration(value, DurationUnit.SECONDS)
|
||||
fun seconds(value: Double) = Duration(value, DurationUnit.SECONDS)
|
||||
fun milliseconds(value: Int) = Duration(value, DurationUnit.MILLISECONDS)
|
||||
fun milliseconds(value: Long) = Duration(value, DurationUnit.MILLISECONDS)
|
||||
fun milliseconds(value: Double) = Duration(value, DurationUnit.MILLISECONDS)
|
||||
fun microseconds(value: Int) = Duration(value, DurationUnit.MICROSECONDS)
|
||||
fun microseconds(value: Long) = Duration(value, DurationUnit.MICROSECONDS)
|
||||
fun microseconds(value: Double) = Duration(value, DurationUnit.MICROSECONDS)
|
||||
fun nanoseconds(value: Int) = Duration(value, DurationUnit.NANOSECONDS)
|
||||
fun nanoseconds(value: Long) = Duration(value, DurationUnit.NANOSECONDS)
|
||||
fun nanoseconds(value: Double) = Duration(value, DurationUnit.NANOSECONDS)
|
||||
}
|
||||
|
||||
|
||||
// constructing from number of units
|
||||
// option 0: constructors
|
||||
|
||||
// unit is lost after construction
|
||||
|
||||
constructor(value: Int, unit: DurationUnit) : this(convertDurationUnit(value.toDouble(), unit, storageUnit))
|
||||
constructor(value: Long, unit: DurationUnit) : this(convertDurationUnit(value.toDouble(), unit, storageUnit))
|
||||
constructor(value: Double, unit: DurationUnit) : this(convertDurationUnit(value, unit, storageUnit))
|
||||
|
||||
|
||||
// arithmetic operators
|
||||
|
||||
operator fun unaryMinus(): Duration = Duration(-_value)
|
||||
@@ -111,29 +86,19 @@ public inline class Duration internal constructor(internal val _value: Double) :
|
||||
|
||||
// conversion to units
|
||||
|
||||
fun toDouble(unit: DurationUnit): Double = convertDurationUnit(_value, storageUnit, unit)
|
||||
fun toLong(unit: DurationUnit): Long = toDouble(unit).toLong()
|
||||
fun toInt(unit: DurationUnit): Int = toDouble(unit).toInt()
|
||||
|
||||
// option 1: in- properties
|
||||
|
||||
val inDays: Double get() = inUnits(DurationUnit.DAYS)
|
||||
val inHours: Double get() = inUnits(DurationUnit.HOURS)
|
||||
val inMinutes: Double get() = inUnits(DurationUnit.MINUTES)
|
||||
val inSeconds: Double get() = inUnits(DurationUnit.SECONDS)
|
||||
val inMilliseconds: Double get() = inUnits(DurationUnit.MILLISECONDS)
|
||||
val inMicroseconds: Double get() = inUnits(DurationUnit.MICROSECONDS)
|
||||
val inNanoseconds: Double get() = inUnits(DurationUnit.NANOSECONDS)
|
||||
|
||||
fun inUnits(unit: DurationUnit) = convertDurationUnit(_value, storageUnit, unit)
|
||||
|
||||
// option 2: to- functions
|
||||
|
||||
fun toDays(): Double = toUnits(DurationUnit.DAYS)
|
||||
fun toHours(): Double = toUnits(DurationUnit.HOURS)
|
||||
fun toMinutes(): Double = toUnits(DurationUnit.MINUTES)
|
||||
fun toSeconds(): Double = toUnits(DurationUnit.SECONDS)
|
||||
fun toMilliseconds(): Double = toUnits(DurationUnit.MILLISECONDS)
|
||||
fun toMicroseconds(): Double = toUnits(DurationUnit.MICROSECONDS)
|
||||
fun toNanoseconds(): Double = toUnits(DurationUnit.NANOSECONDS)
|
||||
|
||||
fun toUnits(unit: DurationUnit): Double = convertDurationUnit(_value, storageUnit, unit)
|
||||
val inDays: Double get() = toDouble(DurationUnit.DAYS)
|
||||
val inHours: Double get() = toDouble(DurationUnit.HOURS)
|
||||
val inMinutes: Double get() = toDouble(DurationUnit.MINUTES)
|
||||
val inSeconds: Double get() = toDouble(DurationUnit.SECONDS)
|
||||
val inMilliseconds: Double get() = toDouble(DurationUnit.MILLISECONDS)
|
||||
val inMicroseconds: Double get() = toDouble(DurationUnit.MICROSECONDS)
|
||||
val inNanoseconds: Double get() = toDouble(DurationUnit.NANOSECONDS)
|
||||
|
||||
|
||||
override fun toString(): String = buildString {
|
||||
@@ -156,7 +121,7 @@ public inline class Duration internal constructor(internal val _value: Double) :
|
||||
absNs < 86400e9 * 1e7 -> DurationUnit.DAYS
|
||||
else -> DurationUnit.DAYS.also { scientific = true }
|
||||
}
|
||||
val value = inUnits(unit)
|
||||
val value = toDouble(unit)
|
||||
return when {
|
||||
scientific -> formatScientific(value)
|
||||
maxDecimals > 0 -> formatUpToDecimals(value, maxDecimals)
|
||||
@@ -175,7 +140,7 @@ public inline class Duration internal constructor(internal val _value: Double) :
|
||||
fun toString(unit: DurationUnit, decimals: Int = 0): String {
|
||||
require(decimals >= 0) { "decimals must be not negative, but was $decimals" }
|
||||
if (isInfinite()) return _value.toString()
|
||||
return formatToExactDecimals(inUnits(unit), decimals) + unit.shortName()
|
||||
return formatToExactDecimals(toDouble(unit), decimals) + unit.shortName()
|
||||
}
|
||||
|
||||
|
||||
@@ -219,36 +184,42 @@ public inline class Duration internal constructor(internal val _value: Double) :
|
||||
}
|
||||
|
||||
// constructing from number of units
|
||||
// option 2: constructor extension functions
|
||||
// extension functions
|
||||
|
||||
fun Int.toDuration(unit: DurationUnit): Duration = toDouble().toDuration(unit)
|
||||
fun Long.toDuration(unit: DurationUnit): Duration = toDouble().toDuration(unit)
|
||||
fun Double.toDuration(unit: DurationUnit): Duration = Duration(convertDurationUnit(this, unit, storageUnit))
|
||||
|
||||
val Int.nanoseconds get() = Duration(this, DurationUnit.NANOSECONDS)
|
||||
val Long.nanoseconds get() = Duration(this, DurationUnit.NANOSECONDS)
|
||||
val Double.nanoseconds get() = Duration(this, DurationUnit.NANOSECONDS)
|
||||
// constructing from number of units
|
||||
// extension properties
|
||||
|
||||
val Int.microseconds get() = Duration(this, DurationUnit.MICROSECONDS)
|
||||
val Long.microseconds get() = Duration(this, DurationUnit.MICROSECONDS)
|
||||
val Double.microseconds get() = Duration(this, DurationUnit.MICROSECONDS)
|
||||
val Int.nanoseconds get() = toDuration(DurationUnit.NANOSECONDS)
|
||||
val Long.nanoseconds get() = toDuration(DurationUnit.NANOSECONDS)
|
||||
val Double.nanoseconds get() = toDuration(DurationUnit.NANOSECONDS)
|
||||
|
||||
val Int.milliseconds get() = Duration(this, DurationUnit.MILLISECONDS)
|
||||
val Long.milliseconds get() = Duration(this, DurationUnit.MILLISECONDS)
|
||||
val Double.milliseconds get() = Duration(this, DurationUnit.MILLISECONDS)
|
||||
val Int.microseconds get() = toDuration(DurationUnit.MICROSECONDS)
|
||||
val Long.microseconds get() = toDuration(DurationUnit.MICROSECONDS)
|
||||
val Double.microseconds get() = toDuration(DurationUnit.MICROSECONDS)
|
||||
|
||||
val Int.seconds get() = Duration(this, DurationUnit.SECONDS)
|
||||
val Long.seconds get() = Duration(this, DurationUnit.SECONDS)
|
||||
val Double.seconds get() = Duration(this, DurationUnit.SECONDS)
|
||||
val Int.milliseconds get() = toDuration(DurationUnit.MILLISECONDS)
|
||||
val Long.milliseconds get() = toDuration(DurationUnit.MILLISECONDS)
|
||||
val Double.milliseconds get() = toDuration(DurationUnit.MILLISECONDS)
|
||||
|
||||
val Int.minutes get() = Duration(this, DurationUnit.MINUTES)
|
||||
val Long.minutes get() = Duration(this, DurationUnit.MINUTES)
|
||||
val Double.minutes get() = Duration(this, DurationUnit.MINUTES)
|
||||
val Int.seconds get() = toDuration(DurationUnit.SECONDS)
|
||||
val Long.seconds get() = toDuration(DurationUnit.SECONDS)
|
||||
val Double.seconds get() = toDuration(DurationUnit.SECONDS)
|
||||
|
||||
val Int.hours get() = Duration(this, DurationUnit.HOURS)
|
||||
val Long.hours get() = Duration(this, DurationUnit.HOURS)
|
||||
val Double.hours get() = Duration(this, DurationUnit.HOURS)
|
||||
val Int.minutes get() = toDuration(DurationUnit.MINUTES)
|
||||
val Long.minutes get() = toDuration(DurationUnit.MINUTES)
|
||||
val Double.minutes get() = toDuration(DurationUnit.MINUTES)
|
||||
|
||||
val Int.days get() = Duration(this, DurationUnit.DAYS)
|
||||
val Long.days get() = Duration(this, DurationUnit.DAYS)
|
||||
val Double.days get() = Duration(this, DurationUnit.DAYS)
|
||||
val Int.hours get() = toDuration(DurationUnit.HOURS)
|
||||
val Long.hours get() = toDuration(DurationUnit.HOURS)
|
||||
val Double.hours get() = toDuration(DurationUnit.HOURS)
|
||||
|
||||
val Int.days get() = toDuration(DurationUnit.DAYS)
|
||||
val Long.days get() = toDuration(DurationUnit.DAYS)
|
||||
val Double.days get() = toDuration(DurationUnit.DAYS)
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -25,13 +25,13 @@ class DurationTest {
|
||||
val value = Random.nextInt(1_000_000)
|
||||
val unit = units.random()
|
||||
val expected = convertDurationUnit(value.toDouble(), unit, expectStorageUnit)
|
||||
assertEquals(expected, Duration(value, unit)._value)
|
||||
assertEquals(expected, Duration(value.toLong(), unit)._value)
|
||||
assertEquals(expected, Duration(value.toDouble(), unit)._value)
|
||||
assertEquals(expected, value.toDuration(unit)._value)
|
||||
assertEquals(expected, value.toLong().toDuration(unit)._value)
|
||||
assertEquals(expected, value.toDouble().toDuration(unit)._value)
|
||||
}
|
||||
|
||||
todo {
|
||||
assertFails { Duration(Double.NaN, DurationUnit.SECONDS) }
|
||||
assertFails { Double.NaN.toDuration(DurationUnit.SECONDS) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,14 +50,14 @@ class DurationTest {
|
||||
|
||||
for ((value, unit) in data) {
|
||||
repeat(10) {
|
||||
val d1 = Duration(value, unit)
|
||||
val d1 = value.toDuration(unit)
|
||||
val unit2 = units.random()
|
||||
val value2 = convertDurationUnit(value, unit, unit2)
|
||||
val d2 = Duration(value2, unit2)
|
||||
val d2 = value2.toDuration(unit2)
|
||||
assertEquals(d1, d2, "$value $unit in $unit2")
|
||||
assertEquals(d1.hashCode(), d2.hashCode())
|
||||
|
||||
val d3 = Duration(value2 * 2, unit2)
|
||||
val d3 = (value2 * 2).toDuration(unit2)
|
||||
assertNotEquals(d1, d3, "$value $unit in $unit2")
|
||||
}
|
||||
}
|
||||
@@ -70,33 +70,33 @@ class DurationTest {
|
||||
val n2 = Random.nextLong(Long.MAX_VALUE)
|
||||
val n3 = Random.nextDouble()
|
||||
|
||||
assertEquals(Duration(n1, DurationUnit.DAYS), n1.days)
|
||||
assertEquals(Duration(n2, DurationUnit.DAYS), n2.days)
|
||||
assertEquals(Duration(n3, DurationUnit.DAYS), n3.days)
|
||||
assertEquals(n1.toDuration(DurationUnit.DAYS), n1.days)
|
||||
assertEquals(n2.toDuration(DurationUnit.DAYS), n2.days)
|
||||
assertEquals(n3.toDuration(DurationUnit.DAYS), n3.days)
|
||||
|
||||
assertEquals(Duration(n1, DurationUnit.HOURS), n1.hours)
|
||||
assertEquals(Duration(n2, DurationUnit.HOURS), n2.hours)
|
||||
assertEquals(Duration(n3, DurationUnit.HOURS), n3.hours)
|
||||
assertEquals(n1.toDuration(DurationUnit.HOURS), n1.hours)
|
||||
assertEquals(n2.toDuration(DurationUnit.HOURS), n2.hours)
|
||||
assertEquals(n3.toDuration(DurationUnit.HOURS), n3.hours)
|
||||
|
||||
assertEquals(Duration(n1, DurationUnit.MINUTES), n1.minutes)
|
||||
assertEquals(Duration(n2, DurationUnit.MINUTES), n2.minutes)
|
||||
assertEquals(Duration(n3, DurationUnit.MINUTES), n3.minutes)
|
||||
assertEquals(n1.toDuration(DurationUnit.MINUTES), n1.minutes)
|
||||
assertEquals(n2.toDuration(DurationUnit.MINUTES), n2.minutes)
|
||||
assertEquals(n3.toDuration(DurationUnit.MINUTES), n3.minutes)
|
||||
|
||||
assertEquals(Duration(n1, DurationUnit.SECONDS), n1.seconds)
|
||||
assertEquals(Duration(n2, DurationUnit.SECONDS), n2.seconds)
|
||||
assertEquals(Duration(n3, DurationUnit.SECONDS), n3.seconds)
|
||||
assertEquals(n1.toDuration(DurationUnit.SECONDS), n1.seconds)
|
||||
assertEquals(n2.toDuration(DurationUnit.SECONDS), n2.seconds)
|
||||
assertEquals(n3.toDuration(DurationUnit.SECONDS), n3.seconds)
|
||||
|
||||
assertEquals(Duration(n1, DurationUnit.MILLISECONDS), n1.milliseconds)
|
||||
assertEquals(Duration(n2, DurationUnit.MILLISECONDS), n2.milliseconds)
|
||||
assertEquals(Duration(n3, DurationUnit.MILLISECONDS), n3.milliseconds)
|
||||
assertEquals(n1.toDuration(DurationUnit.MILLISECONDS), n1.milliseconds)
|
||||
assertEquals(n2.toDuration(DurationUnit.MILLISECONDS), n2.milliseconds)
|
||||
assertEquals(n3.toDuration(DurationUnit.MILLISECONDS), n3.milliseconds)
|
||||
|
||||
assertEquals(Duration(n1, DurationUnit.MICROSECONDS), n1.microseconds)
|
||||
assertEquals(Duration(n2, DurationUnit.MICROSECONDS), n2.microseconds)
|
||||
assertEquals(Duration(n3, DurationUnit.MICROSECONDS), n3.microseconds)
|
||||
assertEquals(n1.toDuration(DurationUnit.MICROSECONDS), n1.microseconds)
|
||||
assertEquals(n2.toDuration(DurationUnit.MICROSECONDS), n2.microseconds)
|
||||
assertEquals(n3.toDuration(DurationUnit.MICROSECONDS), n3.microseconds)
|
||||
|
||||
assertEquals(Duration(n1, DurationUnit.NANOSECONDS), n1.nanoseconds)
|
||||
assertEquals(Duration(n2, DurationUnit.NANOSECONDS), n2.nanoseconds)
|
||||
assertEquals(Duration(n3, DurationUnit.NANOSECONDS), n3.nanoseconds)
|
||||
assertEquals(n1.toDuration(DurationUnit.NANOSECONDS), n1.nanoseconds)
|
||||
assertEquals(n2.toDuration(DurationUnit.NANOSECONDS), n2.nanoseconds)
|
||||
assertEquals(n3.toDuration(DurationUnit.NANOSECONDS), n3.nanoseconds)
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -118,7 +118,7 @@ class DurationTest {
|
||||
val unit = units.random()
|
||||
val unit2 = units.random()
|
||||
|
||||
assertAlmostEquals(convertDurationUnit(value.toDouble(), unit, unit2), Duration(value, unit).inUnits(unit2))
|
||||
assertAlmostEquals(convertDurationUnit(value.toDouble(), unit, unit2), value.toDuration(unit).toDouble(unit2))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -166,12 +166,6 @@ class DurationTest {
|
||||
assertTrue((-Duration.INFINITE).isInfinite())
|
||||
assertTrue(Double.POSITIVE_INFINITY.nanoseconds.isInfinite())
|
||||
|
||||
assertTrue(Duration.MAX_VALUE.isFinite())
|
||||
assertTrue(Duration.MIN_VALUE.isFinite())
|
||||
|
||||
assertFalse((Duration.MAX_VALUE * 2).isFinite())
|
||||
assertFalse((Duration.MIN_VALUE * 2).isFinite())
|
||||
|
||||
// seconds converted to nanoseconds overflow to infinite
|
||||
assertTrue(Double.MAX_VALUE.seconds.isInfinite())
|
||||
assertTrue((-Double.MAX_VALUE).seconds.isInfinite())
|
||||
@@ -184,7 +178,7 @@ class DurationTest {
|
||||
val value = Random.nextLong()
|
||||
val unit = units.random()
|
||||
|
||||
assertEquals(Duration(-value, unit), -Duration(value, unit))
|
||||
assertEquals((-value).toDuration(unit), -value.toDuration(unit))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -298,8 +292,8 @@ class DurationTest {
|
||||
d = (d - 516.nanoseconds) / 17
|
||||
test(DurationUnit.NANOSECONDS, "0ns", "0.0ns", "0.02ns", "0.020ns", "0.0202ns")
|
||||
|
||||
d = Duration.MAX_VALUE
|
||||
testOnJvm {
|
||||
d = Double.MAX_VALUE.nanoseconds
|
||||
// are such long representations ok?
|
||||
test(DurationUnit.DAYS, "20806633505350875${"0".repeat(278)}d")
|
||||
test(DurationUnit.NANOSECONDS, "17976931348623157${"0".repeat(292)}ns")
|
||||
@@ -375,7 +369,7 @@ class DurationTest {
|
||||
|
||||
test(universeAge, "5.04e12d")
|
||||
test(planckTime, "5.4e-44s", "5.40e-44s")
|
||||
test(Duration.MAX_VALUE, "2.08e294d")
|
||||
test(Double.MAX_VALUE.nanoseconds, "2.08e294d")
|
||||
test(Duration.INFINITE, "Infinity")
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user