Skip to content

Commit 73aad58

Browse files
authored
Add TimeSource.asClock converter (#164)
1 parent fbb2187 commit 73aad58

File tree

3 files changed

+70
-0
lines changed

3 files changed

+70
-0
lines changed

core/common/src/Clock.kt

+15
Original file line numberDiff line numberDiff line change
@@ -124,5 +124,20 @@ private class InstantTimeMark(private val instant: Instant, private val clock: C
124124
}
125125
}
126126

127+
/**
128+
* Creates a [Clock] that uses the [time mark at the moment of creation][TimeMark.markNow] to determine how [far][TimeMark.elapsedNow]
129+
* the [current moment][Clock.now] is from the [origin].
130+
*
131+
* This clock stores the [TimeMark] at the moment of creation, so repeatedly creating [Clock]s from the same [TimeSource] results
132+
* in different [Instant]s iff the time of the [TimeSource] was increased. To sync different [Clock]s, use the [origin]
133+
* parameter.
134+
*
135+
* @sample kotlinx.datetime.test.samples.ClockSamples.timeSourceAsClock
136+
*/
137+
public fun TimeSource.asClock(origin: Instant): Clock = object : Clock {
138+
private val startMark: TimeMark = markNow()
139+
override fun now() = origin + startMark.elapsedNow()
140+
}
141+
127142
@Deprecated("Use Clock.todayIn instead", ReplaceWith("this.todayIn(timeZone)"), DeprecationLevel.WARNING)
128143
public fun Clock.todayAt(timeZone: TimeZone): LocalDate = todayIn(timeZone)

core/common/test/ClockTimeSourceTest.kt

+38
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import kotlin.test.*
1010
import kotlin.time.*
1111
import kotlin.time.Duration.Companion.days
1212
import kotlin.time.Duration.Companion.nanoseconds
13+
import kotlin.time.Duration.Companion.seconds
1314

1415
@OptIn(ExperimentalTime::class)
1516
class ClockTimeSourceTest {
@@ -83,4 +84,41 @@ class ClockTimeSourceTest {
8384
assertFailsWith<IllegalArgumentException> { markFuture - Duration.INFINITE }
8485
assertFailsWith<IllegalArgumentException> { markPast + Duration.INFINITE }
8586
}
87+
88+
@Test
89+
fun timeSourceAsClock() {
90+
val timeSource = TestTimeSource()
91+
val clock = timeSource.asClock(origin = Instant.fromEpochSeconds(0))
92+
93+
assertEquals(Instant.fromEpochSeconds(0), clock.now())
94+
assertEquals(Instant.fromEpochSeconds(0), clock.now())
95+
96+
timeSource += 1.seconds
97+
assertEquals(Instant.fromEpochSeconds(1), clock.now())
98+
assertEquals(Instant.fromEpochSeconds(1), clock.now())
99+
}
100+
101+
@Test
102+
fun syncMultipleClocksFromTimeSource() {
103+
val timeSource = TestTimeSource()
104+
val clock1 = timeSource.asClock(origin = Instant.fromEpochSeconds(0))
105+
106+
assertEquals(0, clock1.now().epochSeconds)
107+
108+
timeSource += 1.seconds
109+
assertEquals(1, clock1.now().epochSeconds)
110+
111+
val clock2 = timeSource.asClock(origin = Instant.fromEpochSeconds(1))
112+
assertEquals(clock1.now(), clock2.now())
113+
114+
timeSource += 1.seconds
115+
assertEquals(2, clock1.now().epochSeconds)
116+
assertEquals(clock1.now(), clock2.now())
117+
118+
val clock3 = timeSource.asClock(origin = clock2.now())
119+
timeSource += 1.seconds
120+
assertEquals(3, clock3.now().epochSeconds)
121+
assertEquals(clock1.now(), clock2.now())
122+
assertEquals(clock1.now(), clock3.now())
123+
}
86124
}

core/common/test/samples/ClockSamples.kt

+17
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ package kotlinx.datetime.test.samples
77

88
import kotlinx.datetime.*
99
import kotlin.test.*
10+
import kotlin.time.Duration.Companion.seconds
11+
import kotlin.time.TestTimeSource
1012

1113
class ClockSamples {
1214
@Test
@@ -45,4 +47,19 @@ class ClockSamples {
4547
check(clock.todayIn(TimeZone.UTC) == LocalDate(2020, 1, 1))
4648
check(clock.todayIn(TimeZone.of("America/New_York")) == LocalDate(2019, 12, 31))
4749
}
50+
51+
@Test
52+
fun timeSourceAsClock() {
53+
// Creating a TimeSource
54+
// When testing a Clock in combination of kotlinx-coroutines-test, use the testTimeSource of the TestDispatcher.
55+
val timeSource = TestTimeSource()
56+
// Creating a clock by setting the origin, here the epoch start
57+
val clock = timeSource.asClock(origin = Instant.fromEpochSeconds(0))
58+
59+
check(Instant.fromEpochSeconds(0) == clock.now())
60+
61+
// Increasing the timeSource
62+
timeSource += 1.seconds
63+
check(Instant.fromEpochSeconds(1) == clock.now())
64+
}
4865
}

0 commit comments

Comments
 (0)