Skip to content

Commit bcbd8af

Browse files
Abduqodiri QurbonzodaSpace Team
Abduqodiri Qurbonzoda
authored and
Space Team
committed
Move Instant and Clock from kotlinx-datetime to stdlib #KT-72480
1 parent c572e24 commit bcbd8af

File tree

30 files changed

+2314
-13
lines changed

30 files changed

+2314
-13
lines changed

kotlin-native/runtime/src/main/cpp/Porting.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,10 @@ uint64_t getTimeMicros() {
273273
return duration_cast<microseconds>(steady_time_clock::now().time_since_epoch()).count();
274274
}
275275

276+
uint64_t getSystemTimeNanos() {
277+
return duration_cast<nanoseconds>(system_clock::now().time_since_epoch()).count();
278+
}
279+
276280
bool isLittleEndian() {
277281
return __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__;
278282
}

kotlin-native/runtime/src/main/cpp/Porting.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ uintptr_t currentThreadId();
4545
uint64_t getTimeMillis();
4646
uint64_t getTimeMicros();
4747
uint64_t getTimeNanos();
48+
uint64_t getSystemTimeNanos();
4849

4950
// Endianness
5051
bool isLittleEndian();

kotlin-native/runtime/src/main/cpp/Time.cpp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,16 +20,20 @@
2020

2121
extern "C" {
2222

23-
KLong Kotlin_system_getTimeMillis() {
23+
KLong Kotlin_system_getSteadyTimeMillis() {
2424
return konan::getTimeMillis();
2525
}
2626

27-
KLong Kotlin_system_getTimeNanos() {
27+
KLong Kotlin_system_getSteadyTimeNanos() {
2828
return konan::getTimeNanos();
2929
}
3030

31-
KLong Kotlin_system_getTimeMicros() {
31+
KLong Kotlin_system_getSteadyTimeMicros() {
3232
return konan::getTimeMicros();
3333
}
3434

35+
KLong Kotlin_system_getSystemTimeNanos() {
36+
return konan::getSystemTimeNanos();
37+
}
38+
3539
} // extern "C"

kotlin-native/runtime/src/main/kotlin/kotlin/system/Timing.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ import kotlin.time.*
2222
*/
2323
@Deprecated("Use measureTime() or TimeSource.Monotonic.markNow() instead.")
2424
@DeprecatedSinceKotlin(warningSince = "1.9", errorSince = "2.1")
25-
@GCUnsafeCall("Kotlin_system_getTimeMillis")
25+
@GCUnsafeCall("Kotlin_system_getSteadyTimeMillis")
2626
public external fun getTimeMillis() : Long
2727

2828
/**
@@ -39,7 +39,7 @@ public external fun getTimeMillis() : Long
3939
*/
4040
@Deprecated("Use measureTime() or TimeSource.Monotonic.markNow() instead.")
4141
@DeprecatedSinceKotlin(warningSince = "1.9", errorSince = "2.1")
42-
@GCUnsafeCall("Kotlin_system_getTimeNanos")
42+
@GCUnsafeCall("Kotlin_system_getSteadyTimeNanos")
4343
public external fun getTimeNanos() : Long
4444

4545
/**
@@ -56,7 +56,7 @@ public external fun getTimeNanos() : Long
5656
*/
5757
@Deprecated("Use measureTime() or TimeSource.Monotonic.markNow() instead.")
5858
@DeprecatedSinceKotlin(warningSince = "1.9", errorSince = "2.1")
59-
@GCUnsafeCall("Kotlin_system_getTimeMicros")
59+
@GCUnsafeCall("Kotlin_system_getSteadyTimeMicros")
6060
public external fun getTimeMicros() : Long
6161

6262
/**
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/*
2+
* Copyright 2010-2024 JetBrains s.r.o. and Kotlin Programming Language contributors.
3+
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
4+
*/
5+
6+
package kotlin.time
7+
8+
import kotlin.native.internal.GCUnsafeCall
9+
10+
@ExperimentalTime
11+
internal actual fun systemClockNow(): Instant = getSystemTimeNanos().let { time ->
12+
// Instant.MAX and Instant.MIN are never going to be exceeded using just the Long number of nanoseconds
13+
Instant(time.floorDiv(NANOS_PER_SECOND.toLong()), time.mod(NANOS_PER_SECOND.toLong()).toInt())
14+
}
15+
16+
@GCUnsafeCall("Kotlin_system_getSystemTimeNanos")
17+
private external fun getSystemTimeNanos(): Long
18+
19+
@ExperimentalTime
20+
internal actual fun serializedInstant(instant: Instant): Any =
21+
throw UnsupportedOperationException("Serialization is supported only in Kotlin/JVM")

libraries/stdlib/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ val commonTestOptIns = listOf(
7777
"kotlin.ExperimentalStdlibApi",
7878
"kotlin.io.encoding.ExperimentalEncodingApi",
7979
"kotlin.uuid.ExperimentalUuidApi",
80+
"kotlin.time.ExperimentalTime",
8081
)
8182

8283
kotlin {

libraries/stdlib/jdk8/src/kotlin/internal/jdk8/JDK8PlatformImplementations.kt

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,10 @@ package kotlin.internal.jdk8
1919

2020
import java.util.regex.MatchResult
2121
import java.util.regex.Matcher
22-
import kotlin.internal.PlatformImplementations
2322
import kotlin.internal.jdk7.JDK7PlatformImplementations
2423
import kotlin.random.Random
2524
import kotlin.random.jdk8.PlatformThreadLocalRandom
25+
import kotlin.time.*
2626

2727
internal open class JDK8PlatformImplementations : JDK7PlatformImplementations() {
2828

@@ -57,4 +57,19 @@ internal open class JDK8PlatformImplementations : JDK7PlatformImplementations()
5757
// then.
5858
if (sdkIsNullOrAtLeast(34)) PlatformThreadLocalRandom() else super.defaultPlatformRandom()
5959

60+
@ExperimentalTime
61+
override fun getSystemClock(): Clock {
62+
// java.time.Instant is available since SDK 26
63+
return if (sdkIsNullOrAtLeast(26)) object : Clock {
64+
override fun now(): Instant =
65+
java.time.Instant.now().toKotlinInstant()
66+
} else object : Clock {
67+
override fun now(): Instant =
68+
// After experimenting in Android Studio, it seems like on Android with API < 26, only millisecond precision
69+
// is available in `Instant.now()` with core library desugaring enabled. Because of that, `currentTimeMillis`
70+
// is good enough + suggesting that our users enable core library desugaring isn't going to bring any benefits,
71+
// so the KDoc for [Clock] does not mention any of this.
72+
Instant.fromEpochMilliseconds(System.currentTimeMillis())
73+
}
74+
}
6075
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/*
2+
* Copyright 2010-2024 JetBrains s.r.o. and Kotlin Programming Language contributors.
3+
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
4+
*/
5+
6+
@file:JvmName("InstantConversionsJDK8Kt")
7+
@file:JvmPackageName("kotlin.time.jdk8")
8+
9+
package kotlin.time
10+
11+
12+
/**
13+
* Converts this [kotlin.time.Instant][Instant] value to a [java.time.Instant][java.time.Instant] value.
14+
*
15+
* @sample samples.time.Instants.toJavaInstant
16+
*/
17+
@SinceKotlin("2.1")
18+
@ExperimentalTime
19+
public fun Instant.toJavaInstant(): java.time.Instant =
20+
java.time.Instant.ofEpochSecond(epochSeconds, nanosecondsOfSecond.toLong())
21+
22+
/**
23+
* Converts this [java.time.Instant][java.time.Instant] value to a [kotlin.time.Instant][Instant] value.
24+
*
25+
* @sample samples.time.Instants.toKotlinInstant
26+
*/
27+
@SinceKotlin("2.1")
28+
@ExperimentalTime
29+
public fun java.time.Instant.toKotlinInstant(): Instant =
30+
Instant.fromEpochSeconds(epochSecond, nano)
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/*
2+
* Copyright 2010-2024 JetBrains s.r.o. and Kotlin Programming Language contributors.
3+
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
4+
*/
5+
6+
package kotlin.jdk8.time.test
7+
8+
import kotlin.time.*
9+
import kotlin.test.*
10+
import kotlin.random.*
11+
import java.time.Instant as JTInstant
12+
13+
class InstantConversionTest {
14+
@Test
15+
fun instant() {
16+
fun test(seconds: Long, nanosecond: Int) {
17+
val ktInstant = Instant.fromEpochSeconds(seconds, nanosecond.toLong())
18+
val jtInstant = JTInstant.ofEpochSecond(seconds, nanosecond.toLong())
19+
20+
assertEquals(ktInstant, jtInstant.toKotlinInstant())
21+
assertEquals(jtInstant, ktInstant.toJavaInstant())
22+
23+
assertEquals(ktInstant, jtInstant.toString().let(Instant::parse))
24+
assertEquals(jtInstant, ktInstant.toString().let(JTInstant::parse))
25+
}
26+
27+
repeat(100) {
28+
val seconds = Random.nextLong(1_000_000_000_000)
29+
val nanos = Random.nextInt()
30+
test(seconds, nanos)
31+
}
32+
}
33+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/*
2+
* Copyright 2010-2024 JetBrains s.r.o. and Kotlin Programming Language contributors.
3+
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
4+
*/
5+
6+
package kotlin.time
7+
8+
import kotlin.js.Date
9+
10+
/**
11+
* Converts the [Instant] to an instance of JS [Date].
12+
*
13+
* The conversion is lossy: JS uses millisecond precision to represent dates, and [Instant] allows for nanosecond
14+
* resolution.
15+
*/
16+
@SinceKotlin("2.1")
17+
@ExperimentalTime
18+
public fun Instant.toJSDate(): Date = Date(milliseconds = toEpochMilliseconds().toDouble())
19+
20+
/**
21+
* Converts the JS [Date] to the corresponding [Instant].
22+
*/
23+
@SinceKotlin("2.1")
24+
@ExperimentalTime
25+
public fun Date.toKotlinInstant(): Instant = Instant.fromEpochMilliseconds(getTime().toLong())
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
/*
2+
* Copyright 2010-2024 JetBrains s.r.o. and Kotlin Programming Language contributors.
3+
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
4+
*/
5+
6+
package kotlin.time
7+
8+
import kotlin.js.Date
9+
10+
@ExperimentalTime
11+
internal actual fun systemClockNow(): Instant =
12+
Instant.fromEpochMilliseconds(Date().getTime().toLong())
13+
14+
@ExperimentalTime
15+
internal actual fun serializedInstant(instant: Instant): Any =
16+
throw UnsupportedOperationException("Serialization is supported only in Kotlin/JVM")
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/*
2+
* Copyright 2010-2024 JetBrains s.r.o. and Kotlin Programming Language contributors.
3+
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
4+
*/
5+
6+
package test.time
7+
8+
import kotlin.js.Date
9+
import kotlin.test.*
10+
import kotlin.time.*
11+
12+
class InstantConversionTest {
13+
@Test
14+
fun toJSDateTest() {
15+
val releaseInstant = Instant.parse("2016-02-15T00:00:00Z")
16+
val releaseDate = releaseInstant.toJSDate()
17+
assertEquals(2016, releaseDate.getUTCFullYear())
18+
assertEquals(1, releaseDate.getUTCMonth())
19+
assertEquals(15, releaseDate.getUTCDate())
20+
}
21+
22+
@Test
23+
fun toInstantTest() {
24+
val kotlinReleaseEpochMilliseconds = 1455494400000
25+
val releaseDate = Date(milliseconds = kotlinReleaseEpochMilliseconds)
26+
val releaseInstant = Instant.parse("2016-02-15T00:00:00Z")
27+
assertEquals(releaseInstant, releaseDate.toKotlinInstant())
28+
}
29+
}

libraries/stdlib/jvm/src/kotlin/internal/PlatformImplementations.kt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ import java.lang.reflect.Method
99
import java.util.regex.MatchResult
1010
import kotlin.random.FallbackThreadLocalRandom
1111
import kotlin.random.Random
12+
import kotlin.time.Clock
13+
import kotlin.time.ExperimentalTime
1214

1315
internal open class PlatformImplementations {
1416

@@ -43,6 +45,11 @@ internal open class PlatformImplementations {
4345
}
4446

4547
public open fun defaultPlatformRandom(): Random = FallbackThreadLocalRandom()
48+
49+
@ExperimentalTime
50+
public open fun getSystemClock(): Clock {
51+
throw UnsupportedOperationException("getSystemClock should not be called on the base PlatformImplementations.")
52+
}
4653
}
4754

4855

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/*
2+
* Copyright 2010-2024 JetBrains s.r.o. and Kotlin Programming Language contributors.
3+
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
4+
*/
5+
6+
package kotlin.time
7+
8+
import java.io.*
9+
import kotlin.internal.IMPLEMENTATIONS
10+
11+
@ExperimentalTime
12+
private val systemClock: Clock = IMPLEMENTATIONS.getSystemClock()
13+
14+
@ExperimentalTime
15+
internal actual fun systemClockNow(): Instant = systemClock.now()
16+
17+
@ExperimentalTime
18+
private class InstantSerialized(
19+
var epochSeconds: Long,
20+
var nanosecondsOfSecond: Int
21+
) : Externalizable {
22+
23+
constructor() : this(0L, 0) // for deserialization
24+
25+
override fun writeExternal(output: ObjectOutput) {
26+
output.writeLong(epochSeconds)
27+
output.writeInt(nanosecondsOfSecond)
28+
}
29+
30+
override fun readExternal(input: ObjectInput) {
31+
epochSeconds = input.readLong()
32+
nanosecondsOfSecond = input.readInt()
33+
}
34+
35+
private fun readResolve(): Any =
36+
Instant.fromEpochSeconds(epochSeconds, nanosecondsOfSecond)
37+
38+
companion object {
39+
private const val serialVersionUID: Long = 0L
40+
}
41+
}
42+
43+
@ExperimentalTime
44+
internal actual fun serializedInstant(instant: Instant): Any =
45+
InstantSerialized(instant.epochSeconds, instant.nanosecondsOfSecond)
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/*
2+
* Copyright 2010-2024 JetBrains s.r.o. and Kotlin Programming Language contributors.
3+
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
4+
*/
5+
6+
package test.time
7+
8+
import test.io.serializeAndDeserialize
9+
import kotlin.test.*
10+
import kotlin.time.Instant
11+
12+
class InstantJVMTest {
13+
@Test
14+
fun serialize() {
15+
listOf(
16+
Instant.MIN,
17+
Instant.MAX,
18+
Instant.DISTANT_PAST,
19+
Instant.DISTANT_FUTURE,
20+
Instant.fromEpochSeconds(0),
21+
Instant.fromEpochSeconds(1, 1),
22+
Instant.fromEpochSeconds(-1, 1),
23+
).forEach {
24+
assertEquals(it, serializeAndDeserialize(it))
25+
}
26+
}
27+
}

libraries/stdlib/samples/build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ compileTestKotlin {
1414
optIn.addAll([
1515
"kotlin.ExperimentalStdlibApi",
1616
"kotlin.ExperimentalUnsignedTypes",
17+
"kotlin.time.ExperimentalTime",
1718
])
1819
}
1920
}

0 commit comments

Comments
 (0)