Stabilize Duration, DurationUnit and related top-level functions KT-46784
Co-authored-by: Abduqodiri Qurbonzoda <abduqodiri.qurbonzoda@jetbrains.com>
This commit is contained in:
@@ -26,8 +26,8 @@ import kotlin.math.*
|
||||
* use the functions [toInt], [toLong], and [toDouble]
|
||||
* or the properties [inWholeHours], [inWholeMinutes], [inWholeSeconds], [inWholeNanoseconds], and so on.
|
||||
*/
|
||||
@SinceKotlin("1.3")
|
||||
@ExperimentalTime
|
||||
@SinceKotlin("1.6")
|
||||
@WasExperimental(ExperimentalTime::class)
|
||||
@JvmInline
|
||||
public value class Duration internal constructor(private val rawValue: Long) : Comparable<Duration> {
|
||||
|
||||
@@ -183,7 +183,6 @@ public value class Duration internal constructor(private val rawValue: Long) : C
|
||||
* @throws IllegalArgumentException if the string doesn't represent a duration in any of the supported formats.
|
||||
* @sample samples.time.Durations.parse
|
||||
*/
|
||||
@SinceKotlin("1.5")
|
||||
public fun parse(value: String): Duration = try {
|
||||
parseDuration(value, strictIso = false)
|
||||
} catch (e: IllegalArgumentException) {
|
||||
@@ -196,7 +195,6 @@ public value class Duration internal constructor(private val rawValue: Long) : C
|
||||
* @throws IllegalArgumentException if the string doesn't represent a duration in ISO-8601 format.
|
||||
* @sample samples.time.Durations.parseIsoString
|
||||
*/
|
||||
@SinceKotlin("1.5")
|
||||
public fun parseIsoString(value: String): Duration = try {
|
||||
parseDuration(value, strictIso = true)
|
||||
} catch (e: IllegalArgumentException) {
|
||||
@@ -214,7 +212,6 @@ public value class Duration internal constructor(private val rawValue: Long) : C
|
||||
* e.g. `10s`, `1h 30m` or `-(1h 30m)`.
|
||||
* @sample samples.time.Durations.parse
|
||||
*/
|
||||
@SinceKotlin("1.5")
|
||||
public fun parseOrNull(value: String): Duration? = try {
|
||||
parseDuration(value, strictIso = false)
|
||||
} catch (e: IllegalArgumentException) {
|
||||
@@ -226,7 +223,6 @@ public value class Duration internal constructor(private val rawValue: Long) : C
|
||||
* or `null` if the string doesn't represent a duration in ISO-8601 format.
|
||||
* @sample samples.time.Durations.parseIsoString
|
||||
*/
|
||||
@SinceKotlin("1.5")
|
||||
public fun parseIsoStringOrNull(value: String): Duration? = try {
|
||||
parseDuration(value, strictIso = true)
|
||||
} catch (e: IllegalArgumentException) {
|
||||
@@ -603,7 +599,6 @@ public value class Duration internal constructor(private val rawValue: Long) : C
|
||||
*
|
||||
* 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)
|
||||
|
||||
@@ -612,7 +607,6 @@ public value class Duration internal constructor(private val rawValue: Long) : C
|
||||
*
|
||||
* 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)
|
||||
|
||||
@@ -621,7 +615,6 @@ public value class Duration internal constructor(private val rawValue: Long) : C
|
||||
*
|
||||
* 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)
|
||||
|
||||
@@ -630,7 +623,6 @@ public value class Duration internal constructor(private val rawValue: Long) : C
|
||||
*
|
||||
* 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)
|
||||
|
||||
@@ -639,7 +631,6 @@ public value class Duration internal constructor(private val rawValue: Long) : C
|
||||
*
|
||||
* 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)
|
||||
@@ -654,7 +645,6 @@ public value class Duration internal constructor(private val rawValue: Long) : C
|
||||
*
|
||||
* 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)
|
||||
|
||||
@@ -667,7 +657,6 @@ public value class Duration internal constructor(private val rawValue: Long) : C
|
||||
*
|
||||
* 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
|
||||
@@ -851,8 +840,8 @@ public value class Duration internal constructor(private val rawValue: Long) : C
|
||||
// extension functions
|
||||
|
||||
/** Returns a [Duration] equal to this [Int] number of the specified [unit]. */
|
||||
@SinceKotlin("1.3")
|
||||
@ExperimentalTime
|
||||
@SinceKotlin("1.6")
|
||||
@WasExperimental(ExperimentalTime::class)
|
||||
public fun Int.toDuration(unit: DurationUnit): Duration {
|
||||
return if (unit <= DurationUnit.SECONDS) {
|
||||
durationOfNanos(convertDurationUnitOverflow(this.toLong(), unit, DurationUnit.NANOSECONDS))
|
||||
@@ -861,8 +850,8 @@ public fun Int.toDuration(unit: DurationUnit): Duration {
|
||||
}
|
||||
|
||||
/** Returns a [Duration] equal to this [Long] number of the specified [unit]. */
|
||||
@SinceKotlin("1.3")
|
||||
@ExperimentalTime
|
||||
@SinceKotlin("1.6")
|
||||
@WasExperimental(ExperimentalTime::class)
|
||||
public fun Long.toDuration(unit: DurationUnit): Duration {
|
||||
val maxNsInUnit = convertDurationUnitOverflow(MAX_NANOS, DurationUnit.NANOSECONDS, unit)
|
||||
if (this in -maxNsInUnit..maxNsInUnit) {
|
||||
@@ -878,8 +867,8 @@ public fun Long.toDuration(unit: DurationUnit): Duration {
|
||||
*
|
||||
* @throws IllegalArgumentException if this `Double` value is `NaN`.
|
||||
*/
|
||||
@SinceKotlin("1.3")
|
||||
@ExperimentalTime
|
||||
@SinceKotlin("1.6")
|
||||
@WasExperimental(ExperimentalTime::class)
|
||||
public fun Double.toDuration(unit: DurationUnit): Duration {
|
||||
val valueInNs = convertDurationUnit(this, unit, DurationUnit.NANOSECONDS)
|
||||
require(!valueInNs.isNaN()) { "Duration value cannot be NaN." }
|
||||
@@ -1051,8 +1040,8 @@ public val Double.days get() = toDuration(DurationUnit.DAYS)
|
||||
|
||||
|
||||
/** Returns a duration whose value is the specified [duration] value multiplied by this number. */
|
||||
@SinceKotlin("1.3")
|
||||
@ExperimentalTime
|
||||
@SinceKotlin("1.6")
|
||||
@WasExperimental(ExperimentalTime::class)
|
||||
@kotlin.internal.InlineOnly
|
||||
public inline operator fun Int.times(duration: Duration): Duration = duration * this
|
||||
|
||||
@@ -1061,14 +1050,13 @@ public inline operator fun Int.times(duration: Duration): Duration = duration *
|
||||
*
|
||||
* @throws IllegalArgumentException if the operation results in a `NaN` value.
|
||||
*/
|
||||
@SinceKotlin("1.3")
|
||||
@ExperimentalTime
|
||||
@SinceKotlin("1.6")
|
||||
@WasExperimental(ExperimentalTime::class)
|
||||
@kotlin.internal.InlineOnly
|
||||
public inline operator fun Double.times(duration: Duration): Duration = duration * this
|
||||
|
||||
|
||||
|
||||
@ExperimentalTime
|
||||
private fun parseDuration(value: String, strictIso: Boolean): Duration {
|
||||
var length = value.length
|
||||
if (length == 0) throw IllegalArgumentException("The string is empty")
|
||||
@@ -1197,17 +1185,17 @@ private const val MAX_NANOS_IN_MILLIS = MAX_NANOS / NANOS_IN_MILLIS
|
||||
private fun nanosToMillis(nanos: Long): Long = nanos / NANOS_IN_MILLIS
|
||||
private fun millisToNanos(millis: Long): Long = millis * NANOS_IN_MILLIS
|
||||
|
||||
@ExperimentalTime private fun durationOfNanos(normalNanos: Long) = Duration(normalNanos shl 1)
|
||||
@ExperimentalTime private fun durationOfMillis(normalMillis: Long) = Duration((normalMillis shl 1) + 1)
|
||||
@ExperimentalTime private fun durationOf(normalValue: Long, unitDiscriminator: Int) = Duration((normalValue shl 1) + unitDiscriminator)
|
||||
@ExperimentalTime private fun durationOfNanosNormalized(nanos: Long) =
|
||||
private fun durationOfNanos(normalNanos: Long) = Duration(normalNanos shl 1)
|
||||
private fun durationOfMillis(normalMillis: Long) = Duration((normalMillis shl 1) + 1)
|
||||
private fun durationOf(normalValue: Long, unitDiscriminator: Int) = Duration((normalValue shl 1) + unitDiscriminator)
|
||||
private fun durationOfNanosNormalized(nanos: Long) =
|
||||
if (nanos in -MAX_NANOS..MAX_NANOS) {
|
||||
durationOfNanos(nanos)
|
||||
} else {
|
||||
durationOfMillis(nanosToMillis(nanos))
|
||||
}
|
||||
|
||||
@ExperimentalTime private fun durationOfMillisNormalized(millis: Long) =
|
||||
private fun durationOfMillisNormalized(millis: Long) =
|
||||
if (millis in -MAX_NANOS_IN_MILLIS..MAX_NANOS_IN_MILLIS) {
|
||||
durationOfNanos(millisToNanos(millis))
|
||||
} else {
|
||||
|
||||
@@ -14,8 +14,8 @@ package kotlin.time
|
||||
*
|
||||
* The smallest time unit is [NANOSECONDS] and the largest is [DAYS], which corresponds to exactly 24 [HOURS].
|
||||
*/
|
||||
@SinceKotlin("1.3")
|
||||
@ExperimentalTime
|
||||
@SinceKotlin("1.6")
|
||||
@WasExperimental(ExperimentalTime::class)
|
||||
public expect enum class DurationUnit {
|
||||
/**
|
||||
* Time unit representing one nanosecond, which is 1/1000 of a microsecond.
|
||||
@@ -49,22 +49,18 @@ public expect enum class DurationUnit {
|
||||
|
||||
/** Converts the given time duration [value] expressed in the specified [sourceUnit] into the specified [targetUnit]. */
|
||||
@SinceKotlin("1.3")
|
||||
@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
|
||||
@Suppress("REDUNDANT_ELSE_IN_WHEN")
|
||||
internal fun DurationUnit.shortName(): String = when (this) {
|
||||
DurationUnit.NANOSECONDS -> "ns"
|
||||
@@ -78,7 +74,6 @@ internal fun DurationUnit.shortName(): String = when (this) {
|
||||
}
|
||||
|
||||
@SinceKotlin("1.5")
|
||||
@ExperimentalTime
|
||||
internal fun durationUnitByShortName(shortName: String): DurationUnit = when (shortName) {
|
||||
"ns" -> DurationUnit.NANOSECONDS
|
||||
"us" -> DurationUnit.MICROSECONDS
|
||||
@@ -91,7 +86,6 @@ internal fun durationUnitByShortName(shortName: String): DurationUnit = when (sh
|
||||
}
|
||||
|
||||
@SinceKotlin("1.5")
|
||||
@ExperimentalTime
|
||||
internal fun durationUnitByIsoChar(isoChar: Char, isTimeComponent: Boolean): DurationUnit =
|
||||
when {
|
||||
!isTimeComponent -> {
|
||||
|
||||
Reference in New Issue
Block a user