diff --git a/kotlin-native/runtime/src/main/kotlin/kotlin/time/DurationUnit.kt b/kotlin-native/runtime/src/main/kotlin/kotlin/time/DurationUnit.kt index c6c09c967a4..85997abcab6 100644 --- a/kotlin-native/runtime/src/main/kotlin/kotlin/time/DurationUnit.kt +++ b/kotlin-native/runtime/src/main/kotlin/kotlin/time/DurationUnit.kt @@ -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 + } +} diff --git a/libraries/stdlib/jdk8/test/time/DurationConversionTest.kt b/libraries/stdlib/jdk8/test/time/DurationConversionTest.kt index 04b9f7355fd..3c65260ad26 100644 --- a/libraries/stdlib/jdk8/test/time/DurationConversionTest.kt +++ b/libraries/stdlib/jdk8/test/time/DurationConversionTest.kt @@ -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 diff --git a/libraries/stdlib/js/src/kotlin/time/DurationUnit.kt b/libraries/stdlib/js/src/kotlin/time/DurationUnit.kt index 58718a12004..63a1338eb56 100644 --- a/libraries/stdlib/js/src/kotlin/time/DurationUnit.kt +++ b/libraries/stdlib/js/src/kotlin/time/DurationUnit.kt @@ -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 + } +} + + diff --git a/libraries/stdlib/jvm/src/kotlin/time/DurationUnitJvm.kt b/libraries/stdlib/jvm/src/kotlin/time/DurationUnitJvm.kt index ad847913a69..8d9cfb4c5a2 100644 --- a/libraries/stdlib/jvm/src/kotlin/time/DurationUnitJvm.kt +++ b/libraries/stdlib/jvm/src/kotlin/time/DurationUnitJvm.kt @@ -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 -} \ No newline at end of file +} + +@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) +} diff --git a/libraries/stdlib/src/kotlin/time/Duration.kt b/libraries/stdlib/src/kotlin/time/Duration.kt index 533beb37b5b..6e33639b841 100644 --- a/libraries/stdlib/src/kotlin/time/Duration.kt +++ b/libraries/stdlib/src/kotlin/time/Duration.kt @@ -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 { +public value class Duration internal constructor(internal val rawValue: Long) : Comparable { + + 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 \ No newline at end of file diff --git a/libraries/stdlib/src/kotlin/time/DurationUnit.kt b/libraries/stdlib/src/kotlin/time/DurationUnit.kt index 49723578c41..0fef53256eb 100644 --- a/libraries/stdlib/src/kotlin/time/DurationUnit.kt +++ b/libraries/stdlib/src/kotlin/time/DurationUnit.kt @@ -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 diff --git a/libraries/stdlib/test/time/DurationTest.kt b/libraries/stdlib/test/time/DurationTest.kt index 5c98ff00327..55a0fab555a 100644 --- a/libraries/stdlib/test/time/DurationTest.kt +++ b/libraries/stdlib/test/time/DurationTest.kt @@ -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 { 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 { 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 { 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 { Duration.INFINITE * 0 } - assertFailsWith { 0 * Duration.INFINITE } + assertFailsWith { 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 { Duration.INFINITE / Double.POSITIVE_INFINITY } assertFailsWith { Duration.ZERO / 0 } + assertFailsWith { 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") } diff --git a/libraries/stdlib/wasm/src/kotlin/time/DurationUnit.kt b/libraries/stdlib/wasm/src/kotlin/time/DurationUnit.kt index 515e8385967..668cc48ad67 100644 --- a/libraries/stdlib/wasm/src/kotlin/time/DurationUnit.kt +++ b/libraries/stdlib/wasm/src/kotlin/time/DurationUnit.kt @@ -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") \ No newline at end of file diff --git a/libraries/tools/binary-compatibility-validator/reference-public-api/kotlin-stdlib-runtime-merged.txt b/libraries/tools/binary-compatibility-validator/reference-public-api/kotlin-stdlib-runtime-merged.txt index 7bc62c4689b..69edc721436 100644 --- a/libraries/tools/binary-compatibility-validator/reference-public-api/kotlin-stdlib-runtime-merged.txt +++ b/libraries/tools/binary-compatibility-validator/reference-public-api/kotlin-stdlib-runtime-merged.txt @@ -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 ()V - public final fun plusAssign-LRDsOJo (D)V + public final fun plusAssign-LRDsOJo (J)V } public abstract class kotlin/time/TimeMark { public fun ()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 (Ljava/lang/Object;DLkotlin/jvm/internal/DefaultConstructorMarker;)V + public synthetic fun (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;