Store Duration value as a multi-range Long

Now precision loss happens at bigger durations.

This changes the binary API due different underlying type of Duration.
This commit is contained in:
Ilya Gorbunov
2021-02-17 20:15:18 +03:00
parent 3f4fa7eb98
commit fa7460ba48
9 changed files with 596 additions and 182 deletions
@@ -1,5 +1,5 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
@@ -49,3 +49,33 @@ internal actual fun convertDurationUnit(value: Double, sourceUnit: DurationUnit,
else -> value
}
}
@SinceKotlin("1.5")
@ExperimentalTime
internal actual fun convertDurationUnitOverflow(value: Long, sourceUnit: DurationUnit, targetUnit: DurationUnit): Long {
val sourceCompareTarget = sourceUnit.scale.compareTo(targetUnit.scale)
return when {
sourceCompareTarget > 0 -> value * (sourceUnit.scale / targetUnit.scale).toLong()
sourceCompareTarget < 0 -> value / (targetUnit.scale / sourceUnit.scale).toLong()
else -> value
}
}
@SinceKotlin("1.5")
@ExperimentalTime
internal actual fun convertDurationUnit(value: Long, sourceUnit: DurationUnit, targetUnit: DurationUnit): Long {
val sourceCompareTarget = sourceUnit.scale.compareTo(targetUnit.scale)
return when {
sourceCompareTarget > 0 -> {
val scale = (sourceUnit.scale / targetUnit.scale).toLong()
val result = value * scale
when {
result / scale == value -> result
value > 0 -> Long.MAX_VALUE
else -> Long.MIN_VALUE
}
}
sourceCompareTarget < 0 -> value / (targetUnit.scale / sourceUnit.scale).toLong()
else -> value
}
}
@@ -44,9 +44,14 @@ class DurationConversionTest {
@Test
fun javaToKotlinRounding() {
val jtDuration = JTDuration.ofDays(105).plusNanos(1)
val duration = jtDuration.toKotlinDuration()
assertEquals(Duration.days(105), duration)
val jtDuration1 = JTDuration.ofDays(365 * 150)
val jtDuration2 = jtDuration1.plusNanos(1)
assertNotEquals(jtDuration1, jtDuration2)
val duration1 = jtDuration1.toKotlinDuration()
val duration2 = jtDuration1.toKotlinDuration()
assertEquals(duration1, duration2)
assertEquals(Duration.days(365 * 150), duration2)
}
@Test
@@ -1,5 +1,5 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
@@ -49,3 +49,34 @@ internal actual fun convertDurationUnit(value: Double, sourceUnit: DurationUnit,
}
}
@SinceKotlin("1.5")
@ExperimentalTime
internal actual fun convertDurationUnitOverflow(value: Long, sourceUnit: DurationUnit, targetUnit: DurationUnit): Long {
val sourceCompareTarget = sourceUnit.scale.compareTo(targetUnit.scale)
return when {
sourceCompareTarget > 0 -> value * (sourceUnit.scale / targetUnit.scale).toLong()
sourceCompareTarget < 0 -> value / (targetUnit.scale / sourceUnit.scale).toLong()
else -> value
}
}
@SinceKotlin("1.5")
@ExperimentalTime
internal actual fun convertDurationUnit(value: Long, sourceUnit: DurationUnit, targetUnit: DurationUnit): Long {
val sourceCompareTarget = sourceUnit.scale.compareTo(targetUnit.scale)
return when {
sourceCompareTarget > 0 -> {
val scale = (sourceUnit.scale / targetUnit.scale).toLong()
val result = value * scale
when {
result / scale == value -> result
value > 0 -> Long.MAX_VALUE
else -> Long.MIN_VALUE
}
}
sourceCompareTarget < 0 -> value / (targetUnit.scale / sourceUnit.scale).toLong()
else -> value
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
@@ -21,4 +21,16 @@ internal actual fun convertDurationUnit(value: Double, sourceUnit: DurationUnit,
val otherInThis = sourceUnit.convert(1, targetUnit)
return value / otherInThis
}
}
@SinceKotlin("1.5")
@ExperimentalTime
internal actual fun convertDurationUnitOverflow(value: Long, sourceUnit: DurationUnit, targetUnit: DurationUnit): Long {
return targetUnit.convert(value, sourceUnit)
}
@SinceKotlin("1.5")
@ExperimentalTime
internal actual fun convertDurationUnit(value: Long, sourceUnit: DurationUnit, targetUnit: DurationUnit): Long {
return targetUnit.convert(value, sourceUnit)
}
+258 -41
View File
@@ -8,9 +8,20 @@ package kotlin.time
import kotlin.contracts.*
import kotlin.jvm.JvmInline
import kotlin.math.abs
import kotlin.math.roundToInt
import kotlin.math.sign
@OptIn(ExperimentalTime::class)
private inline val storageUnit get() = DurationUnit.NANOSECONDS
private const val MAX_LONG_63 = Long.MAX_VALUE / 2
private const val MIN_LONG_63 = Long.MIN_VALUE / 2
private const val NANOS_IN_MILLIS = 1_000_000
private const val MAX_MILLIS_IN_NANOS = MAX_LONG_63 / NANOS_IN_MILLIS
private const val MIN_MILLIS_IN_NANOS = MIN_LONG_63 / NANOS_IN_MILLIS
private fun nanosToMillis(value: Long): Long = value / NANOS_IN_MILLIS
private fun millisToNanos(value: Long): Long = value * NANOS_IN_MILLIS
private fun storeAsMillis(value: Long): Long = (value shl 1) + 1
private fun storeAsNanos(value: Long): Long = value shl 1
private fun storeAs(value: Long, unitValue: Long): Long = (value shl 1) + (unitValue and 1)
/**
* Represents the amount of time one instant of time is away from another instant.
@@ -18,7 +29,10 @@ private inline val storageUnit get() = DurationUnit.NANOSECONDS
* 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] available on [Int], [Long], and [Double] numeric types,
* The type can store duration values up to ±146 years with nanosecond precision,
* and up to ±146 million years with millisecond precision.
*
* To construct a duration, use either the extension function [toDuration] available on [Int], [Long], and [Double] numeric types,
* or the `Duration` companion object functions [Duration.hours], [Duration.minutes], [Duration.seconds], and so on,
* taking [Int], [Long], or [Double] numbers as parameters.
*
@@ -29,17 +43,23 @@ private inline val storageUnit get() = DurationUnit.NANOSECONDS
@SinceKotlin("1.3")
@ExperimentalTime
@JvmInline
public value class Duration internal constructor(internal val value: Double) : Comparable<Duration> {
public value class Duration internal constructor(internal val rawValue: Long) : Comparable<Duration> {
private fun isInNanos() = rawValue and 1L == 0L
private fun isInMillis() = rawValue and 1L == 1L
private val value: Long get() = rawValue shr 1
private val storageUnit get() = if (isInNanos()) DurationUnit.NANOSECONDS else DurationUnit.MILLISECONDS
init {
require(!value.isNaN()) { "Duration value cannot be NaN." }
// TODO: assert invariants
}
companion object {
/** The duration equal to exactly 0 seconds. */
public val ZERO: Duration = Duration(0.0)
public val ZERO: Duration = Duration(0L)
/** The duration whose value is positive infinity. It is useful for representing timeouts that should never expire. */
public val INFINITE: Duration = Duration(Double.POSITIVE_INFINITY)
public val INFINITE: Duration = Duration(storeAsMillis(MAX_LONG_63))
/** Converts the given time duration [value] expressed in the specified [sourceUnit] into the specified [targetUnit]. */
public fun convert(value: Double, sourceUnit: DurationUnit, targetUnit: DurationUnit): Double =
@@ -162,69 +182,218 @@ public value class Duration internal constructor(internal val value: Double) : C
// arithmetic operators
/** Returns the negative of this value. */
public operator fun unaryMinus(): Duration = Duration((-value).normalizeZero())
public operator fun unaryMinus(): Duration {
val value = value
return when {
rawValue == INFINITE.rawValue -> // negate positive infinite to negative infinite
Duration(storeAsMillis(MIN_LONG_63))
value != MIN_LONG_63 ->
Duration(storeAs(-value, rawValue))
isInNanos() -> // negating MIN_VALUE in nanos overflows to millisecond units
Duration(storeAsMillis(-nanosToMillis(value)))
else -> // negating negative infinity overflows to positive infinity
INFINITE
}
}
/**
* Returns a duration whose value is the sum of this and [other] duration values.
*
* @throws IllegalArgumentException if the operation results in a `NaN` value.
* @throws IllegalArgumentException if the operation results in an undefined value for the given arguments,
* e.g. when adding infinite durations of different sign.
*/
public operator fun plus(other: Duration): Duration = Duration(value + other.value)
public operator fun plus(other: Duration): Duration {
when {
this.isInfinite() -> {
if (other.isFinite() || (this.rawValue xor other.rawValue >= 0))
return this
else
throw IllegalArgumentException("Sum of infinite durations of different signs is undefined.")
}
other.isInfinite() -> return other
}
return if (this.isInNanos() == other.isInNanos()) {
when (val newValue = this.value + other.value) { // never overflows long, but can overflow long63
in MIN_LONG_63..MAX_LONG_63 -> {
if (isInMillis() && newValue in MIN_MILLIS_IN_NANOS..MAX_MILLIS_IN_NANOS)
Duration(storeAsNanos(millisToNanos(newValue)))
else
Duration(storeAs(newValue, this.rawValue))
}
else -> {
val millisValue = if (isInNanos()) nanosToMillis(newValue) else newValue.coerceIn(MIN_LONG_63, MAX_LONG_63)
Duration(storeAsMillis(millisValue))
}
}
} else {
val a: Long
val b: Long
if (this.isInMillis()) {
a = this.value
b = other.value
} else {
a = other.value
b = this.value
}
val bMillis = nanosToMillis(b)
val resultMillis = a + bMillis
return if (resultMillis in MIN_MILLIS_IN_NANOS..MAX_MILLIS_IN_NANOS) {
val bRemainder = b - millisToNanos(bMillis)
Duration(storeAsNanos(millisToNanos(resultMillis) + bRemainder)) // can it overflow nanos?
} else {
Duration(storeAsMillis(resultMillis.coerceIn(MIN_LONG_63, MAX_LONG_63)))
}
}
}
/**
* Returns a duration whose value is the difference between this and [other] duration values.
*
* @throws IllegalArgumentException if the operation results in a `NaN` value.
* @throws IllegalArgumentException if the operation results in an undefined value for the given arguments,
* e.g. when subtracting infinite durations of the same sign.
*/
public operator fun minus(other: Duration): Duration = Duration(value - other.value)
// TODO: negation may overflow
public operator fun minus(other: Duration): Duration = this + (-other)
/**
* Returns a duration whose value is this duration value multiplied by the given [scale] number.
*
* @throws IllegalArgumentException if the operation results in a `NaN` value.
* @throws IllegalArgumentException if the operation results in an undefined value for the given arguments,
* e.g. when multiplying an infinite duration by zero.
*/
public operator fun times(scale: Int): Duration = Duration((value * scale).normalizeZero())
public operator fun times(scale: Int): Duration {
if (isInfinite()) {
return when {
scale == 0 -> throw IllegalArgumentException("Multiplying infinite duration by zero is undefined.")
scale > 0 -> this
else -> -this
}
}
if (scale == 0) return ZERO
val result = value * scale
if (value >= Int.MIN_VALUE && value <= Int.MAX_VALUE) {
return Duration(storeAs(result, rawValue))
}
if (result / scale != value && isInNanos()) { // Long overflow
val rawMillis = nanosToMillis(value)
val resultMillis = rawMillis * scale
if (resultMillis / scale != rawMillis) return Duration.INFINITE
return when {
resultMillis in MIN_LONG_63..MAX_LONG_63 -> Duration(storeAsMillis(resultMillis))
resultMillis > 0 -> Duration.INFINITE
else -> -Duration.INFINITE
}
}
return when {
result in MIN_LONG_63..MAX_LONG_63 -> {
Duration(storeAs(result, rawValue))
}
isInNanos() -> {
Duration(storeAsMillis(nanosToMillis(result)))
}
result > 0 -> Duration.INFINITE
else -> -Duration.INFINITE
}
}
/**
* Returns a duration whose value is this duration value multiplied by the given [scale] number.
*
* @throws IllegalArgumentException if the operation results in a `NaN` value.
* @throws IllegalArgumentException if the operation results in an undefined value for the given arguments,
* e.g. when multiplying an infinite duration by zero.
*/
public operator fun times(scale: Double): Duration = Duration((value * scale).normalizeZero())
public operator fun times(scale: Double): Duration {
val intScale = scale.roundToInt()
if (intScale.toDouble() == scale) {
return times(intScale)
}
val unit = storageUnit
val result = toDouble(unit) * scale
return result.toDuration(unit)
}
/**
* Returns a duration whose value is this duration value divided by the given [scale] number.
*
* @throws IllegalArgumentException if the operation results in a `NaN` value.
* @throws IllegalArgumentException if the operation results in an undefined value for the given arguments,
* e.g. when dividing zero duration by zero.
*/
public operator fun div(scale: Int): Duration = Duration((value / scale).normalizeZero())
public operator fun div(scale: Int): Duration {
if (scale == 0) {
return when {
isPositive() -> Duration.INFINITE
isNegative() -> -Duration.INFINITE
else -> throw IllegalArgumentException("Dividing zero duration by zero is undefined")
}
}
if (isInNanos()) {
return Duration(storeAsNanos(value / scale))
} else {
if (isInfinite())
return this * scale.sign
val result = value / scale
if (result in MIN_MILLIS_IN_NANOS..MAX_MILLIS_IN_NANOS) {
// TODO: more precise
return Duration(storeAsNanos(millisToNanos(result)))
}
return Duration(storeAsMillis(result))
}
}
/**
* Returns a duration whose value is this duration value divided by the given [scale] number.
*
* @throws IllegalArgumentException if the operation results in a `NaN` value.
* @throws IllegalArgumentException if the operation results in an undefined value for the given arguments,
* e.g. when dividing an infinite duration by infinity or zero duration by zero.
*/
public operator fun div(scale: Double): Duration = Duration((value / scale).normalizeZero())
public operator fun div(scale: Double): Duration {
if (scale != 0.0) {
val intScale = scale.roundToInt()
if (intScale.toDouble() == scale) {
return div(intScale)
}
}
val unit = storageUnit
val result = toDouble(unit) / scale
return result.toDuration(unit)
}
/** Returns a number that is the ratio of this and [other] duration values. */
public operator fun div(other: Duration): Double = this.value / other.value
public operator fun div(other: Duration): Double {
val coarserUnit = maxOf(this.storageUnit, other.storageUnit)
return this.toDouble(coarserUnit) / other.toDouble(coarserUnit)
}
/** Returns true, if the duration value is less than zero. */
public fun isNegative(): Boolean = value < 0
public fun isNegative(): Boolean = rawValue < 0
/** Returns true, if the duration value is greater than zero. */
public fun isPositive(): Boolean = value > 0
public fun isPositive(): Boolean = rawValue > 0
/** Returns true, if the duration value is infinite. */
public fun isInfinite(): Boolean = value.isInfinite()
public fun isInfinite(): Boolean = isInMillis() && value.let { it == MAX_LONG_63 || it == MIN_LONG_63 }
/** Returns true, if the duration value is finite. */
public fun isFinite(): Boolean = value.isFinite()
public fun isFinite(): Boolean = !isInfinite()
/** Returns the absolute value of this value. The returned value is always non-negative. */
public val absoluteValue: Duration get() = if (isNegative()) -this else this
override fun compareTo(other: Duration): Int = this.value.compareTo(other.value)
override fun compareTo(other: Duration): Int {
val compareBits = this.rawValue xor other.rawValue
if (compareBits < 0 || compareBits and 1L == 0L) // different signs or same sign, same scale
return this.rawValue.compareTo(other.rawValue)
// same sign, different scales
val r = (this.rawValue and 1L).toInt() - (other.rawValue and 1L).toInt()
return if (this.rawValue < 0) -r else r
}
// splitting to components
@@ -304,21 +473,37 @@ public value class Duration internal constructor(internal val value: Double) : C
// conversion to units
/** Returns the value of this duration expressed as a [Double] number of the specified [unit]. */
public fun toDouble(unit: DurationUnit): Double = convertDurationUnit(value, storageUnit, unit)
public fun toDouble(unit: DurationUnit): Double {
return if (isInfinite()) {
if (isNegative()) Double.NEGATIVE_INFINITY else Double.POSITIVE_INFINITY
} else {
// TODO: whether it's ok to convert to Double before scaling
convertDurationUnit(value.toDouble(), storageUnit, unit)
}
}
/**
* Returns the value of this duration expressed as a [Long] number of the specified [unit].
*
* If the value doesn't fit in the range of [Long] type, it is coerced into that range, see the conversion [Double.toLong] for details.
*/
public fun toLong(unit: DurationUnit): Long = toDouble(unit).toLong()
public fun toLong(unit: DurationUnit): Long {
return if (isInfinite()) {
if (isNegative()) Long.MIN_VALUE else Long.MAX_VALUE
} else {
convertDurationUnit(value, storageUnit, unit)
}
}
/**
* Returns the value of this duration expressed as an [Int] number of the specified [unit].
*
* If the value doesn't fit in the range of [Int] type, it is coerced into that range, see the conversion [Double.toInt] for details.
*/
public fun toInt(unit: DurationUnit): Int = toDouble(unit).toInt()
public fun toInt(unit: DurationUnit): Int =
toLong(unit).coerceIn(Int.MIN_VALUE.toLong(), Int.MAX_VALUE.toLong()).toInt()
// TODO: inWholeUnits conversions, deprecate inUnits
/** The value of this duration expressed as a [Double] number of days. */
public val inDays: Double get() = toDouble(DurationUnit.DAYS)
@@ -350,7 +535,16 @@ public value class Duration internal constructor(internal val value: Double) : C
*
* The range of durations that can be expressed as a `Long` number of nanoseconds is approximately ±292 years.
*/
public fun toLongNanoseconds(): Long = toLong(DurationUnit.NANOSECONDS)
// TODO: Deprecate in favor inWholeNanoseconds
public fun toLongNanoseconds(): Long {
val value = value
return when {
isInNanos() -> value
value > Long.MAX_VALUE / NANOS_IN_MILLIS -> Long.MAX_VALUE
value < Long.MIN_VALUE / NANOS_IN_MILLIS -> Long.MIN_VALUE
else -> millisToNanos(value)
}
}
/**
* Returns the value of this duration expressed as a [Long] number of milliseconds.
@@ -359,7 +553,10 @@ public value class Duration internal constructor(internal val value: Double) : C
*
* The range of durations that can be expressed as a `Long` number of milliseconds is approximately ±292 million years.
*/
public fun toLongMilliseconds(): Long = toLong(DurationUnit.MILLISECONDS)
// TODO: Deprecate in favor inWholeMilliseconds
public fun toLongMilliseconds(): Long {
return if (isInMillis() && isFinite()) value else toLong(DurationUnit.MILLISECONDS)
}
/**
* Returns a string representation of this duration value expressed in the unit which yields the most compact and readable number value.
@@ -375,8 +572,8 @@ public value class Duration internal constructor(internal val value: Double) : C
* @sample samples.time.Durations.toStringDefault
*/
override fun toString(): String = when {
isInfinite() -> value.toString()
value == 0.0 -> "0s"
isInfinite() -> if (isNegative()) "-Infinity" else "Infinity"
rawValue == 0L -> "0s"
else -> {
val absNs = absoluteValue.inNanoseconds
var scientific = false
@@ -424,8 +621,8 @@ public value class Duration internal constructor(internal val value: Double) : C
*/
public fun toString(unit: DurationUnit, decimals: Int = 0): String {
require(decimals >= 0) { "decimals must be not negative, but was $decimals" }
if (isInfinite()) return value.toString()
val number = toDouble(unit)
if (number.isInfinite()) return number.toString()
return when {
abs(number) < 1e14 -> formatToExactDecimals(number, decimals.coerceAtMost(12))
else -> formatScientific(number)
@@ -485,12 +682,28 @@ public value class Duration internal constructor(internal val value: Double) : C
/** Returns a [Duration] equal to this [Int] number of the specified [unit]. */
@SinceKotlin("1.3")
@ExperimentalTime
public fun Int.toDuration(unit: DurationUnit): Duration = toDouble().toDuration(unit)
public fun Int.toDuration(unit: DurationUnit): Duration {
return if (unit <= DurationUnit.SECONDS) {
Duration(storeAsNanos(convertDurationUnitOverflow(this.toLong(), unit, DurationUnit.NANOSECONDS)))
} else
toLong().toDuration(unit)
}
/** Returns a [Duration] equal to this [Long] number of the specified [unit]. */
@SinceKotlin("1.3")
@ExperimentalTime
public fun Long.toDuration(unit: DurationUnit): Duration = toDouble().toDuration(unit)
public fun Long.toDuration(unit: DurationUnit): Duration {
val maxInUnit = convertDurationUnitOverflow(MAX_LONG_63, DurationUnit.NANOSECONDS, unit)
if (this in -maxInUnit..maxInUnit) {
return Duration(storeAsNanos(convertDurationUnitOverflow(this, unit, DurationUnit.NANOSECONDS)))
} else {
val max2InUnit = convertDurationUnitOverflow(MAX_LONG_63, DurationUnit.MILLISECONDS, unit)
if (unit < DurationUnit.MILLISECONDS || this in -max2InUnit..max2InUnit) {
return Duration(storeAsMillis(convertDurationUnitOverflow(this, unit, DurationUnit.MILLISECONDS)))
}
return if (this < 0) -Duration.INFINITE else Duration.INFINITE
}
}
/**
* Returns a [Duration] equal to this [Double] number of the specified [unit].
@@ -499,7 +712,15 @@ public fun Long.toDuration(unit: DurationUnit): Duration = toDouble().toDuration
*/
@SinceKotlin("1.3")
@ExperimentalTime
public fun Double.toDuration(unit: DurationUnit): Duration = Duration(convertDurationUnit(this, unit, storageUnit).normalizeZero())
public fun Double.toDuration(unit: DurationUnit): Duration {
val valueInNs = convertDurationUnit(this, unit, DurationUnit.NANOSECONDS)
require(!valueInNs.isNaN()) { "Duration value cannot be NaN." }
return if (valueInNs > MAX_LONG_63 || valueInNs < MIN_LONG_63) {
Duration(storeAsMillis((valueInNs / NANOS_IN_MILLIS).toLong().coerceIn(MIN_LONG_63, MAX_LONG_63)))
} else {
Duration(storeAsNanos(valueInNs.toLong()))
}
}
// constructing from number of units
// extension properties
@@ -675,10 +896,6 @@ public inline operator fun Int.times(duration: Duration): Duration = duration *
@kotlin.internal.InlineOnly
public inline operator fun Double.times(duration: Duration): Duration = duration * this
@kotlin.internal.InlineOnly
private inline fun Double.normalizeZero(): Double = this + 0.0
internal expect fun formatToExactDecimals(value: Double, decimals: Int): String
internal expect fun formatUpToDecimals(value: Double, decimals: Int): String
internal expect fun formatScientific(value: Double): String
@@ -1,5 +1,5 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
@@ -52,6 +52,16 @@ public expect enum class DurationUnit {
@ExperimentalTime
internal expect fun convertDurationUnit(value: Double, sourceUnit: DurationUnit, targetUnit: DurationUnit): Double
// overflown result is unspecified
@SinceKotlin("1.5")
@ExperimentalTime
internal expect fun convertDurationUnitOverflow(value: Long, sourceUnit: DurationUnit, targetUnit: DurationUnit): Long
// overflown result is coerced in the Long range boundaries
@SinceKotlin("1.5")
@ExperimentalTime
internal expect fun convertDurationUnit(value: Long, sourceUnit: DurationUnit, targetUnit: DurationUnit): Long
@SinceKotlin("1.3")
@ExperimentalTime
+134 -33
View File
@@ -4,6 +4,7 @@
*/
@file:OptIn(ExperimentalTime::class)
@file:Suppress("INVISIBLE_MEMBER")
package test.time
import test.numbers.assertAlmostEquals
@@ -12,26 +13,40 @@ import kotlin.test.*
import kotlin.time.*
import kotlin.random.*
@SharedImmutable
private val expectStorageUnit = DurationUnit.NANOSECONDS
@SharedImmutable
private val units = DurationUnit.values()
class DurationTest {
// construction white-box testing
@Test
fun construction() {
@Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER")
repeat(100) {
val value = Random.nextInt(1_000_000)
val unit = units.random()
val expected = convertDurationUnit(value.toDouble(), unit, expectStorageUnit)
assertEquals(expected, value.toDuration(unit).value)
assertEquals(expected, value.toLong().toDuration(unit).value)
assertEquals(expected, value.toDouble().toDuration(unit).value)
// nanosecond precision
val testValues = listOf(0L, 1L, Long.MAX_VALUE / 2) + List(100) { Random.nextLong(0, Long.MAX_VALUE / 2) }
for (value in testValues) {
assertEquals(value, value.toDuration(DurationUnit.NANOSECONDS).toLongNanoseconds())
assertEquals(-value, -value.toDuration(DurationUnit.NANOSECONDS).toLongNanoseconds())
}
// expressible as long nanoseconds but stored as milliseconds
for (delta in testValues) {
val value = 1L.shl(62) + delta
val expected = value - (value % 1_000_000)
assertEquals(expected, value.toDuration(DurationUnit.NANOSECONDS).toLongNanoseconds())
assertEquals(-expected, -value.toDuration(DurationUnit.NANOSECONDS).toLongNanoseconds())
}
// any int value of small units can always be represented in nanoseconds
for (unit in units.filter { it <= DurationUnit.SECONDS }) {
val scale = convertDurationUnitOverflow(1L, unit, DurationUnit.NANOSECONDS)
repeat(100) {
val value = Random.nextInt()
assertEquals(value * scale, value.toDuration(unit).toLongNanoseconds())
}
}
assertEquals(Long.MAX_VALUE / 1000, Long.MAX_VALUE.toDuration(DurationUnit.MICROSECONDS).toLongMilliseconds())
assertEquals(Long.MAX_VALUE / 1000 * 1000, Long.MAX_VALUE.toDuration(DurationUnit.MICROSECONDS).toLong(DurationUnit.MICROSECONDS))
assertEquals(Duration.INFINITE, (Long.MAX_VALUE / 2).toDuration(DurationUnit.MILLISECONDS))
assertEquals(-Duration.INFINITE, (Long.MIN_VALUE / 2).toDuration(DurationUnit.MILLISECONDS))
assertFailsWith<IllegalArgumentException> { Double.NaN.toDuration(DurationUnit.SECONDS) }
}
@@ -64,6 +79,26 @@ class DurationTest {
}
}
@Test
fun comparison() {
run {
val d1 = Duration.nanoseconds(Long.MAX_VALUE / 2 + 1)
val d2 = Duration.nanoseconds(Long.MAX_VALUE / 2)
assertTrue(d1 >= d2, "same sign, different ranges")
// TODO: Address this contradiction
// assertTrue(d1.toLongNanoseconds() >= d2.toLongNanoseconds())
val d3 = Duration.nanoseconds(Long.MAX_VALUE / 2 - 1)
assertTrue(d2 > d3, "same sign, same range nanos")
val d4 = Duration.nanoseconds(Long.MAX_VALUE)
assertTrue(d4 > d1, "same sign, same range millis")
assertTrue(d2 > -d1, "different signs, different ranges")
assertTrue(d1 > -d4, "different signs, same ranges")
}
}
@Test
fun conversionFromNumber() {
@@ -127,6 +162,15 @@ class DurationTest {
assertAlmostEquals(Duration.convert(value.toDouble(), unit, unit2), value.toDuration(unit).toDouble(unit2))
}
for (unit in units) {
assertEquals(Long.MAX_VALUE, Duration.INFINITE.toLong(unit))
assertEquals(Int.MAX_VALUE, Duration.INFINITE.toInt(unit))
assertEquals(Double.POSITIVE_INFINITY, Duration.INFINITE.toDouble(unit))
assertEquals(Long.MIN_VALUE, (-Duration.INFINITE).toLong(unit))
assertEquals(Int.MIN_VALUE, (-Duration.INFINITE).toInt(unit))
assertEquals(Double.NEGATIVE_INFINITY, (-Duration.INFINITE).toDouble(unit))
}
}
@Test
@@ -248,6 +292,14 @@ class DurationTest {
assertEquals(Duration.days(0.5), Duration.hours(6) + Duration.minutes(360))
assertEquals(Duration.seconds(0.5), Duration.milliseconds(200) + Duration.microseconds(300_000))
for (value in listOf(Duration.ZERO, Duration.nanoseconds(1), Duration.days(500 * 365))) {
for (inf in listOf(Duration.INFINITE, -Duration.INFINITE)) {
for (result in listOf(inf + inf, inf + value, inf + (-value), value + inf, (-value) + inf)) {
assertEquals(inf, result)
}
}
}
assertFailsWith<IllegalArgumentException> { Duration.INFINITE + (-Duration.INFINITE) }
}
@@ -255,6 +307,38 @@ class DurationTest {
fun subtraction() {
assertEquals(Duration.hours(10), Duration.days(0.5) - Duration.minutes(120))
assertEquals(Duration.milliseconds(850), Duration.seconds(1) - Duration.milliseconds(150))
assertEquals(Duration.milliseconds(1150), Duration.seconds(1) - Duration.milliseconds(-150))
assertEquals(Duration.milliseconds(1), Duration.microseconds(Long.MAX_VALUE) - Duration.microseconds(Long.MAX_VALUE - 1_000))
run {
val offset = 2_000_000L
val value = Long.MAX_VALUE / 2 + offset
val base = Duration.nanoseconds(value)
val baseNs = base.toLongMilliseconds() * 1_000_000
assertEquals(baseNs, base.toLongNanoseconds()) // base stored as millis
val smallDeltas = listOf(1L, 2L, 1000L, offset / 2 - 1) + List(10) { Random.nextLong(offset / 2) }
for (smallDeltaNs in smallDeltas) {
assertEquals(base, base - Duration.nanoseconds(smallDeltaNs), "delta: $smallDeltaNs")
}
val deltas = listOf(offset + 1L, offset + 1500L) +
List(10) { Random.nextLong(offset + 1500, offset + 10000) } +
List(100) { Random.nextLong(offset + 1500, Long.MAX_VALUE / 2) }
for (deltaNs in deltas) {
val delta = Duration.nanoseconds(deltaNs)
assertEquals(deltaNs, delta.toLongNanoseconds())
assertEquals(baseNs - deltaNs, (base - delta).toLongNanoseconds(), "base: $baseNs, delta: $deltaNs")
}
}
for (value in listOf(Duration.ZERO, Duration.nanoseconds(1), Duration.days(500 * 365))) {
for (inf in listOf(Duration.INFINITE, -Duration.INFINITE)) {
for (result in listOf(inf - (-inf), inf - value, inf - (-value), value - (-inf), (-value) - (-inf))) {
assertEquals(inf, result)
}
}
}
assertFailsWith<IllegalArgumentException> { Duration.INFINITE - Duration.INFINITE }
}
@@ -272,8 +356,13 @@ class DurationTest {
assertEquals(Duration.ZERO, 0 * Duration.hours(1))
assertEquals(Duration.ZERO, Duration.seconds(1) * 0.0)
assertEquals(Duration.INFINITE, Duration.INFINITE * Double.POSITIVE_INFINITY)
assertEquals(Duration.INFINITE, Duration.INFINITE * Double.MIN_VALUE)
assertEquals(-Duration.INFINITE, Duration.INFINITE * Double.NEGATIVE_INFINITY)
assertEquals(-Duration.INFINITE, Duration.INFINITE * -1)
assertFailsWith<IllegalArgumentException> { Duration.INFINITE * 0 }
assertFailsWith<IllegalArgumentException> { 0 * Duration.INFINITE }
assertFailsWith<IllegalArgumentException> { 0.0 * Duration.INFINITE }
}
@Test
@@ -282,10 +371,18 @@ class DurationTest {
assertEquals(Duration.minutes(60), Duration.days(1) / 24.0)
assertEquals(Duration.seconds(20), Duration.minutes(2) / 6)
assertEquals(Duration.INFINITE, Duration.seconds(1) / 0.0)
assertEquals(Duration.INFINITE, Duration.seconds(1) / 0)
assertEquals(-Duration.INFINITE, -Duration.seconds(1) / 0.0)
assertEquals(Duration.INFINITE, -Duration.seconds(1) / (-0.0))
assertEquals(Duration.INFINITE, Duration.INFINITE / Int.MAX_VALUE)
assertEquals(Duration.INFINITE, -Duration.INFINITE / Int.MIN_VALUE)
assertEquals(-Duration.INFINITE, Duration.INFINITE / -1)
assertEquals(Duration.INFINITE, Duration.INFINITE / Double.MAX_VALUE)
assertFailsWith<IllegalArgumentException> { Duration.INFINITE / Double.POSITIVE_INFINITY }
assertFailsWith<IllegalArgumentException> { Duration.ZERO / 0 }
assertFailsWith<IllegalArgumentException> { Duration.ZERO / 0.0 }
}
@Test
@@ -293,6 +390,7 @@ class DurationTest {
assertEquals(24.0, Duration.days(1) / Duration.hours(1))
assertEquals(0.1, Duration.minutes(9) / Duration.hours(1.5))
assertEquals(50.0, Duration.microseconds(1) / Duration.nanoseconds(20))
assertEquals(299.0, Duration.days(365 * 299) / Duration.days(365))
assertTrue((Duration.INFINITE / Duration.INFINITE).isNaN())
}
@@ -354,14 +452,15 @@ class DurationTest {
d -= Duration.milliseconds(1678)
test(DurationUnit.MICROSECONDS, "921us", "920.5us", "920.52us", "920.516us")
d -= Duration.microseconds(920)
// sub-nanosecond precision errors
test(DurationUnit.NANOSECONDS, "516ns", "516.3ns", "516.34ns", "516.344ns", "516.3438ns")
// no sub-nanosecond precision
test(DurationUnit.NANOSECONDS, "516ns", "516.0ns", "516.00ns", "516.000ns", "516.0000ns")
d = (d - Duration.nanoseconds(516)) / 17
test(DurationUnit.NANOSECONDS, "0ns", "0.0ns", "0.02ns", "0.020ns", "0.0202ns")
test(DurationUnit.NANOSECONDS, "0ns", "0.0ns", "0.00ns", "0.000ns", "0.0000ns")
d = Duration.nanoseconds(Double.MAX_VALUE)
test(DurationUnit.DAYS, "2.08e+294d")
test(DurationUnit.NANOSECONDS, "1.80e+308ns")
// infinite
// d = Duration.nanoseconds(Double.MAX_VALUE)
// test(DurationUnit.DAYS, "2.08e+294d")
// test(DurationUnit.NANOSECONDS, "1.80e+308ns")
assertEquals("0.500000000000s", Duration.seconds(0.5).toString(DurationUnit.SECONDS, 100))
assertEquals("99999000000000.000000000000ns", Duration.seconds(99_999).toString(DurationUnit.NANOSECONDS, 15))
@@ -417,27 +516,29 @@ class DurationTest {
test(Duration.microseconds(1.005), "1.01us", "1.00us")
test(Duration.nanoseconds(950.5), "951ns", "950ns")
test(Duration.nanoseconds(85.23), "85.2ns")
test(Duration.nanoseconds(8.235), "8.24ns", "8.23ns")
test(Duration.nanoseconds(1.3), "1.30ns")
test(Duration.nanoseconds(85.23), "85.0ns")
test(Duration.nanoseconds(8.235), "8.00ns")
test(Duration.nanoseconds(1.3), "1.00ns")
test(Duration.nanoseconds(0.75), "0.75ns")
test(Duration.nanoseconds(0.7512), "0.7512ns")
test(Duration.nanoseconds(0.023), "0.023ns")
test(Duration.nanoseconds(0.0034), "0.0034ns")
test(Duration.nanoseconds(0.0000035), "0.0000035ns")
// equal to zero
// test(Duration.nanoseconds(0.75), "0.75ns")
// test(Duration.nanoseconds(0.7512), "0.7512ns")
// test(Duration.nanoseconds(0.023), "0.023ns")
// test(Duration.nanoseconds(0.0034), "0.0034ns")
// test(Duration.nanoseconds(0.0000035), "0.0000035ns")
test(Duration.ZERO, "0s")
test(Duration.days(365) * 10000, "3650000d")
test(Duration.days(300) * 100000, "3.00e+7d")
test(Duration.days(365) * 100000, "3.65e+7d")
val universeAge = Duration.days(365.25) * 13.799e9
val planckTime = Duration.seconds(5.4e-44)
// all infinite
// val universeAge = Duration.days(365.25) * 13.799e9
// val planckTime = Duration.seconds(5.4e-44)
test(universeAge, "5.04e+12d")
test(planckTime, "5.40e-44s")
test(Duration.nanoseconds(Double.MAX_VALUE), "2.08e+294d")
// test(universeAge, "5.04e+12d")
// test(planckTime, "5.40e-44s")
// test(Duration.nanoseconds(Double.MAX_VALUE), "2.08e+294d")
test(Duration.INFINITE, "Infinity")
}
@@ -1,5 +1,5 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
@@ -47,4 +47,12 @@ public actual enum class DurationUnit {
/** Converts the given time duration [value] expressed in the specified [sourceUnit] into the specified [targetUnit]. */
@SinceKotlin("1.3")
@ExperimentalTime
internal actual fun convertDurationUnit(value: Double, sourceUnit: DurationUnit, targetUnit: DurationUnit): Double = TODO("Wasm stdlib: convertDurationUnit")
internal actual fun convertDurationUnit(value: Double, sourceUnit: DurationUnit, targetUnit: DurationUnit): Double = TODO("Wasm stdlib: convertDurationUnit Double")
@SinceKotlin("1.5")
@ExperimentalTime
internal actual fun convertDurationUnitOverflow(value: Long, sourceUnit: DurationUnit, targetUnit: DurationUnit): Long = TODO("Wasm stdlib: convertDurationUnitOverflow Long")
@SinceKotlin("1.5")
@ExperimentalTime
internal actual fun convertDurationUnit(value: Long, sourceUnit: DurationUnit, targetUnit: DurationUnit): Long = TODO("Wasm stdlib: convertDurationUnit Long")
@@ -5645,128 +5645,128 @@ public abstract class kotlin/time/AbstractLongTimeSource : kotlin/time/TimeSourc
public final class kotlin/time/Duration : java/lang/Comparable {
public static final field Companion Lkotlin/time/Duration$Companion;
public static final synthetic fun box-impl (D)Lkotlin/time/Duration;
public static final synthetic fun box-impl (J)Lkotlin/time/Duration;
public synthetic fun compareTo (Ljava/lang/Object;)I
public fun compareTo-LRDsOJo (D)I
public static fun compareTo-LRDsOJo (DD)I
public static final fun div-LRDsOJo (DD)D
public static final fun div-UwyO8pc (DD)D
public static final fun div-UwyO8pc (DI)D
public fun compareTo-LRDsOJo (J)I
public static fun compareTo-LRDsOJo (JJ)I
public static final fun div-LRDsOJo (JJ)D
public static final fun div-UwyO8pc (JD)J
public static final fun div-UwyO8pc (JI)J
public fun equals (Ljava/lang/Object;)Z
public static fun equals-impl (DLjava/lang/Object;)Z
public static final fun equals-impl0 (DD)Z
public static final fun getAbsoluteValue-UwyO8pc (D)D
public static final fun getInDays-impl (D)D
public static final fun getInHours-impl (D)D
public static final fun getInMicroseconds-impl (D)D
public static final fun getInMilliseconds-impl (D)D
public static final fun getInMinutes-impl (D)D
public static final fun getInNanoseconds-impl (D)D
public static final fun getInSeconds-impl (D)D
public static fun equals-impl (JLjava/lang/Object;)Z
public static final fun equals-impl0 (JJ)Z
public static final fun getAbsoluteValue-UwyO8pc (J)J
public static final fun getInDays-impl (J)D
public static final fun getInHours-impl (J)D
public static final fun getInMicroseconds-impl (J)D
public static final fun getInMilliseconds-impl (J)D
public static final fun getInMinutes-impl (J)D
public static final fun getInNanoseconds-impl (J)D
public static final fun getInSeconds-impl (J)D
public fun hashCode ()I
public static fun hashCode-impl (D)I
public static final fun isFinite-impl (D)Z
public static final fun isInfinite-impl (D)Z
public static final fun isNegative-impl (D)Z
public static final fun isPositive-impl (D)Z
public static final fun minus-LRDsOJo (DD)D
public static final fun plus-LRDsOJo (DD)D
public static final fun times-UwyO8pc (DD)D
public static final fun times-UwyO8pc (DI)D
public static final fun toComponents-impl (DLkotlin/jvm/functions/Function2;)Ljava/lang/Object;
public static final fun toComponents-impl (DLkotlin/jvm/functions/Function3;)Ljava/lang/Object;
public static final fun toComponents-impl (DLkotlin/jvm/functions/Function4;)Ljava/lang/Object;
public static final fun toComponents-impl (DLkotlin/jvm/functions/Function5;)Ljava/lang/Object;
public static final fun toDouble-impl (DLjava/util/concurrent/TimeUnit;)D
public static final fun toInt-impl (DLjava/util/concurrent/TimeUnit;)I
public static final fun toIsoString-impl (D)Ljava/lang/String;
public static final fun toLong-impl (DLjava/util/concurrent/TimeUnit;)J
public static final fun toLongMilliseconds-impl (D)J
public static final fun toLongNanoseconds-impl (D)J
public static fun hashCode-impl (J)I
public static final fun isFinite-impl (J)Z
public static final fun isInfinite-impl (J)Z
public static final fun isNegative-impl (J)Z
public static final fun isPositive-impl (J)Z
public static final fun minus-LRDsOJo (JJ)J
public static final fun plus-LRDsOJo (JJ)J
public static final fun times-UwyO8pc (JD)J
public static final fun times-UwyO8pc (JI)J
public static final fun toComponents-impl (JLkotlin/jvm/functions/Function2;)Ljava/lang/Object;
public static final fun toComponents-impl (JLkotlin/jvm/functions/Function3;)Ljava/lang/Object;
public static final fun toComponents-impl (JLkotlin/jvm/functions/Function4;)Ljava/lang/Object;
public static final fun toComponents-impl (JLkotlin/jvm/functions/Function5;)Ljava/lang/Object;
public static final fun toDouble-impl (JLjava/util/concurrent/TimeUnit;)D
public static final fun toInt-impl (JLjava/util/concurrent/TimeUnit;)I
public static final fun toIsoString-impl (J)Ljava/lang/String;
public static final fun toLong-impl (JLjava/util/concurrent/TimeUnit;)J
public static final fun toLongMilliseconds-impl (J)J
public static final fun toLongNanoseconds-impl (J)J
public fun toString ()Ljava/lang/String;
public static fun toString-impl (D)Ljava/lang/String;
public static final fun toString-impl (DLjava/util/concurrent/TimeUnit;I)Ljava/lang/String;
public static synthetic fun toString-impl$default (DLjava/util/concurrent/TimeUnit;IILjava/lang/Object;)Ljava/lang/String;
public static final fun unaryMinus-UwyO8pc (D)D
public final synthetic fun unbox-impl ()D
public static fun toString-impl (J)Ljava/lang/String;
public static final fun toString-impl (JLjava/util/concurrent/TimeUnit;I)Ljava/lang/String;
public static synthetic fun toString-impl$default (JLjava/util/concurrent/TimeUnit;IILjava/lang/Object;)Ljava/lang/String;
public static final fun unaryMinus-UwyO8pc (J)J
public final synthetic fun unbox-impl ()J
}
public final class kotlin/time/Duration$Companion {
public final fun convert (DLjava/util/concurrent/TimeUnit;Ljava/util/concurrent/TimeUnit;)D
public final fun days-UwyO8pc (D)D
public final fun days-UwyO8pc (I)D
public final fun days-UwyO8pc (J)D
public final fun getINFINITE-UwyO8pc ()D
public final fun getZERO-UwyO8pc ()D
public final fun hours-UwyO8pc (D)D
public final fun hours-UwyO8pc (I)D
public final fun hours-UwyO8pc (J)D
public final fun microseconds-UwyO8pc (D)D
public final fun microseconds-UwyO8pc (I)D
public final fun microseconds-UwyO8pc (J)D
public final fun milliseconds-UwyO8pc (D)D
public final fun milliseconds-UwyO8pc (I)D
public final fun milliseconds-UwyO8pc (J)D
public final fun minutes-UwyO8pc (D)D
public final fun minutes-UwyO8pc (I)D
public final fun minutes-UwyO8pc (J)D
public final fun nanoseconds-UwyO8pc (D)D
public final fun nanoseconds-UwyO8pc (I)D
public final fun nanoseconds-UwyO8pc (J)D
public final fun seconds-UwyO8pc (D)D
public final fun seconds-UwyO8pc (I)D
public final fun seconds-UwyO8pc (J)D
public final fun days-UwyO8pc (D)J
public final fun days-UwyO8pc (I)J
public final fun days-UwyO8pc (J)J
public final fun getINFINITE-UwyO8pc ()J
public final fun getZERO-UwyO8pc ()J
public final fun hours-UwyO8pc (D)J
public final fun hours-UwyO8pc (I)J
public final fun hours-UwyO8pc (J)J
public final fun microseconds-UwyO8pc (D)J
public final fun microseconds-UwyO8pc (I)J
public final fun microseconds-UwyO8pc (J)J
public final fun milliseconds-UwyO8pc (D)J
public final fun milliseconds-UwyO8pc (I)J
public final fun milliseconds-UwyO8pc (J)J
public final fun minutes-UwyO8pc (D)J
public final fun minutes-UwyO8pc (I)J
public final fun minutes-UwyO8pc (J)J
public final fun nanoseconds-UwyO8pc (D)J
public final fun nanoseconds-UwyO8pc (I)J
public final fun nanoseconds-UwyO8pc (J)J
public final fun seconds-UwyO8pc (D)J
public final fun seconds-UwyO8pc (I)J
public final fun seconds-UwyO8pc (J)J
}
public final class kotlin/time/DurationKt {
public static final fun getDays (D)D
public static final fun getDays (I)D
public static final fun getDays (J)D
public static final fun getHours (D)D
public static final fun getHours (I)D
public static final fun getHours (J)D
public static final fun getMicroseconds (D)D
public static final fun getMicroseconds (I)D
public static final fun getMicroseconds (J)D
public static final fun getMilliseconds (D)D
public static final fun getMilliseconds (I)D
public static final fun getMilliseconds (J)D
public static final fun getMinutes (D)D
public static final fun getMinutes (I)D
public static final fun getMinutes (J)D
public static final fun getNanoseconds (D)D
public static final fun getNanoseconds (I)D
public static final fun getNanoseconds (J)D
public static final fun getSeconds (D)D
public static final fun getSeconds (I)D
public static final fun getSeconds (J)D
public static final fun toDuration (DLjava/util/concurrent/TimeUnit;)D
public static final fun toDuration (ILjava/util/concurrent/TimeUnit;)D
public static final fun toDuration (JLjava/util/concurrent/TimeUnit;)D
public static final fun getDays (D)J
public static final fun getDays (I)J
public static final fun getDays (J)J
public static final fun getHours (D)J
public static final fun getHours (I)J
public static final fun getHours (J)J
public static final fun getMicroseconds (D)J
public static final fun getMicroseconds (I)J
public static final fun getMicroseconds (J)J
public static final fun getMilliseconds (D)J
public static final fun getMilliseconds (I)J
public static final fun getMilliseconds (J)J
public static final fun getMinutes (D)J
public static final fun getMinutes (I)J
public static final fun getMinutes (J)J
public static final fun getNanoseconds (D)J
public static final fun getNanoseconds (I)J
public static final fun getNanoseconds (J)J
public static final fun getSeconds (D)J
public static final fun getSeconds (I)J
public static final fun getSeconds (J)J
public static final fun toDuration (DLjava/util/concurrent/TimeUnit;)J
public static final fun toDuration (ILjava/util/concurrent/TimeUnit;)J
public static final fun toDuration (JLjava/util/concurrent/TimeUnit;)J
}
public abstract interface annotation class kotlin/time/ExperimentalTime : java/lang/annotation/Annotation {
}
public final class kotlin/time/MeasureTimeKt {
public static final fun measureTime (Lkotlin/jvm/functions/Function0;)D
public static final fun measureTime (Lkotlin/time/TimeSource;Lkotlin/jvm/functions/Function0;)D
public static final fun measureTime (Lkotlin/jvm/functions/Function0;)J
public static final fun measureTime (Lkotlin/time/TimeSource;Lkotlin/jvm/functions/Function0;)J
public static final fun measureTimedValue (Lkotlin/jvm/functions/Function0;)Lkotlin/time/TimedValue;
public static final fun measureTimedValue (Lkotlin/time/TimeSource;Lkotlin/jvm/functions/Function0;)Lkotlin/time/TimedValue;
}
public final class kotlin/time/TestTimeSource : kotlin/time/AbstractLongTimeSource {
public fun <init> ()V
public final fun plusAssign-LRDsOJo (D)V
public final fun plusAssign-LRDsOJo (J)V
}
public abstract class kotlin/time/TimeMark {
public fun <init> ()V
public abstract fun elapsedNow-UwyO8pc ()D
public abstract fun elapsedNow-UwyO8pc ()J
public final fun hasNotPassedNow ()Z
public final fun hasPassedNow ()Z
public fun minus-LRDsOJo (D)Lkotlin/time/TimeMark;
public fun plus-LRDsOJo (D)Lkotlin/time/TimeMark;
public fun minus-LRDsOJo (J)Lkotlin/time/TimeMark;
public fun plus-LRDsOJo (J)Lkotlin/time/TimeMark;
}
public abstract interface class kotlin/time/TimeSource {
@@ -5784,13 +5784,13 @@ public final class kotlin/time/TimeSource$Monotonic : kotlin/time/TimeSource {
}
public final class kotlin/time/TimedValue {
public synthetic fun <init> (Ljava/lang/Object;DLkotlin/jvm/internal/DefaultConstructorMarker;)V
public synthetic fun <init> (Ljava/lang/Object;JLkotlin/jvm/internal/DefaultConstructorMarker;)V
public final fun component1 ()Ljava/lang/Object;
public final fun component2-UwyO8pc ()D
public final fun copy-RFiDyg4 (Ljava/lang/Object;D)Lkotlin/time/TimedValue;
public static synthetic fun copy-RFiDyg4$default (Lkotlin/time/TimedValue;Ljava/lang/Object;DILjava/lang/Object;)Lkotlin/time/TimedValue;
public final fun component2-UwyO8pc ()J
public final fun copy-RFiDyg4 (Ljava/lang/Object;J)Lkotlin/time/TimedValue;
public static synthetic fun copy-RFiDyg4$default (Lkotlin/time/TimedValue;Ljava/lang/Object;JILjava/lang/Object;)Lkotlin/time/TimedValue;
public fun equals (Ljava/lang/Object;)Z
public final fun getDuration-UwyO8pc ()D
public final fun getDuration-UwyO8pc ()J
public final fun getValue ()Ljava/lang/Object;
public fun hashCode ()I
public fun toString ()Ljava/lang/String;