From 0e93924ff3fe480dc88e1c7787c2cd1f0cf24616 Mon Sep 17 00:00:00 2001 From: Ilya Gorbunov Date: Tue, 30 Mar 2021 02:31:35 +0300 Subject: [PATCH] Duration: inWholeUnits properties instead of inUnits Introduce conversion properties returning Long values, deprecate the old ones returning Doubles. --- libraries/stdlib/api/js-v1/kotlin.time.kt | 30 ++++ libraries/stdlib/api/js/kotlin.time.kt | 30 ++++ libraries/stdlib/src/kotlin/time/Duration.kt | 158 ++++++++++++++---- libraries/stdlib/test/time/DurationTest.kt | 88 +++++----- .../kotlin-stdlib-runtime-merged.txt | 7 + 5 files changed, 242 insertions(+), 71 deletions(-) diff --git a/libraries/stdlib/api/js-v1/kotlin.time.kt b/libraries/stdlib/api/js-v1/kotlin.time.kt index 7dd56c1ad8a..0d3285344fa 100644 --- a/libraries/stdlib/api/js-v1/kotlin.time.kt +++ b/libraries/stdlib/api/js-v1/kotlin.time.kt @@ -183,20 +183,48 @@ public abstract class AbstractLongTimeSource : kotlin.time.TimeSource { public final inline class Duration : kotlin.Comparable { public final val absoluteValue: kotlin.time.Duration { get; } + @kotlin.Deprecated(message = "Use inWholeDays property instead or convert toDouble(DAYS) if a double value is required.", replaceWith = kotlin.ReplaceWith(expression = "toDouble(DurationUnit.DAYS)", imports = {})) public final val inDays: kotlin.Double { get; } + @kotlin.Deprecated(message = "Use inWholeHours property instead or convert toDouble(HOURS) if a double value is required.", replaceWith = kotlin.ReplaceWith(expression = "toDouble(DurationUnit.HOURS)", imports = {})) public final val inHours: kotlin.Double { get; } + @kotlin.Deprecated(message = "Use inWholeMicroseconds property instead or convert toDouble(MICROSECONDS) if a double value is required.", replaceWith = kotlin.ReplaceWith(expression = "toDouble(DurationUnit.MICROSECONDS)", imports = {})) public final val inMicroseconds: kotlin.Double { get; } + @kotlin.Deprecated(message = "Use inWholeMilliseconds property instead or convert toDouble(MILLISECONDS) if a double value is required.", replaceWith = kotlin.ReplaceWith(expression = "toDouble(DurationUnit.MILLISECONDS)", imports = {})) public final val inMilliseconds: kotlin.Double { get; } + @kotlin.Deprecated(message = "Use inWholeMinutes property instead or convert toDouble(MINUTES) if a double value is required.", replaceWith = kotlin.ReplaceWith(expression = "toDouble(DurationUnit.MINUTES)", imports = {})) public final val inMinutes: kotlin.Double { get; } + @kotlin.Deprecated(message = "Use inWholeNanoseconds property instead or convert toDouble(NANOSECONDS) if a double value is required.", replaceWith = kotlin.ReplaceWith(expression = "toDouble(DurationUnit.NANOSECONDS)", imports = {})) public final val inNanoseconds: kotlin.Double { get; } + @kotlin.Deprecated(message = "Use inWholeSeconds property instead or convert toDouble(SECONDS) if a double value is required.", replaceWith = kotlin.ReplaceWith(expression = "toDouble(DurationUnit.SECONDS)", imports = {})) public final val inSeconds: kotlin.Double { get; } + @kotlin.SinceKotlin(version = "1.5") + public final val inWholeDays: kotlin.Long { get; } + + @kotlin.SinceKotlin(version = "1.5") + public final val inWholeHours: kotlin.Long { get; } + + @kotlin.SinceKotlin(version = "1.5") + public final val inWholeMicroseconds: kotlin.Long { get; } + + @kotlin.SinceKotlin(version = "1.5") + public final val inWholeMilliseconds: kotlin.Long { get; } + + @kotlin.SinceKotlin(version = "1.5") + public final val inWholeMinutes: kotlin.Long { get; } + + @kotlin.SinceKotlin(version = "1.5") + public final val inWholeNanoseconds: kotlin.Long { get; } + + @kotlin.SinceKotlin(version = "1.5") + public final val inWholeSeconds: kotlin.Long { get; } + public open override operator fun compareTo(other: kotlin.time.Duration): kotlin.Int public final operator fun div(scale: kotlin.Double): kotlin.time.Duration @@ -241,8 +269,10 @@ public final inline class Duration : kotlin.Comparable { public final fun toLong(unit: kotlin.time.DurationUnit): kotlin.Long + @kotlin.Deprecated(message = "Use inWholeMilliseconds property instead.", replaceWith = kotlin.ReplaceWith(expression = "this.inWholeMilliseconds", imports = {})) public final fun toLongMilliseconds(): kotlin.Long + @kotlin.Deprecated(message = "Use inWholeNanoseconds property instead.", replaceWith = kotlin.ReplaceWith(expression = "this.inWholeNanoseconds", imports = {})) public final fun toLongNanoseconds(): kotlin.Long public open override fun toString(): kotlin.String diff --git a/libraries/stdlib/api/js/kotlin.time.kt b/libraries/stdlib/api/js/kotlin.time.kt index 7dd56c1ad8a..0d3285344fa 100644 --- a/libraries/stdlib/api/js/kotlin.time.kt +++ b/libraries/stdlib/api/js/kotlin.time.kt @@ -183,20 +183,48 @@ public abstract class AbstractLongTimeSource : kotlin.time.TimeSource { public final inline class Duration : kotlin.Comparable { public final val absoluteValue: kotlin.time.Duration { get; } + @kotlin.Deprecated(message = "Use inWholeDays property instead or convert toDouble(DAYS) if a double value is required.", replaceWith = kotlin.ReplaceWith(expression = "toDouble(DurationUnit.DAYS)", imports = {})) public final val inDays: kotlin.Double { get; } + @kotlin.Deprecated(message = "Use inWholeHours property instead or convert toDouble(HOURS) if a double value is required.", replaceWith = kotlin.ReplaceWith(expression = "toDouble(DurationUnit.HOURS)", imports = {})) public final val inHours: kotlin.Double { get; } + @kotlin.Deprecated(message = "Use inWholeMicroseconds property instead or convert toDouble(MICROSECONDS) if a double value is required.", replaceWith = kotlin.ReplaceWith(expression = "toDouble(DurationUnit.MICROSECONDS)", imports = {})) public final val inMicroseconds: kotlin.Double { get; } + @kotlin.Deprecated(message = "Use inWholeMilliseconds property instead or convert toDouble(MILLISECONDS) if a double value is required.", replaceWith = kotlin.ReplaceWith(expression = "toDouble(DurationUnit.MILLISECONDS)", imports = {})) public final val inMilliseconds: kotlin.Double { get; } + @kotlin.Deprecated(message = "Use inWholeMinutes property instead or convert toDouble(MINUTES) if a double value is required.", replaceWith = kotlin.ReplaceWith(expression = "toDouble(DurationUnit.MINUTES)", imports = {})) public final val inMinutes: kotlin.Double { get; } + @kotlin.Deprecated(message = "Use inWholeNanoseconds property instead or convert toDouble(NANOSECONDS) if a double value is required.", replaceWith = kotlin.ReplaceWith(expression = "toDouble(DurationUnit.NANOSECONDS)", imports = {})) public final val inNanoseconds: kotlin.Double { get; } + @kotlin.Deprecated(message = "Use inWholeSeconds property instead or convert toDouble(SECONDS) if a double value is required.", replaceWith = kotlin.ReplaceWith(expression = "toDouble(DurationUnit.SECONDS)", imports = {})) public final val inSeconds: kotlin.Double { get; } + @kotlin.SinceKotlin(version = "1.5") + public final val inWholeDays: kotlin.Long { get; } + + @kotlin.SinceKotlin(version = "1.5") + public final val inWholeHours: kotlin.Long { get; } + + @kotlin.SinceKotlin(version = "1.5") + public final val inWholeMicroseconds: kotlin.Long { get; } + + @kotlin.SinceKotlin(version = "1.5") + public final val inWholeMilliseconds: kotlin.Long { get; } + + @kotlin.SinceKotlin(version = "1.5") + public final val inWholeMinutes: kotlin.Long { get; } + + @kotlin.SinceKotlin(version = "1.5") + public final val inWholeNanoseconds: kotlin.Long { get; } + + @kotlin.SinceKotlin(version = "1.5") + public final val inWholeSeconds: kotlin.Long { get; } + public open override operator fun compareTo(other: kotlin.time.Duration): kotlin.Int public final operator fun div(scale: kotlin.Double): kotlin.time.Duration @@ -241,8 +269,10 @@ public final inline class Duration : kotlin.Comparable { public final fun toLong(unit: kotlin.time.DurationUnit): kotlin.Long + @kotlin.Deprecated(message = "Use inWholeMilliseconds property instead.", replaceWith = kotlin.ReplaceWith(expression = "this.inWholeMilliseconds", imports = {})) public final fun toLongMilliseconds(): kotlin.Long + @kotlin.Deprecated(message = "Use inWholeNanoseconds property instead.", replaceWith = kotlin.ReplaceWith(expression = "this.inWholeNanoseconds", imports = {})) public final fun toLongNanoseconds(): kotlin.Long public open override fun toString(): kotlin.String diff --git a/libraries/stdlib/src/kotlin/time/Duration.kt b/libraries/stdlib/src/kotlin/time/Duration.kt index cf570a56805..6aa5e9c4f1c 100644 --- a/libraries/stdlib/src/kotlin/time/Duration.kt +++ b/libraries/stdlib/src/kotlin/time/Duration.kt @@ -26,7 +26,7 @@ import kotlin.math.sign * * To get the value of this duration expressed in a particular [duration units][DurationUnit] * use the functions [toInt], [toLong], and [toDouble] - * or the properties [inHours], [inMinutes], [inSeconds], [inNanoseconds], and so on. + * or the properties [inWholeHours], [inWholeMinutes], [inWholeSeconds], [inWholeNanoseconds], and so on. */ @SinceKotlin("1.3") @ExperimentalTime @@ -390,7 +390,7 @@ public value class Duration internal constructor(private val rawValue: Long) : C */ public inline fun toComponents(action: (days: Int, hours: Int, minutes: Int, seconds: Int, nanoseconds: Int) -> T): T { contract { callsInPlace(action, InvocationKind.EXACTLY_ONCE) } - return action(inDays.toInt(), hoursComponent, minutesComponent, secondsComponent, nanosecondsComponent) + return action(toInt(DurationUnit.DAYS), hoursComponent, minutesComponent, secondsComponent, nanosecondsComponent) } /** @@ -406,7 +406,7 @@ public value class Duration internal constructor(private val rawValue: Long) : C */ public inline fun toComponents(action: (hours: Int, minutes: Int, seconds: Int, nanoseconds: Int) -> T): T { contract { callsInPlace(action, InvocationKind.EXACTLY_ONCE) } - return action(inHours.toInt(), minutesComponent, secondsComponent, nanosecondsComponent) + return action(toInt(DurationUnit.HOURS), minutesComponent, secondsComponent, nanosecondsComponent) } /** @@ -421,7 +421,7 @@ public value class Duration internal constructor(private val rawValue: Long) : C */ public inline fun toComponents(action: (minutes: Int, seconds: Int, nanoseconds: Int) -> T): T { contract { callsInPlace(action, InvocationKind.EXACTLY_ONCE) } - return action(inMinutes.toInt(), secondsComponent, nanosecondsComponent) + return action(toInt(DurationUnit.MINUTES), secondsComponent, nanosecondsComponent) } /** @@ -435,22 +435,37 @@ public value class Duration internal constructor(private val rawValue: Long) : C */ public inline fun toComponents(action: (seconds: Long, nanoseconds: Int) -> T): T { contract { callsInPlace(action, InvocationKind.EXACTLY_ONCE) } - return action(inSeconds.toLong(), nanosecondsComponent) + return action(inWholeSeconds, nanosecondsComponent) } @PublishedApi - internal val hoursComponent: Int get() = (inHours % 24).toInt() + internal val hoursComponent: Int + get() = if (isInfinite()) 0 else (inWholeHours % 24).toInt() + @PublishedApi - internal val minutesComponent: Int get() = (inMinutes % 60).toInt() + internal val minutesComponent: Int + get() = if (isInfinite()) 0 else (inWholeMinutes % 60).toInt() + @PublishedApi - internal val secondsComponent: Int get() = (inSeconds % 60).toInt() + internal val secondsComponent: Int + get() = if (isInfinite()) 0 else (inWholeSeconds % 60).toInt() + @PublishedApi - internal val nanosecondsComponent: Int get() = (inNanoseconds % 1e9).toInt() + internal val nanosecondsComponent: Int + get() = when { + isInfinite() -> 0 + isInMillis() -> millisToNanos(value % 1_000).toInt() + else -> (value % 1_000_000_000).toInt() + } // conversion to units - /** Returns the value of this duration expressed as a [Double] number of the specified [unit]. */ + /** + * Returns the value of this duration expressed as a [Double] number of the specified [unit]. + * + * An infinite duration value is converted either to [Double.POSITIVE_INFINITY] or [Double.NEGATIVE_INFINITY] depending on its sign. + */ public fun toDouble(unit: DurationUnit): Double { return when (rawValue) { INFINITE.rawValue -> Double.POSITIVE_INFINITY @@ -465,7 +480,11 @@ public value class Duration internal constructor(private val rawValue: Long) : C /** * 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. + * If the result doesn't fit in the range of [Long] type, it is coerced into that range: + * - [Long.MIN_VALUE] is returned if it's less than `Long.MIN_VALUE`, + * - [Long.MAX_VALUE] is returned if it's greater than `Long.MAX_VALUE`. + * + * An infinite duration value is converted either to [Long.MAX_VALUE] or [Long.MIN_VALUE] depending on its sign. */ public fun toLong(unit: DurationUnit): Long { return when (rawValue) { @@ -478,34 +497,125 @@ public value class Duration internal constructor(private val rawValue: Long) : C /** * 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. + * If the result doesn't fit in the range of [Int] type, it is coerced into that range: + * - [Int.MIN_VALUE] is returned if it's less than `Int.MIN_VALUE`, + * - [Int.MAX_VALUE] is returned if it's greater than `Int.MAX_VALUE`. + * + * An infinite duration value is converted either to [Int.MAX_VALUE] or [Int.MIN_VALUE] depending on its sign. */ 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. */ + @Deprecated("Use inWholeDays property instead or convert toDouble(DAYS) if a double value is required.", ReplaceWith("toDouble(DurationUnit.DAYS)")) public val inDays: Double get() = toDouble(DurationUnit.DAYS) /** The value of this duration expressed as a [Double] number of hours. */ + @Deprecated("Use inWholeHours property instead or convert toDouble(HOURS) if a double value is required.", ReplaceWith("toDouble(DurationUnit.HOURS)")) public val inHours: Double get() = toDouble(DurationUnit.HOURS) /** The value of this duration expressed as a [Double] number of minutes. */ + @Deprecated("Use inWholeMinutes property instead or convert toDouble(MINUTES) if a double value is required.", ReplaceWith("toDouble(DurationUnit.MINUTES)")) public val inMinutes: Double get() = toDouble(DurationUnit.MINUTES) /** The value of this duration expressed as a [Double] number of seconds. */ + @Deprecated("Use inWholeSeconds property instead or convert toDouble(SECONDS) if a double value is required.", ReplaceWith("toDouble(DurationUnit.SECONDS)")) public val inSeconds: Double get() = toDouble(DurationUnit.SECONDS) /** The value of this duration expressed as a [Double] number of milliseconds. */ + @Deprecated("Use inWholeMilliseconds property instead or convert toDouble(MILLISECONDS) if a double value is required.", ReplaceWith("toDouble(DurationUnit.MILLISECONDS)")) public val inMilliseconds: Double get() = toDouble(DurationUnit.MILLISECONDS) /** The value of this duration expressed as a [Double] number of microseconds. */ + @Deprecated("Use inWholeMicroseconds property instead or convert toDouble(MICROSECONDS) if a double value is required.", ReplaceWith("toDouble(DurationUnit.MICROSECONDS)")) public val inMicroseconds: Double get() = toDouble(DurationUnit.MICROSECONDS) /** The value of this duration expressed as a [Double] number of nanoseconds. */ + @Deprecated("Use inWholeNanoseconds property instead or convert toDouble(NANOSECONDS) if a double value is required.", ReplaceWith("toDouble(DurationUnit.NANOSECONDS)")) public val inNanoseconds: Double get() = toDouble(DurationUnit.NANOSECONDS) + + /** + * The value of this duration expressed as a [Long] number of days. + * + * An infinite duration value is converted either to [Long.MAX_VALUE] or [Long.MIN_VALUE] depending on its sign. + */ + @SinceKotlin("1.5") + public val inWholeDays: Long + get() = toLong(DurationUnit.DAYS) + + /** + * The value of this duration expressed as a [Long] number of hours. + * + * An infinite duration value is converted either to [Long.MAX_VALUE] or [Long.MIN_VALUE] depending on its sign. + */ + @SinceKotlin("1.5") + public val inWholeHours: Long + get() = toLong(DurationUnit.HOURS) + + /** + * The value of this duration expressed as a [Long] number of minutes. + * + * An infinite duration value is converted either to [Long.MAX_VALUE] or [Long.MIN_VALUE] depending on its sign. + */ + @SinceKotlin("1.5") + public val inWholeMinutes: Long + get() = toLong(DurationUnit.MINUTES) + + /** + * The value of this duration expressed as a [Long] number of seconds. + * + * An infinite duration value is converted either to [Long.MAX_VALUE] or [Long.MIN_VALUE] depending on its sign. + */ + @SinceKotlin("1.5") + public val inWholeSeconds: Long + get() = toLong(DurationUnit.SECONDS) + + /** + * The value of this duration expressed as a [Long] number of milliseconds. + * + * An infinite duration value is converted either to [Long.MAX_VALUE] or [Long.MIN_VALUE] depending on its sign. + */ + @SinceKotlin("1.5") + public val inWholeMilliseconds: Long + get() { + return if (isInMillis() && isFinite()) value else toLong(DurationUnit.MILLISECONDS) + } + + /** + * The value of this duration expressed as a [Long] number of microseconds. + * + * If the result doesn't fit in the range of [Long] type, it is coerced into that range: + * - [Long.MIN_VALUE] is returned if it's less than `Long.MIN_VALUE`, + * - [Long.MAX_VALUE] is returned if it's greater than `Long.MAX_VALUE`. + * + * An infinite duration value is converted either to [Long.MAX_VALUE] or [Long.MIN_VALUE] depending on its sign. + */ + @SinceKotlin("1.5") + public val inWholeMicroseconds: Long + get() = toLong(DurationUnit.MICROSECONDS) + + /** + * The value of this duration expressed as a [Long] number of nanoseconds. + * + * If the result doesn't fit in the range of [Long] type, it is coerced into that range: + * - [Long.MIN_VALUE] is returned if it's less than `Long.MIN_VALUE`, + * - [Long.MAX_VALUE] is returned if it's greater than `Long.MAX_VALUE`. + * + * An infinite duration value is converted either to [Long.MAX_VALUE] or [Long.MIN_VALUE] depending on its sign. + */ + @SinceKotlin("1.5") + public val inWholeNanoseconds: Long + get() { + 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) + } + } + // shortcuts /** @@ -515,16 +625,8 @@ public value class Duration internal constructor(private val rawValue: Long) : C * * The range of durations that can be expressed as a `Long` number of nanoseconds is approximately ±292 years. */ - // 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) - } - } + @Deprecated("Use inWholeNanoseconds property instead.", ReplaceWith("this.inWholeNanoseconds")) + public fun toLongNanoseconds(): Long = inWholeNanoseconds /** * Returns the value of this duration expressed as a [Long] number of milliseconds. @@ -533,10 +635,8 @@ public value class Duration internal constructor(private val rawValue: Long) : C * * The range of durations that can be expressed as a `Long` number of milliseconds is approximately ±292 million years. */ - // TODO: Deprecate in favor inWholeMilliseconds - public fun toLongMilliseconds(): Long { - return if (isInMillis() && isFinite()) rawValue else toLong(DurationUnit.MILLISECONDS) - } + @Deprecated("Use inWholeMilliseconds property instead.", ReplaceWith("this.inWholeMilliseconds")) + public fun toLongMilliseconds(): Long = inWholeMilliseconds /** * Returns a string representation of this duration value expressed in the unit which yields the most compact and readable number value. @@ -556,7 +656,7 @@ public value class Duration internal constructor(private val rawValue: Long) : C INFINITE.rawValue -> "Infinity" NEG_INFINITE.rawValue -> "-Infinity" else -> { - val absNs = absoluteValue.inNanoseconds + val absNs = absoluteValue.toDouble(DurationUnit.NANOSECONDS) var scientific = false var maxDecimals = 0 val unit = when { diff --git a/libraries/stdlib/test/time/DurationTest.kt b/libraries/stdlib/test/time/DurationTest.kt index cb361af04c5..6a85ce18284 100644 --- a/libraries/stdlib/test/time/DurationTest.kt +++ b/libraries/stdlib/test/time/DurationTest.kt @@ -24,22 +24,22 @@ class DurationTest { // nanosecond precision val testValues = listOf(0L, 1L, MAX_NANOS) + List(100) { Random.nextLong(0, MAX_NANOS) } for (value in testValues) { - assertEquals(value, value.toDuration(DurationUnit.NANOSECONDS).toLongNanoseconds()) - assertEquals(-value, -value.toDuration(DurationUnit.NANOSECONDS).toLongNanoseconds()) + assertEquals(value, value.toDuration(DurationUnit.NANOSECONDS).inWholeNanoseconds) + assertEquals(-value, -value.toDuration(DurationUnit.NANOSECONDS).inWholeNanoseconds) } // expressible as long nanoseconds but stored as milliseconds for (delta in testValues) { val value = (MAX_NANOS + 1) + delta val expected = value - (value % NANOS_IN_MILLIS) - assertEquals(expected, value.toDuration(DurationUnit.NANOSECONDS).toLongNanoseconds()) - assertEquals(-expected, -value.toDuration(DurationUnit.NANOSECONDS).toLongNanoseconds()) + assertEquals(expected, value.toDuration(DurationUnit.NANOSECONDS).inWholeNanoseconds) + assertEquals(-expected, -value.toDuration(DurationUnit.NANOSECONDS).inWholeNanoseconds) } // 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(value * scale, value.toDuration(unit).inWholeNanoseconds) } } @@ -51,7 +51,7 @@ class DurationTest { assertEquals(d2, d2 + Duration.nanoseconds(1)) } - assertEquals(Long.MAX_VALUE / 1000, Long.MAX_VALUE.toDuration(DurationUnit.MICROSECONDS).toLongMilliseconds()) + assertEquals(Long.MAX_VALUE / 1000, Long.MAX_VALUE.toDuration(DurationUnit.MICROSECONDS).inWholeMilliseconds) assertEquals(Long.MAX_VALUE / 1000 * 1000, Long.MAX_VALUE.toDuration(DurationUnit.MICROSECONDS).toLong(DurationUnit.MICROSECONDS)) assertEquals(Duration.INFINITE, (MAX_MILLIS).toDuration(DurationUnit.MILLISECONDS)) @@ -60,8 +60,8 @@ class DurationTest { run { val maxNsDouble = MAX_NANOS.toDouble() val lessThanMaxDouble = maxNsDouble.nextDown() - val maxNs = maxNsDouble.toDuration(DurationUnit.NANOSECONDS).toLongNanoseconds() - val lessThanMaxNs = lessThanMaxDouble.toDuration(DurationUnit.NANOSECONDS).toLongNanoseconds() + val maxNs = maxNsDouble.toDuration(DurationUnit.NANOSECONDS).inWholeNanoseconds + val lessThanMaxNs = lessThanMaxDouble.toDuration(DurationUnit.NANOSECONDS).inWholeNanoseconds assertTrue(maxNs > lessThanMaxNs, "$maxNs should be > $lessThanMaxNs") } @@ -95,10 +95,10 @@ class DurationTest { } } - run { // invariant Duration.nanoseconds(d.toLongNanoseconds()) == d when duration does not overflow nanoseconds + run { // invariant Duration.nanoseconds(d.inWholeNanoseconds) == d when whole nanoseconds fits into Long range val d1 = Duration.nanoseconds(MAX_NANOS + 1) - val d2 = Duration.nanoseconds(d1.toLongNanoseconds()) - assertEquals(d1.toLongNanoseconds(), d2.toLongNanoseconds()) + val d2 = Duration.nanoseconds(d1.inWholeNanoseconds) + assertEquals(d1.inWholeNanoseconds, d2.inWholeNanoseconds) assertEquals(d1, d2) } } @@ -109,8 +109,8 @@ class DurationTest { assertTrue(d1 > d2, message) assertFalse(d1 <= d2, message) assertTrue( - d1.toLongNanoseconds() > d2.toLongNanoseconds() || - d1.toLongNanoseconds() == d2.toLongNanoseconds() && d1.toLongMilliseconds() > d2.toLongMilliseconds(), + d1.inWholeNanoseconds > d2.inWholeNanoseconds || + d1.inWholeNanoseconds == d2.inWholeNanoseconds && d1.inWholeMilliseconds > d2.inWholeMilliseconds, message ) } @@ -167,23 +167,26 @@ class DurationTest { @Test fun conversionToNumber() { - assertEquals(24.0, Duration.days(1).inHours) - assertEquals(0.5, Duration.hours(12).inDays) - assertEquals(15.0, Duration.hours(0.25).inMinutes) - assertEquals(600.0, Duration.minutes(10).inSeconds) - assertEquals(500.0, Duration.seconds(0.5).inMilliseconds) - assertEquals(50_000.0, Duration.seconds(0.05).inMicroseconds) - assertEquals(50_000.0, Duration.milliseconds(0.05).inNanoseconds) + assertEquals(24, Duration.days(1).inWholeHours) + assertEquals(0.5, Duration.hours(12).toDouble(DurationUnit.DAYS)) + assertEquals(0, Duration.hours(12).inWholeDays) + assertEquals(15, Duration.hours(0.25).inWholeMinutes) + assertEquals(600, Duration.minutes(10).inWholeSeconds) + assertEquals(500, Duration.seconds(0.5).inWholeMilliseconds) + assertEquals(50_000, Duration.seconds(0.05).inWholeMicroseconds) + assertEquals(50_000, Duration.milliseconds(0.05).inWholeNanoseconds) - assertEquals(365 * 86400e9, Duration.days(365).inNanoseconds) + assertEquals(365 * 86400 * 1_000_000_000L, Duration.days(365).inWholeNanoseconds) - assertEquals(0.0, Duration.ZERO.inNanoseconds) + assertEquals(0, Duration.ZERO.inWholeNanoseconds) + assertEquals(0, Duration.ZERO.inWholeMicroseconds) + assertEquals(0, Duration.ZERO.inWholeMilliseconds) - assertEquals(10500, Duration.seconds(10.5).toLongMilliseconds()) - assertEquals(11, Duration.milliseconds(11.5).toLongMilliseconds()) - assertEquals(-11, Duration.milliseconds((-11.5)).toLongMilliseconds()) - assertEquals(252_000_000, Duration.milliseconds(252).toLongNanoseconds()) - assertEquals(Long.MAX_VALUE, (Duration.days(365) * 293).toLongNanoseconds()) // clamping overflowed value + assertEquals(10500, Duration.seconds(10.5).inWholeMilliseconds) + assertEquals(11, Duration.milliseconds(11.5).inWholeMilliseconds) + assertEquals(-11, Duration.milliseconds((-11.5)).inWholeMilliseconds) + assertEquals(252_000_000, Duration.milliseconds(252).inWholeNanoseconds) + assertEquals(Long.MAX_VALUE, (Duration.days(365) * 293).inWholeNanoseconds) // clamping overflowed value repeat(100) { val value = Random.nextLong(1000) @@ -206,28 +209,29 @@ class DurationTest { @Test fun componentsOfProperSum() { repeat(100) { + val d = Random.nextInt(365 * 50) // fits in Int seconds val h = Random.nextInt(24) val m = Random.nextInt(60) val s = Random.nextInt(60) val ns = Random.nextInt(1e9.toInt()) - (Duration.hours(h) + Duration.minutes(m) + Duration.seconds(s) + Duration.nanoseconds(ns)).run { + (Duration.days(d) + Duration.hours(h) + Duration.minutes(m) + Duration.seconds(s) + Duration.nanoseconds(ns)).run { toComponents { seconds, nanoseconds -> - assertEquals(h.toLong() * 3600 + m * 60 + s, seconds) + assertEquals(d.toLong() * 86400 + h * 3600 + m * 60 + s, seconds) assertEquals(ns, nanoseconds) } toComponents { minutes, seconds, nanoseconds -> - assertEquals(h * 60 + m, minutes) + assertEquals(d * 1440 + h * 60 + m, minutes) assertEquals(s, seconds) assertEquals(ns, nanoseconds) } toComponents { hours, minutes, seconds, nanoseconds -> - assertEquals(h, hours) + assertEquals(d * 24 + h, hours) assertEquals(m, minutes) assertEquals(s, seconds) - assertEquals(ns, nanoseconds, "ns component of duration ${toIsoString()} differs too much, expected: $ns, actual: $nanoseconds") + assertEquals(ns, nanoseconds) } toComponents { days, hours, minutes, seconds, nanoseconds -> - assertEquals(0, days) + assertEquals(d, days) assertEquals(h, hours) assertEquals(m, minutes) assertEquals(s, seconds) @@ -302,9 +306,9 @@ class DurationTest { assertFalse(value.isPositive()) assertEquals(Duration.ZERO.toString(), value.toString()) assertEquals(Duration.ZERO.toIsoString(), value.toIsoString()) - assertEquals(Duration.ZERO.inSeconds, value.inSeconds) + assertEquals(Duration.ZERO.toDouble(DurationUnit.SECONDS), value.toDouble(DurationUnit.SECONDS)) assertEquals(0, Duration.ZERO.compareTo(value)) - assertEquals(0, Duration.ZERO.inNanoseconds.compareTo(value.inNanoseconds)) + assertEquals(0, Duration.ZERO.toDouble(DurationUnit.NANOSECONDS).compareTo(value.toDouble(DurationUnit.NANOSECONDS))) } equivalentToZero(Duration.seconds(-0.0)) equivalentToZero((-0.0).toDuration(DurationUnit.DAYS)) @@ -345,8 +349,8 @@ class DurationTest { val offset = 2L * NANOS_IN_MILLIS val value = MAX_NANOS + offset val base = Duration.nanoseconds(value) - val baseNs = base.toLongMilliseconds() * NANOS_IN_MILLIS - assertEquals(baseNs, base.toLongNanoseconds()) // base stored as millis + val baseNs = base.inWholeMilliseconds * NANOS_IN_MILLIS + assertEquals(baseNs, base.inWholeNanoseconds) // base stored as millis val smallDeltas = listOf(1L, 2L, 1000L, NANOS_IN_MILLIS - 1L) + List(10) { Random.nextLong(NANOS_IN_MILLIS.toLong()) } for (smallDeltaNs in smallDeltas) { @@ -358,8 +362,8 @@ class DurationTest { List(100) { Random.nextLong(offset + 1500, MAX_NANOS) } for (deltaNs in deltas) { val delta = Duration.nanoseconds(deltaNs) - assertEquals(deltaNs, delta.toLongNanoseconds()) - assertEquals(baseNs - deltaNs, (base - delta).toLongNanoseconds(), "base: $baseNs, delta: $deltaNs") + assertEquals(deltaNs, delta.inWholeNanoseconds) + assertEquals(baseNs - deltaNs, (base - delta).inWholeNanoseconds, "base: $baseNs, delta: $deltaNs") } } @@ -389,8 +393,8 @@ class DurationTest { run { // promoting nanos range to millis range after multiplication val value = MAX_NANOS - assertEquals(value, (Duration.nanoseconds(value) * 1_000_000).toLongMilliseconds()) - assertEquals(value / 1000, (Duration.nanoseconds(value) * 1_000).toLongMilliseconds()) + assertEquals(value, (Duration.nanoseconds(value) * 1_000_000).inWholeMilliseconds) + assertEquals(value / 1000, (Duration.nanoseconds(value) * 1_000).inWholeMilliseconds) assertEquals(Duration.INFINITE, Duration.nanoseconds(Long.MAX_VALUE / 1000 + 1) * 1_000_000_000) } @@ -421,7 +425,7 @@ class DurationTest { run { val value = MAX_NANOS - assertEquals(value, (Duration.milliseconds(value) / 1_000_000).toLongNanoseconds()) + assertEquals(value, (Duration.milliseconds(value) / 1_000_000).inWholeNanoseconds) } assertEquals(Duration.INFINITE, Duration.seconds(1) / 0) 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 69edc721436..8881da98fae 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 @@ -5663,6 +5663,13 @@ public final class kotlin/time/Duration : java/lang/Comparable { 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 static final fun getInWholeDays-impl (J)J + public static final fun getInWholeHours-impl (J)J + public static final fun getInWholeMicroseconds-impl (J)J + public static final fun getInWholeMilliseconds-impl (J)J + public static final fun getInWholeMinutes-impl (J)J + public static final fun getInWholeNanoseconds-impl (J)J + public static final fun getInWholeSeconds-impl (J)J public fun hashCode ()I public static fun hashCode-impl (J)I public static final fun isFinite-impl (J)Z