Skip to content

Commit e117611

Browse files
authored
Remove kotlinx.datetime from JS target (#316)
Add JS actual implementation
1 parent 986142b commit e117611

File tree

11 files changed

+221
-22
lines changed

11 files changed

+221
-22
lines changed

gradle/libs.versions.toml

+2-2
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@ logback = "1.2.11"
55
okhttp = "4.12.0"
66
retrofit2 = "2.9.0"
77
nexus = "2.0.0"
8-
kotlin = "2.0.20"
8+
kotlin = "2.0.21"
99
vanniktech = "0.29.0"
1010
ktlint = "12.1.0"
1111
dokka = "1.9.20"
12-
kotlinx_datetime = "0.6.0"
12+
kotlinx_datetime = "0.6.1"
1313
kotlinx_coroutines = "1.8.1"
1414

1515
[libraries]

kotlin-js-store/yarn.lock

-5
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,6 @@
22
# yarn lockfile v1
33

44

5-
"@js-joda/[email protected]":
6-
version "3.2.0"
7-
resolved "https://registry.yarnpkg.com/@js-joda/core/-/core-3.2.0.tgz#3e61e21b7b2b8a6be746df1335cf91d70db2a273"
8-
integrity sha512-PMqgJ0sw5B7FKb2d5bWYIoxjri+QlW/Pys7+Rw82jSH0QN3rB05jZ/VrrsUdh1w4+i2kw9JOejXGq/KhDOX7Kg==
9-
105
"@tootallnate/quickjs-emscripten@^0.23.0":
116
version "0.23.0"
127
resolved "https://registry.yarnpkg.com/@tootallnate/quickjs-emscripten/-/quickjs-emscripten-0.23.0.tgz#db4ecfd499a9765ab24002c3b696d02e6d32a12c"

pubnub-kotlin/pubnub-kotlin-api/build.gradle.kts

+18
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import com.pubnub.gradle.enableAnyIosTarget
12
import com.pubnub.gradle.enableJsTarget
23

34
plugins {
@@ -17,7 +18,15 @@ kotlin {
1718
}
1819
}
1920

21+
val nonJs = create("nonJs") {
22+
dependsOn(commonMain)
23+
dependencies {
24+
api(libs.kotlinx.datetime)
25+
}
26+
}
27+
2028
val jvmMain by getting {
29+
dependsOn(nonJs)
2130
dependencies {
2231
api(libs.retrofit2)
2332
api(libs.okhttp)
@@ -28,6 +37,15 @@ kotlin {
2837
}
2938
}
3039

40+
if (enableAnyIosTarget) {
41+
val appleMain by getting {
42+
dependsOn(nonJs)
43+
dependencies {
44+
api(libs.kotlinx.datetime)
45+
}
46+
}
47+
}
48+
3149
if (enableJsTarget) {
3250
val jsMain by getting {
3351
dependencies {

pubnub-kotlin/pubnub-kotlin-api/src/commonMain/kotlin/com/pubnub/api/utils/TimetokenUtil.kt

-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
package com.pubnub.api.utils
22

3-
import kotlinx.datetime.Instant
4-
53
/**
64
* Utility object for converting PubNub timetokens to various date-time representations and vice versa.
75
*
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package com.pubnub.api.utils
2+
3+
import kotlin.time.Duration
4+
5+
expect class Instant : Comparable<Instant> {
6+
val epochSeconds: Long
7+
val nanosecondsOfSecond: Int
8+
9+
fun toEpochMilliseconds(): Long
10+
11+
operator fun plus(duration: Duration): Instant
12+
13+
operator fun minus(duration: Duration): Instant
14+
15+
operator fun minus(other: Instant): Duration
16+
17+
override operator fun compareTo(other: Instant): Int
18+
19+
companion object {
20+
fun fromEpochMilliseconds(epochMilliseconds: Long): Instant
21+
22+
fun fromEpochSeconds(epochSeconds: Long, nanosecondAdjustment: Int): Instant
23+
}
24+
}
25+
26+
expect interface Clock {
27+
fun now(): Instant
28+
29+
object System : Clock {
30+
override fun now(): Instant
31+
}
32+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
package com.pubnub.api.util
2+
3+
import com.pubnub.api.utils.Instant
4+
import kotlin.test.Test
5+
import kotlin.test.assertEquals
6+
import kotlin.test.assertTrue
7+
import kotlin.time.Duration.Companion.milliseconds
8+
import kotlin.time.Duration.Companion.nanoseconds
9+
import kotlin.time.Duration.Companion.seconds
10+
11+
class InstantTest {
12+
@Test
13+
fun plusDuration() {
14+
val nowMillis = 1732793616984
15+
val now = Instant.fromEpochMilliseconds(nowMillis)
16+
val later = now + 1500.milliseconds
17+
18+
assertEquals(nowMillis + 1500, later.toEpochMilliseconds())
19+
20+
val laterWithNanos = now + 2000.nanoseconds
21+
assertEquals(now.epochSeconds, laterWithNanos.epochSeconds)
22+
assertEquals(now.nanosecondsOfSecond + 2000, laterWithNanos.nanosecondsOfSecond)
23+
24+
val laterWithSecondsAndNanos = now + (1.seconds + 2000.nanoseconds)
25+
assertEquals(now.epochSeconds + 1, laterWithSecondsAndNanos.epochSeconds)
26+
assertEquals(now.nanosecondsOfSecond + 2000, laterWithSecondsAndNanos.nanosecondsOfSecond)
27+
}
28+
29+
@Test
30+
fun minusDuration() {
31+
val nowMillis = 1732793616984
32+
val now = Instant.fromEpochMilliseconds(nowMillis)
33+
val later = now - 1500.milliseconds
34+
35+
assertEquals(nowMillis - 1500, later.toEpochMilliseconds())
36+
37+
val laterWithNanos = now - 2000.nanoseconds
38+
assertEquals(now.epochSeconds, laterWithNanos.epochSeconds)
39+
assertEquals(now.nanosecondsOfSecond - 2000, laterWithNanos.nanosecondsOfSecond)
40+
41+
val laterWithSecondsAndNanos = now - (1.seconds + 2000.nanoseconds)
42+
assertEquals(now.epochSeconds - 1, laterWithSecondsAndNanos.epochSeconds)
43+
assertEquals(now.nanosecondsOfSecond - 2000, laterWithSecondsAndNanos.nanosecondsOfSecond)
44+
}
45+
46+
@Test
47+
fun minusInstant() {
48+
val nowMillis = 1732793616984
49+
val laterMillis = 1732793616984 + 1500
50+
val now = Instant.fromEpochMilliseconds(nowMillis)
51+
val later = Instant.fromEpochMilliseconds(laterMillis)
52+
53+
assertEquals(1500.milliseconds, later - now)
54+
assertEquals(-1500.milliseconds, now - later)
55+
}
56+
57+
@Test
58+
fun compareTo() {
59+
val nowMillis = 1732793616984
60+
val laterMillis = 1732793616984 + 1500
61+
val now = Instant.fromEpochMilliseconds(nowMillis)
62+
val later = Instant.fromEpochMilliseconds(laterMillis)
63+
64+
assertTrue(now < later)
65+
assertTrue(later > now)
66+
67+
assertTrue(now + 100.nanoseconds > now)
68+
assertTrue(now - 100.nanoseconds < now)
69+
}
70+
}

pubnub-kotlin/pubnub-kotlin-api/src/commonTest/kotlin/com/pubnub/api/util/TimetokenUtilsTest.kt

+3-12
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
package com.pubnub.api.util
22

3+
import com.pubnub.api.utils.Instant
34
import com.pubnub.api.utils.TimetokenUtil
4-
import kotlinx.datetime.Instant
5-
import kotlinx.datetime.TimeZone
6-
import kotlinx.datetime.toLocalDateTime
75
import kotlin.test.Test
86
import kotlin.test.assertEquals
97
import kotlin.test.assertFailsWith
@@ -19,9 +17,6 @@ class TimetokenUtilsTest {
1917
val timetokenResult = TimetokenUtil.instantToTimetoken(instant)
2018

2119
// then
22-
val localDateTimeInUTC = instant.toLocalDateTime(TimeZone.UTC)
23-
assertEquals("2024-09-30", localDateTimeInUTC.date.toString())
24-
assertEquals("11:24:20.623211800", localDateTimeInUTC.time.toString())
2520
assertEquals(timetoken, timetokenResult)
2621
}
2722

@@ -35,9 +30,7 @@ class TimetokenUtilsTest {
3530

3631
// then
3732
val instant: Instant = TimetokenUtil.timetokenToInstant(timetoken)
38-
val localDateTimeInUTC = instant.toLocalDateTime(TimeZone.UTC)
39-
assertEquals("2024-10-02", localDateTimeInUTC.date.toString())
40-
assertEquals("11:02:15.316", localDateTimeInUTC.time.toString())
33+
assertEquals(unixTime, instant.toEpochMilliseconds())
4134
}
4235

4336
@Test
@@ -59,8 +52,6 @@ class TimetokenUtilsTest {
5952

6053
// then
6154
val instant = Instant.fromEpochMilliseconds(unixTime)
62-
val toLocalDateTime = instant.toLocalDateTime(TimeZone.UTC)
63-
assertEquals("2024-09-30", toLocalDateTime.date.toString())
64-
assertEquals("11:24:20.623", toLocalDateTime.time.toString())
55+
assertEquals(timetoken / 10000 * 10000, TimetokenUtil.instantToTimetoken(instant))
6556
}
6657
}

pubnub-kotlin/pubnub-kotlin-api/src/commonTest/kotlin/com/pubnub/test/integration/MessageCountsTest.kt

+7
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,13 @@ package com.pubnub.test.integration
33
import com.pubnub.test.BaseIntegrationTest
44
import com.pubnub.test.await
55
import com.pubnub.test.randomString
6+
import kotlinx.coroutines.Dispatchers
7+
import kotlinx.coroutines.delay
68
import kotlinx.coroutines.test.runTest
9+
import kotlinx.coroutines.withContext
710
import kotlin.test.Test
811
import kotlin.test.assertEquals
12+
import kotlin.time.Duration.Companion.seconds
913

1014
class MessageCountsTest : BaseIntegrationTest() {
1115
private val channel = randomString()
@@ -35,6 +39,9 @@ class MessageCountsTest : BaseIntegrationTest() {
3539
).await().timetoken
3640
}
3741

42+
withContext(Dispatchers.Default) {
43+
delay(2.seconds)
44+
}
3845
val counts = pubnub.messageCounts(
3946
listOf(channel, otherChannel),
4047
listOf(timetokens.first() - 1, timetokensOther.first() - 1)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
package com.pubnub.api.utils
2+
3+
import kotlin.js.Date
4+
import kotlin.time.Duration
5+
import kotlin.time.Duration.Companion.milliseconds
6+
import kotlin.time.Duration.Companion.nanoseconds
7+
import kotlin.time.Duration.Companion.seconds
8+
9+
actual class Instant(
10+
actual val epochSeconds: Long,
11+
actual val nanosecondsOfSecond: Int = 0,
12+
) : Comparable<Instant> {
13+
actual fun toEpochMilliseconds(): Long {
14+
return epochSeconds.seconds.inWholeMilliseconds + nanosecondsOfSecond.nanoseconds.inWholeMilliseconds
15+
}
16+
17+
actual operator fun plus(duration: Duration): Instant {
18+
val durationWholeSecondsOnly = duration.inWholeSeconds.seconds
19+
val durationNanosOnly = duration - durationWholeSecondsOnly
20+
val sum = add(epochSeconds to nanosecondsOfSecond, duration.inWholeSeconds to durationNanosOnly.inWholeNanoseconds.toInt())
21+
return Instant(sum.first, sum.second)
22+
}
23+
24+
actual operator fun minus(duration: Duration): Instant {
25+
return plus(-duration)
26+
}
27+
28+
actual operator fun minus(other: Instant): Duration {
29+
return epochSeconds.seconds + nanosecondsOfSecond.nanoseconds - other.epochSeconds.seconds - other.nanosecondsOfSecond.nanoseconds
30+
}
31+
32+
actual override operator fun compareTo(other: Instant): Int {
33+
return epochSeconds.compareTo(other.epochSeconds)
34+
.takeIf { it != 0 }
35+
?: nanosecondsOfSecond.compareTo(other.nanosecondsOfSecond)
36+
}
37+
38+
private fun add(secondsAndNanos: SecondsAndNanos, secondsAndNanos2: SecondsAndNanos): Pair<Long, Int> {
39+
val nanosSum = secondsAndNanos.nanos + secondsAndNanos2.nanos
40+
val secondsFromNanos = nanosSum.inWholeSeconds.seconds
41+
42+
val secondsResult = secondsAndNanos.seconds + secondsAndNanos2.seconds + secondsFromNanos
43+
val nanosResult = nanosSum - secondsFromNanos
44+
return secondsResult.inWholeSeconds to nanosResult.inWholeNanoseconds.toInt()
45+
}
46+
47+
actual companion object {
48+
actual fun fromEpochMilliseconds(epochMilliseconds: Long): Instant {
49+
val wholeSeconds = epochMilliseconds.milliseconds.inWholeSeconds
50+
val nanos = (epochMilliseconds.milliseconds - wholeSeconds.seconds).inWholeNanoseconds
51+
return Instant(wholeSeconds, nanos.toInt())
52+
}
53+
54+
actual fun fromEpochSeconds(epochSeconds: Long, nanosecondAdjustment: Int): Instant {
55+
return Instant(epochSeconds, nanosecondAdjustment)
56+
}
57+
}
58+
}
59+
60+
actual interface Clock {
61+
actual fun now(): Instant
62+
63+
actual object System : Clock {
64+
actual override fun now(): Instant {
65+
return Instant.fromEpochMilliseconds(Date.now().toLong())
66+
}
67+
}
68+
}
69+
70+
typealias SecondsAndNanos = Pair<Long, Int>
71+
72+
val SecondsAndNanos.seconds get() = this.first.seconds
73+
val SecondsAndNanos.nanos get() = this.second.nanoseconds
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package com.pubnub.api.utils
2+
3+
import kotlinx.datetime.Clock
4+
import kotlinx.datetime.Instant
5+
6+
actual typealias Instant = Instant
7+
8+
actual interface Clock {
9+
actual fun now(): com.pubnub.api.utils.Instant
10+
11+
actual object System : com.pubnub.api.utils.Clock {
12+
actual override fun now(): com.pubnub.api.utils.Instant {
13+
return Clock.System.now()
14+
}
15+
}
16+
}

pubnub-kotlin/pubnub-kotlin-core-api/build.gradle.kts

-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ kotlin {
1212
val commonMain by getting {
1313
dependencies {
1414
implementation(libs.kotlinx.atomicfu)
15-
api(libs.kotlinx.datetime)
1615
}
1716
}
1817

0 commit comments

Comments
 (0)