Duration.toComponents: change the highest component type to Long
This commit is contained in:
@@ -253,11 +253,11 @@ public final inline class Duration : kotlin.Comparable<kotlin.time.Duration> {
|
||||
|
||||
public final operator fun times(scale: kotlin.Int): kotlin.time.Duration
|
||||
|
||||
public final inline fun <T> toComponents(action: (days: kotlin.Int, hours: kotlin.Int, minutes: kotlin.Int, seconds: kotlin.Int, nanoseconds: kotlin.Int) -> T): T
|
||||
public final inline fun <T> toComponents(action: (days: kotlin.Long, hours: kotlin.Int, minutes: kotlin.Int, seconds: kotlin.Int, nanoseconds: kotlin.Int) -> T): T
|
||||
|
||||
public final inline fun <T> toComponents(action: (hours: kotlin.Int, minutes: kotlin.Int, seconds: kotlin.Int, nanoseconds: kotlin.Int) -> T): T
|
||||
public final inline fun <T> toComponents(action: (hours: kotlin.Long, minutes: kotlin.Int, seconds: kotlin.Int, nanoseconds: kotlin.Int) -> T): T
|
||||
|
||||
public final inline fun <T> toComponents(action: (minutes: kotlin.Int, seconds: kotlin.Int, nanoseconds: kotlin.Int) -> T): T
|
||||
public final inline fun <T> toComponents(action: (minutes: kotlin.Long, seconds: kotlin.Int, nanoseconds: kotlin.Int) -> T): T
|
||||
|
||||
public final inline fun <T> toComponents(action: (seconds: kotlin.Long, nanoseconds: kotlin.Int) -> T): T
|
||||
|
||||
|
||||
@@ -253,11 +253,11 @@ public final inline class Duration : kotlin.Comparable<kotlin.time.Duration> {
|
||||
|
||||
public final operator fun times(scale: kotlin.Int): kotlin.time.Duration
|
||||
|
||||
public final inline fun <T> toComponents(action: (days: kotlin.Int, hours: kotlin.Int, minutes: kotlin.Int, seconds: kotlin.Int, nanoseconds: kotlin.Int) -> T): T
|
||||
public final inline fun <T> toComponents(action: (days: kotlin.Long, hours: kotlin.Int, minutes: kotlin.Int, seconds: kotlin.Int, nanoseconds: kotlin.Int) -> T): T
|
||||
|
||||
public final inline fun <T> toComponents(action: (hours: kotlin.Int, minutes: kotlin.Int, seconds: kotlin.Int, nanoseconds: kotlin.Int) -> T): T
|
||||
public final inline fun <T> toComponents(action: (hours: kotlin.Long, minutes: kotlin.Int, seconds: kotlin.Int, nanoseconds: kotlin.Int) -> T): T
|
||||
|
||||
public final inline fun <T> toComponents(action: (minutes: kotlin.Int, seconds: kotlin.Int, nanoseconds: kotlin.Int) -> T): T
|
||||
public final inline fun <T> toComponents(action: (minutes: kotlin.Long, seconds: kotlin.Int, nanoseconds: kotlin.Int) -> T): T
|
||||
|
||||
public final inline fun <T> toComponents(action: (seconds: kotlin.Long, nanoseconds: kotlin.Int) -> T): T
|
||||
|
||||
|
||||
@@ -444,12 +444,13 @@ public value class Duration internal constructor(private val rawValue: Long) : C
|
||||
* - `minutes` represents the whole number of minutes in this duration, and its absolute value is less than 60;
|
||||
* - `hours` represents the whole number of hours in this duration, and its absolute value is less than 24;
|
||||
* - `days` represents the whole number of days in this duration.
|
||||
* If the value doesn't fit in [Int] range, i.e. it's greater than [Int.MAX_VALUE] or less than [Int.MIN_VALUE],
|
||||
* it is coerced into that range.
|
||||
*
|
||||
* Infinite durations are represented as either [Long.MAX_VALUE] days, or [Long.MIN_VALUE] days (depending on the sign of infinity),
|
||||
* and zeroes in the lower components.
|
||||
*/
|
||||
public inline fun <T> toComponents(action: (days: Int, hours: Int, minutes: Int, seconds: Int, nanoseconds: Int) -> T): T {
|
||||
public inline fun <T> toComponents(action: (days: Long, hours: Int, minutes: Int, seconds: Int, nanoseconds: Int) -> T): T {
|
||||
contract { callsInPlace(action, InvocationKind.EXACTLY_ONCE) }
|
||||
return action(toInt(DurationUnit.DAYS), hoursComponent, minutesComponent, secondsComponent, nanosecondsComponent)
|
||||
return action(inWholeDays, hoursComponent, minutesComponent, secondsComponent, nanosecondsComponent)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -460,12 +461,13 @@ public value class Duration internal constructor(private val rawValue: Long) : C
|
||||
* - `seconds` represents the whole number of seconds in this duration, and its absolute value is less than 60;
|
||||
* - `minutes` represents the whole number of minutes in this duration, and its absolute value is less than 60;
|
||||
* - `hours` represents the whole number of hours in this duration.
|
||||
* If the value doesn't fit in [Int] range, i.e. it's greater than [Int.MAX_VALUE] or less than [Int.MIN_VALUE],
|
||||
* it is coerced into that range.
|
||||
*
|
||||
* Infinite durations are represented as either [Long.MAX_VALUE] hours, or [Long.MIN_VALUE] hours (depending on the sign of infinity),
|
||||
* and zeroes in the lower components.
|
||||
*/
|
||||
public inline fun <T> toComponents(action: (hours: Int, minutes: Int, seconds: Int, nanoseconds: Int) -> T): T {
|
||||
public inline fun <T> toComponents(action: (hours: Long, minutes: Int, seconds: Int, nanoseconds: Int) -> T): T {
|
||||
contract { callsInPlace(action, InvocationKind.EXACTLY_ONCE) }
|
||||
return action(toInt(DurationUnit.HOURS), minutesComponent, secondsComponent, nanosecondsComponent)
|
||||
return action(inWholeHours, minutesComponent, secondsComponent, nanosecondsComponent)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -475,12 +477,13 @@ public value class Duration internal constructor(private val rawValue: Long) : C
|
||||
* - `nanoseconds` represents the whole number of nanoseconds in this duration, and its absolute value is less than 1_000_000_000;
|
||||
* - `seconds` represents the whole number of seconds in this duration, and its absolute value is less than 60;
|
||||
* - `minutes` represents the whole number of minutes in this duration.
|
||||
* If the value doesn't fit in [Int] range, i.e. it's greater than [Int.MAX_VALUE] or less than [Int.MIN_VALUE],
|
||||
* it is coerced into that range.
|
||||
*
|
||||
* Infinite durations are represented as either [Long.MAX_VALUE] minutes, or [Long.MIN_VALUE] minutes (depending on the sign of infinity),
|
||||
* and zeroes in the lower components.
|
||||
*/
|
||||
public inline fun <T> toComponents(action: (minutes: Int, seconds: Int, nanoseconds: Int) -> T): T {
|
||||
public inline fun <T> toComponents(action: (minutes: Long, seconds: Int, nanoseconds: Int) -> T): T {
|
||||
contract { callsInPlace(action, InvocationKind.EXACTLY_ONCE) }
|
||||
return action(toInt(DurationUnit.MINUTES), secondsComponent, nanosecondsComponent)
|
||||
return action(inWholeMinutes, secondsComponent, nanosecondsComponent)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -489,8 +492,9 @@ public value class Duration internal constructor(private val rawValue: Long) : C
|
||||
*
|
||||
* - `nanoseconds` represents the whole number of nanoseconds in this duration, and its absolute value is less than 1_000_000_000;
|
||||
* - `seconds` represents the whole number of seconds in this duration.
|
||||
* If the value doesn't fit in [Long] range, i.e. it's greater than [Long.MAX_VALUE] or less than [Long.MIN_VALUE],
|
||||
* it is coerced into that range.
|
||||
*
|
||||
* Infinite durations are represented as either [Long.MAX_VALUE] seconds, or [Long.MIN_VALUE] seconds (depending on the sign of infinity),
|
||||
* and zero nanoseconds.
|
||||
*/
|
||||
public inline fun <T> toComponents(action: (seconds: Long, nanoseconds: Int) -> T): T {
|
||||
contract { callsInPlace(action, InvocationKind.EXACTLY_ONCE) }
|
||||
@@ -728,41 +732,38 @@ public value class Duration internal constructor(private val rawValue: Long) : C
|
||||
val isNegative = isNegative()
|
||||
buildString {
|
||||
if (isNegative) append('-')
|
||||
absoluteValue.run {
|
||||
toComponents { _, hours, minutes, seconds, nanoseconds ->
|
||||
val days = inWholeDays
|
||||
val hasDays = days != 0L
|
||||
val hasHours = hours != 0
|
||||
val hasMinutes = minutes != 0
|
||||
val hasSeconds = seconds != 0 || nanoseconds != 0
|
||||
var components = 0
|
||||
if (hasDays) {
|
||||
append(days).append('d')
|
||||
components++
|
||||
}
|
||||
if (hasHours || (hasDays && (hasMinutes || hasSeconds))) {
|
||||
if (components++ > 0) append(' ')
|
||||
append(hours).append('h')
|
||||
}
|
||||
if (hasMinutes || (hasSeconds && (hasHours || hasDays))) {
|
||||
if (components++ > 0) append(' ')
|
||||
append(minutes).append('m')
|
||||
}
|
||||
if (hasSeconds) {
|
||||
if (components++ > 0) append(' ')
|
||||
when {
|
||||
seconds != 0 || hasDays || hasHours || hasMinutes ->
|
||||
appendFractional(seconds, nanoseconds, 9, "s", isoZeroes = false)
|
||||
nanoseconds >= 1_000_000 ->
|
||||
appendFractional(nanoseconds / 1_000_000, nanoseconds % 1_000_000, 6, "ms", isoZeroes = false)
|
||||
nanoseconds >= 1_000 ->
|
||||
appendFractional(nanoseconds / 1_000, nanoseconds % 1_000, 3, "us", isoZeroes = false)
|
||||
else ->
|
||||
append(nanoseconds).append("ns")
|
||||
}
|
||||
}
|
||||
if (isNegative && components > 1) insert(1, '(').append(')')
|
||||
absoluteValue.toComponents { days, hours, minutes, seconds, nanoseconds ->
|
||||
val hasDays = days != 0L
|
||||
val hasHours = hours != 0
|
||||
val hasMinutes = minutes != 0
|
||||
val hasSeconds = seconds != 0 || nanoseconds != 0
|
||||
var components = 0
|
||||
if (hasDays) {
|
||||
append(days).append('d')
|
||||
components++
|
||||
}
|
||||
if (hasHours || (hasDays && (hasMinutes || hasSeconds))) {
|
||||
if (components++ > 0) append(' ')
|
||||
append(hours).append('h')
|
||||
}
|
||||
if (hasMinutes || (hasSeconds && (hasHours || hasDays))) {
|
||||
if (components++ > 0) append(' ')
|
||||
append(minutes).append('m')
|
||||
}
|
||||
if (hasSeconds) {
|
||||
if (components++ > 0) append(' ')
|
||||
when {
|
||||
seconds != 0 || hasDays || hasHours || hasMinutes ->
|
||||
appendFractional(seconds, nanoseconds, 9, "s", isoZeroes = false)
|
||||
nanoseconds >= 1_000_000 ->
|
||||
appendFractional(nanoseconds / 1_000_000, nanoseconds % 1_000_000, 6, "ms", isoZeroes = false)
|
||||
nanoseconds >= 1_000 ->
|
||||
appendFractional(nanoseconds / 1_000, nanoseconds % 1_000, 3, "us", isoZeroes = false)
|
||||
else ->
|
||||
append(nanoseconds).append("ns")
|
||||
}
|
||||
}
|
||||
if (isNegative && components > 1) insert(1, '(').append(')')
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -822,9 +823,9 @@ public value class Duration internal constructor(private val rawValue: Long) : C
|
||||
public fun toIsoString(): String = buildString {
|
||||
if (isNegative()) append('-')
|
||||
append("PT")
|
||||
val absoluteValue = this@Duration.absoluteValue
|
||||
absoluteValue.toComponents { _, minutes, seconds, nanoseconds ->
|
||||
var hours = absoluteValue.inWholeHours
|
||||
this@Duration.absoluteValue.toComponents { hours, minutes, seconds, nanoseconds ->
|
||||
@Suppress("NAME_SHADOWING")
|
||||
var hours = hours
|
||||
if (isInfinite()) {
|
||||
// use large enough value instead of Long.MAX_VALUE
|
||||
hours = 9_999_999_999_999
|
||||
|
||||
@@ -210,33 +210,38 @@ class DurationTest {
|
||||
@Test
|
||||
fun componentsOfProperSum() {
|
||||
repeat(100) {
|
||||
val d = Random.nextInt(365 * 50) // fits in Int seconds
|
||||
val isNsRange = Random.nextBoolean()
|
||||
val d = if (isNsRange)
|
||||
Random.nextLong(365L * 146)
|
||||
else
|
||||
Random.nextLong(365L * 150, 365L * 146_000_000)
|
||||
val h = Random.nextInt(24)
|
||||
val m = Random.nextInt(60)
|
||||
val s = Random.nextInt(60)
|
||||
val ns = Random.nextInt(1e9.toInt())
|
||||
val expectedNs = if (isNsRange) ns else ns - (ns % NANOS_IN_MILLIS)
|
||||
(Duration.days(d) + Duration.hours(h) + Duration.minutes(m) + Duration.seconds(s) + Duration.nanoseconds(ns)).run {
|
||||
toComponents { seconds, nanoseconds ->
|
||||
assertEquals(d.toLong() * 86400 + h * 3600 + m * 60 + s, seconds)
|
||||
assertEquals(ns, nanoseconds)
|
||||
assertEquals(d * 86400 + h * 3600 + m * 60 + s, seconds)
|
||||
assertEquals(expectedNs, nanoseconds)
|
||||
}
|
||||
toComponents { minutes, seconds, nanoseconds ->
|
||||
assertEquals(d * 1440 + h * 60 + m, minutes)
|
||||
assertEquals(s, seconds)
|
||||
assertEquals(ns, nanoseconds)
|
||||
assertEquals(expectedNs, nanoseconds)
|
||||
}
|
||||
toComponents { hours, minutes, seconds, nanoseconds ->
|
||||
assertEquals(d * 24 + h, hours)
|
||||
assertEquals(m, minutes)
|
||||
assertEquals(s, seconds)
|
||||
assertEquals(ns, nanoseconds)
|
||||
assertEquals(expectedNs, nanoseconds)
|
||||
}
|
||||
toComponents { days, hours, minutes, seconds, nanoseconds ->
|
||||
assertEquals(d, days)
|
||||
assertEquals(h, hours)
|
||||
assertEquals(m, minutes)
|
||||
assertEquals(s, seconds)
|
||||
assertEquals(ns, nanoseconds)
|
||||
assertEquals(expectedNs, nanoseconds)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -255,6 +260,35 @@ class DurationTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun componentsOfInfinity() {
|
||||
for (d in listOf(Duration.INFINITE, -Duration.INFINITE)) {
|
||||
val expected = if (d.isPositive()) Long.MAX_VALUE else Long.MIN_VALUE
|
||||
d.toComponents { seconds, nanoseconds ->
|
||||
assertEquals(expected, seconds)
|
||||
assertEquals(0, nanoseconds)
|
||||
}
|
||||
d.toComponents { minutes: Long, seconds: Int, nanoseconds: Int ->
|
||||
assertEquals(expected, minutes)
|
||||
assertEquals(0, seconds)
|
||||
assertEquals(0, nanoseconds)
|
||||
}
|
||||
d.toComponents { hours, minutes, seconds, nanoseconds ->
|
||||
assertEquals(expected, hours)
|
||||
assertEquals(0, minutes)
|
||||
assertEquals(0, seconds)
|
||||
assertEquals(0, nanoseconds)
|
||||
}
|
||||
d.toComponents { days, hours, minutes, seconds, nanoseconds ->
|
||||
assertEquals(expected, days)
|
||||
assertEquals(0, hours)
|
||||
assertEquals(0, minutes)
|
||||
assertEquals(0, seconds)
|
||||
assertEquals(0, nanoseconds)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun infinite() {
|
||||
assertTrue(Duration.INFINITE.isInfinite())
|
||||
|
||||
Reference in New Issue
Block a user