Change Duration.toString format KT-42851
This commit is contained in:
@@ -25,12 +25,12 @@ class Durations {
|
||||
|
||||
@Sample
|
||||
fun toStringDefault() {
|
||||
assertPrints(Duration.days(45), "45.0d")
|
||||
assertPrints(Duration.days(1.5), "36.0h")
|
||||
assertPrints(Duration.minutes(1230), "20.5h")
|
||||
assertPrints(Duration.minutes(920), "920m")
|
||||
assertPrints(Duration.seconds(1.546), "1.55s")
|
||||
assertPrints(Duration.milliseconds(25.12), "25.1ms")
|
||||
assertPrints(Duration.days(45), "1080h")
|
||||
assertPrints(Duration.days(1.5), "36h")
|
||||
assertPrints(Duration.minutes(1230), "20h 30m")
|
||||
assertPrints(Duration.minutes(920), "15h 20m")
|
||||
assertPrints(Duration.seconds(1.546), "1.546s")
|
||||
assertPrints(Duration.milliseconds(25.12), "0.025120s")
|
||||
}
|
||||
|
||||
@Sample
|
||||
|
||||
@@ -639,15 +639,25 @@ public value class Duration internal constructor(private val rawValue: Long) : C
|
||||
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.
|
||||
* Returns a string representation of this duration value
|
||||
* expressed as a combination of numeric components, each in its own unit.
|
||||
*
|
||||
* Each component is a number followed by the unit abbreviated name: `d`, `h`, `m`, `s`:
|
||||
* `5h`, `1d 12h`, `1h 0m 30.3340s`.
|
||||
* The last component, usually seconds, can be a number with a fractional part.
|
||||
*
|
||||
* If the duration is less than a second, it is represented as a single number
|
||||
* with one of sub-second units: `ms` (milliseconds), `us` (microseconds), or `ns` (nanoseconds):
|
||||
* `140.884ms`, `500us`, `24ns`.
|
||||
*
|
||||
* A negative duration is prefixed with `-` sign and, if it consists of multiple components, surrounded with parentheses:
|
||||
* `-12m` and `-(1h 30m)`.
|
||||
*
|
||||
* Special cases:
|
||||
* - zero duration is formatted as `"0s"`
|
||||
* - the infinite duration is formatted as `"Infinity"` without unit
|
||||
* - very small durations (less than 1e-15 s) are expressed in seconds and formatted in scientific notation
|
||||
* - very big durations (more than 1e+7 days) are expressed in days and formatted in scientific notation
|
||||
* - an infinite duration is formatted as `"Infinity"` or `"-Infinity"` without a unit.
|
||||
*
|
||||
* @return the value of duration in the automatically determined unit followed by that unit abbreviated name: `d`, `h`, `m`, `s`, `ms`, `us`, or `ns`.
|
||||
* It's recommended to use [toIsoString] that uses more strict ISO-8601 format instead of this `toString`
|
||||
* when you want to convert a duration to a string in cases of serialization, interchange, etc.
|
||||
*
|
||||
* @sample samples.time.Durations.toStringDefault
|
||||
*/
|
||||
@@ -656,27 +666,41 @@ public value class Duration internal constructor(private val rawValue: Long) : C
|
||||
INFINITE.rawValue -> "Infinity"
|
||||
NEG_INFINITE.rawValue -> "-Infinity"
|
||||
else -> {
|
||||
val absNs = absoluteValue.toDouble(DurationUnit.NANOSECONDS)
|
||||
var scientific = false
|
||||
var maxDecimals = 0
|
||||
val unit = when {
|
||||
absNs < 1e-6 -> DurationUnit.SECONDS.also { scientific = true }
|
||||
absNs < 1 -> DurationUnit.NANOSECONDS.also { maxDecimals = 7 }
|
||||
absNs < 1e3 -> DurationUnit.NANOSECONDS
|
||||
absNs < 1e6 -> DurationUnit.MICROSECONDS
|
||||
absNs < 1e9 -> DurationUnit.MILLISECONDS
|
||||
absNs < 1000e9 -> DurationUnit.SECONDS
|
||||
absNs < 60_000e9 -> DurationUnit.MINUTES
|
||||
absNs < 3600_000e9 -> DurationUnit.HOURS
|
||||
absNs < 86400e9 * 1e7 -> DurationUnit.DAYS
|
||||
else -> DurationUnit.DAYS.also { scientific = true }
|
||||
buildString {
|
||||
if (isNegative()) append('-')
|
||||
absoluteValue.run {
|
||||
toComponents { _, minutes, seconds, nanoseconds ->
|
||||
val hours = inWholeHours
|
||||
val hasHours = hours != 0L
|
||||
val hasSeconds = seconds != 0 || nanoseconds != 0
|
||||
if (hasHours) {
|
||||
append(hours)
|
||||
append('h')
|
||||
}
|
||||
if (minutes != 0 || (hasSeconds && hasHours)) {
|
||||
if (length > 1) append(' ')
|
||||
append(minutes)
|
||||
append('m')
|
||||
}
|
||||
if (hasSeconds) {
|
||||
if (length > 1) append(' ')
|
||||
append(seconds)
|
||||
if (nanoseconds != 0) {
|
||||
append('.')
|
||||
when {
|
||||
(nanoseconds % 1_000_000 == 0) ->
|
||||
append((nanoseconds / 1_000_000).toString().padStart(3, '0'))
|
||||
(nanoseconds % 1_000 == 0) ->
|
||||
append((nanoseconds / 1_000).toString().padStart(6, '0'))
|
||||
else ->
|
||||
append(nanoseconds.toString().padStart(9, '0'))
|
||||
}
|
||||
}
|
||||
append('s')
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
val value = toDouble(unit)
|
||||
when {
|
||||
scientific -> formatScientific(value)
|
||||
maxDecimals > 0 -> formatUpToDecimals(value, maxDecimals)
|
||||
else -> formatToExactDecimals(value, precision(abs(value)))
|
||||
} + unit.shortName()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -543,40 +543,43 @@ class DurationTest {
|
||||
assertEquals("-$actual", (-duration).toString())
|
||||
}
|
||||
|
||||
test(Duration.days(101), "101d")
|
||||
test(Duration.days(45.3), "45.3d")
|
||||
test(Duration.days(45), "45.0d")
|
||||
test(Duration.days(101), "2424h")
|
||||
test(Duration.days(45.3), "1087h 12m") // 1080h + 7.2h
|
||||
test(Duration.days(45), "1080h")
|
||||
|
||||
test(Duration.days(40.5), "972h")
|
||||
test(Duration.hours(40) + Duration.minutes(15), "40.3h", "40.2h")
|
||||
test(Duration.hours(40), "40.0h")
|
||||
test(Duration.hours(40) + Duration.minutes(15), "40h 15m")
|
||||
test(Duration.hours(40), "40h")
|
||||
|
||||
test(Duration.hours(12.5), "750m")
|
||||
test(Duration.minutes(30), "30.0m")
|
||||
test(Duration.minutes(17.5), "17.5m")
|
||||
test(Duration.hours(12.5), "12h 30m")
|
||||
test(Duration.hours(12) + Duration.seconds(15), "12h 0m 15s")
|
||||
test(Duration.hours(12) + Duration.nanoseconds(1), "12h 0m 0.000000001s")
|
||||
test(Duration.minutes(30), "30m")
|
||||
test(Duration.minutes(17.5), "17m 30s")
|
||||
|
||||
test(Duration.minutes(16.5), "990s")
|
||||
test(Duration.seconds(90.36), "90.4s")
|
||||
test(Duration.seconds(50), "50.0s")
|
||||
test(Duration.seconds(1.3), "1.30s")
|
||||
test(Duration.seconds(1), "1.00s")
|
||||
test(Duration.minutes(16.5), "16m 30s")
|
||||
test(Duration.seconds(1097.1), "18m 17.099999999s") // Double to Long ns truncation!
|
||||
test(Duration.seconds(90.36), "1m 30.360s")
|
||||
test(Duration.seconds(50), "50s")
|
||||
test(Duration.seconds(1.3), "1.300s")
|
||||
test(Duration.seconds(1), "1s")
|
||||
|
||||
test(Duration.seconds(0.5), "500ms")
|
||||
test(Duration.milliseconds(40.2), "40.2ms")
|
||||
test(Duration.milliseconds(4.225), "4.23ms", "4.22ms")
|
||||
test(Duration.milliseconds(4.245), "4.25ms")
|
||||
test(Duration.milliseconds(1), "1.00ms")
|
||||
test(Duration.seconds(0.5), "0.500s")
|
||||
test(Duration.milliseconds(40.2), "0.040200s")
|
||||
test(Duration.milliseconds(4.225), "0.004225s")
|
||||
test(Duration.milliseconds(4.245), "0.004245s")
|
||||
test(Duration.milliseconds(1), "0.001s")
|
||||
|
||||
test(Duration.milliseconds(0.75), "750us")
|
||||
test(Duration.microseconds(75.35), "75.4us", "75.3us")
|
||||
test(Duration.microseconds(7.25), "7.25us")
|
||||
test(Duration.microseconds(1.035), "1.04us", "1.03us")
|
||||
test(Duration.microseconds(1.005), "1.01us", "1.00us")
|
||||
test(Duration.milliseconds(0.75), "0.000750s")
|
||||
test(Duration.microseconds(75.35), "0.000075350s")
|
||||
test(Duration.microseconds(7.25), "0.000007250s")
|
||||
test(Duration.microseconds(1.035), "0.000001035s")
|
||||
test(Duration.microseconds(1.005), "0.000001004s") // Double to Long ns truncation!
|
||||
|
||||
test(Duration.nanoseconds(950.5), "951ns", "950ns")
|
||||
test(Duration.nanoseconds(85.23), "85.0ns")
|
||||
test(Duration.nanoseconds(8.235), "8.00ns")
|
||||
test(Duration.nanoseconds(1.3), "1.00ns")
|
||||
test(Duration.nanoseconds(950.5), "0.000000950s")
|
||||
test(Duration.nanoseconds(85.23), "0.000000085s")
|
||||
test(Duration.nanoseconds(8.235), "0.000000008s")
|
||||
test(Duration.nanoseconds(1.3), "0.000000001s")
|
||||
|
||||
// equal to zero
|
||||
// test(Duration.nanoseconds(0.75), "0.75ns")
|
||||
@@ -586,9 +589,9 @@ class DurationTest {
|
||||
// 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")
|
||||
test(Duration.days(365) * 10000, "87600000h")
|
||||
test(Duration.days(300) * 100000, "720000000h")
|
||||
test(Duration.days(365) * 100000, "876000000h")
|
||||
|
||||
// all infinite
|
||||
// val universeAge = Duration.days(365.25) * 13.799e9
|
||||
|
||||
Reference in New Issue
Block a user