| /* |
| * 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. |
| */ |
| |
| @file:OptIn(ExperimentalTime::class) |
| @file:Suppress("INVISIBLE_MEMBER") |
| package test.time |
| |
| import test.numbers.assertAlmostEquals |
| import kotlin.math.nextDown |
| import kotlin.native.concurrent.SharedImmutable |
| import kotlin.test.* |
| import kotlin.time.* |
| import kotlin.random.* |
| |
| @SharedImmutable |
| private val units = DurationUnit.values() |
| |
| class DurationTest { |
| |
| @Test |
| fun constructionFromNumber() { |
| // 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).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).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).inWholeNanoseconds) |
| } |
| } |
| |
| for (unit in units) { |
| val borderValue = convertDurationUnit(MAX_NANOS, DurationUnit.NANOSECONDS, unit) |
| val d1 = borderValue.toDuration(unit) |
| val d2 = (borderValue + 1).toDuration(unit) |
| assertNotEquals(d1, d1 + Duration.nanoseconds(1)) |
| assertEquals(d2, d2 + Duration.nanoseconds(1)) |
| } |
| |
| 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)) |
| assertEquals(-Duration.INFINITE, (-MAX_MILLIS).toDuration(DurationUnit.MILLISECONDS)) |
| |
| run { |
| val maxNsDouble = MAX_NANOS.toDouble() |
| val lessThanMaxDouble = maxNsDouble.nextDown() |
| val maxNs = maxNsDouble.toDuration(DurationUnit.NANOSECONDS).inWholeNanoseconds |
| val lessThanMaxNs = lessThanMaxDouble.toDuration(DurationUnit.NANOSECONDS).inWholeNanoseconds |
| assertTrue(maxNs > lessThanMaxNs, "$maxNs should be > $lessThanMaxNs") |
| } |
| |
| assertFailsWith<IllegalArgumentException> { Double.NaN.toDuration(DurationUnit.SECONDS) } |
| } |
| |
| @Test |
| fun equality() { |
| val data = listOf<Pair<Double, DurationUnit>>( |
| Pair(2.0, DurationUnit.DAYS), |
| Pair(2.0, DurationUnit.HOURS), |
| Pair(0.25, DurationUnit.MINUTES), |
| Pair(1.0, DurationUnit.SECONDS), |
| Pair(50.0, DurationUnit.MILLISECONDS), |
| Pair(0.3, DurationUnit.MICROSECONDS), |
| Pair(20_000_000_000.0, DurationUnit.NANOSECONDS), |
| Pair(1.0, DurationUnit.NANOSECONDS) |
| ) |
| |
| for ((value, unit) in data) { |
| repeat(10) { |
| val d1 = value.toDuration(unit) |
| val unit2 = units.random() |
| val value2 = Duration.convert(value, unit, unit2) |
| val d2 = value2.toDuration(unit2) |
| assertEquals(d1, d2, "$value $unit in $unit2") |
| assertEquals(d1.hashCode(), d2.hashCode()) |
| |
| val d3 = (value2 * 2).toDuration(unit2) |
| assertNotEquals(d1, d3, "$value $unit in $unit2") |
| } |
| } |
| |
| 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.inWholeNanoseconds) |
| assertEquals(d1.inWholeNanoseconds, d2.inWholeNanoseconds) |
| assertEquals(d1, d2) |
| } |
| } |
| |
| @Test |
| fun comparison() { |
| fun assertGreater(d1: Duration, d2: Duration, message: String) { |
| assertTrue(d1 > d2, message) |
| assertFalse(d1 <= d2, message) |
| assertTrue( |
| d1.inWholeNanoseconds > d2.inWholeNanoseconds || |
| d1.inWholeNanoseconds == d2.inWholeNanoseconds && d1.inWholeMilliseconds > d2.inWholeMilliseconds, |
| message |
| ) |
| } |
| |
| val d4 = Duration.nanoseconds(Long.MAX_VALUE) |
| val d3 = Duration.nanoseconds(MAX_NANOS + 1) |
| val d2 = Duration.nanoseconds(MAX_NANOS) |
| val d1 = Duration.nanoseconds(MAX_NANOS - 1) |
| |
| assertGreater(d4, d2, "same sign, different ranges") |
| assertGreater(d3, d2, "same sign, different ranges 2") |
| assertGreater(d2, d1, "same sign, same range nanos") |
| assertGreater(d4, d3, "same sign, same range millis") |
| assertGreater(d2, -d3, "different signs, different ranges") |
| assertGreater(d3, -d4, "different signs, same ranges") |
| assertGreater(d1, -d2, "different signs, same ranges 2") |
| } |
| |
| |
| @Test |
| fun constructionFactoryFunctions() { |
| val n1 = Random.nextInt(Int.MAX_VALUE) |
| val n2 = Random.nextLong(Long.MAX_VALUE) |
| val n3 = Random.nextDouble() |
| |
| assertEquals(n1.toDuration(DurationUnit.DAYS), Duration.days(n1)) |
| assertEquals(n2.toDuration(DurationUnit.DAYS), Duration.days(n2)) |
| assertEquals(n3.toDuration(DurationUnit.DAYS), Duration.days(n3)) |
| |
| assertEquals(n1.toDuration(DurationUnit.HOURS), Duration.hours(n1)) |
| assertEquals(n2.toDuration(DurationUnit.HOURS), Duration.hours(n2)) |
| assertEquals(n3.toDuration(DurationUnit.HOURS), Duration.hours(n3)) |
| |
| assertEquals(n1.toDuration(DurationUnit.MINUTES), Duration.minutes(n1)) |
| assertEquals(n2.toDuration(DurationUnit.MINUTES), Duration.minutes(n2)) |
| assertEquals(n3.toDuration(DurationUnit.MINUTES), Duration.minutes(n3)) |
| |
| assertEquals(n1.toDuration(DurationUnit.SECONDS), Duration.seconds(n1)) |
| assertEquals(n2.toDuration(DurationUnit.SECONDS), Duration.seconds(n2)) |
| assertEquals(n3.toDuration(DurationUnit.SECONDS), Duration.seconds(n3)) |
| |
| assertEquals(n1.toDuration(DurationUnit.MILLISECONDS), Duration.milliseconds(n1)) |
| assertEquals(n2.toDuration(DurationUnit.MILLISECONDS), Duration.milliseconds(n2)) |
| assertEquals(n3.toDuration(DurationUnit.MILLISECONDS), Duration.milliseconds(n3)) |
| |
| assertEquals(n1.toDuration(DurationUnit.MICROSECONDS), Duration.microseconds(n1)) |
| assertEquals(n2.toDuration(DurationUnit.MICROSECONDS), Duration.microseconds(n2)) |
| assertEquals(n3.toDuration(DurationUnit.MICROSECONDS), Duration.microseconds(n3)) |
| |
| assertEquals(n1.toDuration(DurationUnit.NANOSECONDS), Duration.nanoseconds(n1)) |
| assertEquals(n2.toDuration(DurationUnit.NANOSECONDS), Duration.nanoseconds(n2)) |
| assertEquals(n3.toDuration(DurationUnit.NANOSECONDS), Duration.nanoseconds(n3)) |
| } |
| |
| @Test |
| fun conversionToNumber() { |
| 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 * 86400 * 1_000_000_000L, Duration.days(365).inWholeNanoseconds) |
| |
| assertEquals(0, Duration.ZERO.inWholeNanoseconds) |
| assertEquals(0, Duration.ZERO.inWholeMicroseconds) |
| assertEquals(0, Duration.ZERO.inWholeMilliseconds) |
| |
| 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) |
| val unit = units.random() |
| val unit2 = units.random() |
| |
| 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 |
| 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.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) |
| } |
| toComponents { minutes, seconds, nanoseconds -> |
| assertEquals(d * 1440 + h * 60 + m, minutes) |
| assertEquals(s, seconds) |
| assertEquals(ns, nanoseconds) |
| } |
| toComponents { hours, minutes, seconds, nanoseconds -> |
| assertEquals(d * 24 + h, hours) |
| assertEquals(m, minutes) |
| assertEquals(s, seconds) |
| assertEquals(ns, nanoseconds) |
| } |
| toComponents { days, hours, minutes, seconds, nanoseconds -> |
| assertEquals(d, days) |
| assertEquals(h, hours) |
| assertEquals(m, minutes) |
| assertEquals(s, seconds) |
| assertEquals(ns, nanoseconds) |
| } |
| } |
| } |
| } |
| |
| @Test |
| fun componentsOfCarriedSum() { |
| (Duration.hours(36) + Duration.minutes(90) + Duration.seconds(90) + Duration.milliseconds(1500)).run { |
| toComponents { days, hours, minutes, seconds, nanoseconds -> |
| assertEquals(1, days) |
| assertEquals(13, hours) |
| assertEquals(31, minutes) |
| assertEquals(31, seconds) |
| assertEquals(500_000_000, nanoseconds) |
| } |
| } |
| } |
| |
| @Test |
| fun infinite() { |
| assertTrue(Duration.INFINITE.isInfinite()) |
| assertTrue((-Duration.INFINITE).isInfinite()) |
| assertTrue(Duration.nanoseconds(Double.POSITIVE_INFINITY).isInfinite()) |
| |
| // seconds converted to nanoseconds overflow to infinite |
| assertTrue(Duration.seconds(Double.MAX_VALUE).isInfinite()) |
| assertTrue(Duration.seconds((-Double.MAX_VALUE)).isInfinite()) |
| } |
| |
| |
| @Test |
| fun negation() { |
| repeat(100) { |
| val value = Random.nextLong() |
| val unit = units.random() |
| |
| assertEquals((-value).toDuration(unit), -value.toDuration(unit)) |
| } |
| } |
| |
| @Test |
| fun signAndAbsoluteValue() { |
| val negative = -Duration.seconds(1) |
| val positive = Duration.seconds(1) |
| val zero = Duration.ZERO |
| |
| assertTrue(negative.isNegative()) |
| assertFalse(zero.isNegative()) |
| assertFalse(positive.isNegative()) |
| |
| assertFalse(negative.isPositive()) |
| assertFalse(zero.isPositive()) |
| assertTrue(positive.isPositive()) |
| |
| assertEquals(positive, negative.absoluteValue) |
| assertEquals(positive, positive.absoluteValue) |
| assertEquals(zero, zero.absoluteValue) |
| } |
| |
| @Test |
| fun negativeZero() { |
| fun equivalentToZero(value: Duration) { |
| assertEquals(Duration.ZERO, value) |
| assertEquals(Duration.ZERO, value.absoluteValue) |
| assertEquals(value, value.absoluteValue) |
| assertEquals(value, value.absoluteValue) |
| assertFalse(value.isNegative()) |
| assertFalse(value.isPositive()) |
| assertEquals(Duration.ZERO.toString(), value.toString()) |
| assertEquals(Duration.ZERO.toIsoString(), value.toIsoString()) |
| assertEquals(Duration.ZERO.toDouble(DurationUnit.SECONDS), value.toDouble(DurationUnit.SECONDS)) |
| assertEquals(0, Duration.ZERO.compareTo(value)) |
| assertEquals(0, Duration.ZERO.toDouble(DurationUnit.NANOSECONDS).compareTo(value.toDouble(DurationUnit.NANOSECONDS))) |
| } |
| equivalentToZero(Duration.seconds(-0.0)) |
| equivalentToZero((-0.0).toDuration(DurationUnit.DAYS)) |
| equivalentToZero(-Duration.ZERO) |
| equivalentToZero(Duration.seconds(-1) / Double.POSITIVE_INFINITY) |
| equivalentToZero(Duration.seconds(0) / -1) |
| equivalentToZero(Duration.seconds(-1) * 0.0) |
| equivalentToZero(Duration.seconds(0) * -1) |
| } |
| |
| |
| @Test |
| fun addition() { |
| assertEquals(Duration.hours(1.5), Duration.hours(1) + Duration.minutes(30)) |
| 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) } |
| } |
| |
| @Test |
| 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)) |
| assertEquals(Duration.milliseconds(-1), Duration.microseconds(Long.MAX_VALUE - 1_000) - Duration.microseconds(Long.MAX_VALUE)) |
| |
| run { |
| val offset = 2L * NANOS_IN_MILLIS |
| val value = MAX_NANOS + offset |
| val base = Duration.nanoseconds(value) |
| 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) { |
| 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, MAX_NANOS) } |
| for (deltaNs in deltas) { |
| val delta = Duration.nanoseconds(deltaNs) |
| assertEquals(deltaNs, delta.inWholeNanoseconds) |
| assertEquals(baseNs - deltaNs, (base - delta).inWholeNanoseconds, "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 } |
| } |
| |
| @Test |
| fun multiplication() { |
| assertEquals(Duration.days(1), Duration.hours(12) * 2) |
| assertEquals(Duration.days(1), Duration.minutes(60) * 24.0) |
| assertEquals(Duration.microseconds(1), Duration.nanoseconds(20) * 50) |
| |
| assertEquals(Duration.days(1), 2 * Duration.hours(12)) |
| assertEquals(Duration.hours(12.5), 12.5 * Duration.minutes(60)) |
| assertEquals(Duration.microseconds(1), 50 * Duration.nanoseconds(20)) |
| |
| assertEquals(Duration.ZERO, 0 * Duration.hours(1)) |
| assertEquals(Duration.ZERO, Duration.seconds(1) * 0.0) |
| |
| run { // promoting nanos range to millis range after multiplication |
| val value = MAX_NANOS |
| 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) |
| } |
| |
| run { |
| val value = MAX_NANOS / Int.MAX_VALUE |
| assertTrue((Duration.nanoseconds(value) * Int.MIN_VALUE).inWholeNanoseconds < -MAX_NANOS) |
| } |
| |
| assertEquals(Duration.INFINITE, Duration.days(Int.MAX_VALUE) * Int.MAX_VALUE) |
| assertEquals(-Duration.INFINITE, Duration.days(Int.MAX_VALUE) * Int.MIN_VALUE) |
| |
| 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.0 * Duration.INFINITE } |
| } |
| |
| @Test |
| fun divisionByNumber() { |
| assertEquals(Duration.hours(12), Duration.days(1) / 2) |
| assertEquals(Duration.minutes(60), Duration.days(1) / 24.0) |
| assertEquals(Duration.seconds(20), Duration.minutes(2) / 6) |
| assertEquals(Duration.days(365), Duration.days(365 * 299) / 299) |
| assertEquals(Duration.days(365), Duration.days(365 * 299.5) / 299.5) |
| |
| run { |
| val value = MAX_NANOS |
| assertEquals(value, (Duration.milliseconds(value) / 1_000_000).inWholeNanoseconds) |
| } |
| |
| 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 |
| fun divisionByDuration() { |
| 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()) |
| assertTrue((Duration.ZERO / Duration.ZERO).isNaN()) |
| } |
| |
| @Test |
| fun toIsoString() { |
| // zero |
| assertEquals("PT0S", Duration.ZERO.toIsoString()) |
| |
| // single unit |
| assertEquals("PT24H", Duration.days(1).toIsoString()) |
| assertEquals("PT1H", Duration.hours(1).toIsoString()) |
| assertEquals("PT1M", Duration.minutes(1).toIsoString()) |
| assertEquals("PT1S", Duration.seconds(1).toIsoString()) |
| assertEquals("PT0.001S", Duration.milliseconds(1).toIsoString()) |
| assertEquals("PT0.000001S", Duration.microseconds(1).toIsoString()) |
| assertEquals("PT0.000000001S", Duration.nanoseconds(1).toIsoString()) |
| |
| // rounded to zero |
| assertEquals("PT0S", Duration.nanoseconds(0.1).toIsoString()) |
| assertEquals("PT0S", Duration.nanoseconds(0.9).toIsoString()) |
| |
| // several units combined |
| assertEquals("PT24H1M", (Duration.days(1) + Duration.minutes(1)).toIsoString()) |
| assertEquals("PT24H0M1S", (Duration.days(1) + Duration.seconds(1)).toIsoString()) |
| assertEquals("PT24H0M0.001S", (Duration.days(1) + Duration.milliseconds(1)).toIsoString()) |
| assertEquals("PT1H30M", (Duration.hours(1) + Duration.minutes(30)).toIsoString()) |
| assertEquals("PT1H0M0.500S", (Duration.hours(1) + Duration.milliseconds(500)).toIsoString()) |
| assertEquals("PT2M0.500S", (Duration.minutes(2) + Duration.milliseconds(500)).toIsoString()) |
| assertEquals("PT1M30.500S", (Duration.milliseconds(90_500)).toIsoString()) |
| |
| // negative |
| assertEquals("-PT23H45M", (-Duration.days(1) + Duration.minutes(15)).toIsoString()) |
| assertEquals("-PT24H15M", (-Duration.days(1) - Duration.minutes(15)).toIsoString()) |
| |
| // infinite |
| assertEquals("PT2147483647H", Duration.INFINITE.toIsoString()) |
| } |
| |
| @Test |
| fun toStringInUnits() { |
| var d = with(Duration) { |
| days(1) + hours(15) + minutes(31) + seconds(45) + |
| milliseconds(678) + microseconds(920) + nanoseconds(516.34) |
| } |
| |
| fun test(unit: DurationUnit, vararg representations: String) { |
| assertFails { d.toString(unit, -1) } |
| assertEquals(representations.toList(), representations.indices.map { d.toString(unit, it) }) |
| } |
| |
| test(DurationUnit.DAYS, "2d", "1.6d", "1.65d", "1.647d") |
| test(DurationUnit.HOURS, "40h", "39.5h", "39.53h") |
| test(DurationUnit.MINUTES, "2372m", "2371.8m", "2371.76m") |
| d -= Duration.hours(39) |
| test(DurationUnit.SECONDS, "1906s", "1905.7s", "1905.68s", "1905.679s") |
| d -= Duration.seconds(1904) |
| test(DurationUnit.MILLISECONDS, "1679ms", "1678.9ms", "1678.92ms", "1678.921ms") |
| d -= Duration.milliseconds(1678) |
| test(DurationUnit.MICROSECONDS, "921us", "920.5us", "920.52us", "920.516us") |
| d -= Duration.microseconds(920) |
| // 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.00ns", "0.000ns", "0.0000ns") |
| |
| // 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)) |
| assertEquals("1.00e+14ns", Duration.seconds(100_000).toString(DurationUnit.NANOSECONDS, 9)) |
| |
| d = Duration.INFINITE |
| test(DurationUnit.DAYS, "Infinity", "Infinity") |
| d = -Duration.INFINITE |
| test(DurationUnit.NANOSECONDS, "-Infinity", "-Infinity") |
| } |
| |
| |
| @Test |
| fun toStringDefault() { |
| fun test(duration: Duration, vararg expectedOptions: String) { |
| val actual = duration.toString() |
| |
| if (!expectedOptions.contains(actual)) { |
| assertEquals<Any>(expectedOptions.toList(), duration.toString()) |
| } |
| if (duration > Duration.ZERO) |
| 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(40.5), "972h") |
| test(Duration.hours(40) + Duration.minutes(15), "40.3h", "40.2h") |
| test(Duration.hours(40), "40.0h") |
| |
| test(Duration.hours(12.5), "750m") |
| test(Duration.minutes(30), "30.0m") |
| test(Duration.minutes(17.5), "17.5m") |
| |
| 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.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.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.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") |
| |
| // 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") |
| |
| // 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(Duration.INFINITE, "Infinity") |
| } |
| |
| } |