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:
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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")
|
||||
+98
-98
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user