From 10238a23a1752beefd4344913045d4ab23d024b3 Mon Sep 17 00:00:00 2001 From: Jonathan Lennox Date: Wed, 4 Sep 2024 16:03:30 -0400 Subject: [PATCH] Add some helpers for Instant. --- src/main/kotlin/org/jitsi/utils/Instant.kt | 65 +++++++++++++++++++ .../kotlin/org/jitsi/utils/InstantTest.kt | 31 +++++++++ 2 files changed, 96 insertions(+) create mode 100644 src/main/kotlin/org/jitsi/utils/Instant.kt create mode 100644 src/test/kotlin/org/jitsi/utils/InstantTest.kt diff --git a/src/main/kotlin/org/jitsi/utils/Instant.kt b/src/main/kotlin/org/jitsi/utils/Instant.kt new file mode 100644 index 0000000..b990b88 --- /dev/null +++ b/src/main/kotlin/org/jitsi/utils/Instant.kt @@ -0,0 +1,65 @@ +/* + * Copyright @ 2018 - present 8x8, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jitsi.utils + +import java.time.Instant + +/** + * Helpers to create instances of [Instant] more easily, and Kotlin operators for it + */ + +/** + * Converts this instant to the number of microseconds from the epoch + * of 1970-01-01T00:00:00Z. + * + * + * If this instant represents a point on the time-line too far in the future + * or past to fit in a `long` microseconds, then an exception is thrown. + * + * If this instant has greater than microseconds precision, then the conversion + * will drop any excess precision information as though the amount in nanoseconds + * was subject to integer division by one thousand. + * + * @return the number of microseconds since the epoch of 1970-01-01T00:00:00Z + * @throws ArithmeticException if numeric overflow occurs + */ +fun Instant.toEpochMicro(): Long { + if (epochSecond < 0 && nano > 0) { + val millis = Math.multiplyExact(epochSecond + 1, 1_000_000).toLong() + val adjustment: Long = (nano / 1_000 - 1).toLong() + return Math.addExact(millis, adjustment) + } else { + val millis = Math.multiplyExact(epochSecond, 1_000_000).toLong() + return Math.addExact(millis, (nano / 1000).toLong()) + } +} + +/** + * Obtains an instance of {@code Instant} using microseconds from the + * epoch of 1970-01-01T00:00:00Z. + *

+ * The seconds and nanoseconds are extracted from the specified microseconds. + * + * @param epochMicro the number of microseconds from 1970-01-01T00:00:00Z + * @return an instant, not null + * @throws DateTimeException if the instant exceeds the maximum or minimum instant + */ +fun instantOfEpochMicro(epochMicro: Long): Instant { + val secs = Math.floorDiv(epochMicro, 1_000_000) + val mos = Math.floorMod(epochMicro, 1_000_000).toLong() + return Instant.ofEpochSecond(secs, mos * 1000) +} diff --git a/src/test/kotlin/org/jitsi/utils/InstantTest.kt b/src/test/kotlin/org/jitsi/utils/InstantTest.kt new file mode 100644 index 0000000..426021e --- /dev/null +++ b/src/test/kotlin/org/jitsi/utils/InstantTest.kt @@ -0,0 +1,31 @@ +/* + * Copyright @ 2018 - present 8x8, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jitsi.utils + +import io.kotest.core.spec.style.ShouldSpec +import io.kotest.matchers.shouldBe +import java.time.Instant + +class InstantTest : ShouldSpec() { + init { + context("The instant helpers should work") { + Instant.ofEpochMilli(123).toEpochMicro() shouldBe 123000L + instantOfEpochMicro(123456).toEpochMilli() shouldBe 123L + instantOfEpochMicro(123987).toEpochMilli() shouldBe 123L + } + } +}