Skip to content

Commit f81909e

Browse files
committed
Copy Instant.kt to kotlinx.time
1 parent 98c3e53 commit f81909e

File tree

6 files changed

+1149
-0
lines changed

6 files changed

+1149
-0
lines changed

fake-kotlinx-time/build.gradle.kts

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
import java.util.Locale
2+
3+
plugins {
4+
id("kotlin-multiplatform")
5+
id("org.jetbrains.kotlinx.kover")
6+
}
7+
8+
val mainJavaToolchainVersion: String by project
9+
val serializationVersion: String by project
10+
11+
java {
12+
toolchain { languageVersion.set(JavaLanguageVersion.of(mainJavaToolchainVersion)) }
13+
}
14+
15+
kotlin {
16+
17+
// Tiers are in accordance with <https://kotlinlang.org/docs/native-target-support.html>
18+
// Tier 1
19+
macosX64()
20+
macosArm64()
21+
iosSimulatorArm64()
22+
iosX64()
23+
iosArm64()
24+
// Tier 2
25+
linuxX64()
26+
linuxArm64()
27+
watchosSimulatorArm64()
28+
watchosX64()
29+
watchosArm32()
30+
watchosArm64()
31+
tvosSimulatorArm64()
32+
tvosX64()
33+
tvosArm64()
34+
// Tier 3
35+
androidNativeArm32()
36+
androidNativeArm64()
37+
androidNativeX86()
38+
androidNativeX64()
39+
mingwX64()
40+
watchosDeviceArm64()
41+
// Deprecated
42+
@Suppress("DEPRECATION") linuxArm32Hfp()
43+
44+
applyDefaultHierarchyTemplate()
45+
46+
jvm {
47+
attributes {
48+
attribute(TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, 8)
49+
}
50+
}
51+
52+
js {
53+
nodejs {
54+
}
55+
compilations.all {
56+
kotlinOptions {
57+
sourceMap = true
58+
moduleKind = "umd"
59+
}
60+
}
61+
}
62+
63+
64+
wasmJs {
65+
nodejs {
66+
}
67+
}
68+
69+
wasmWasi {
70+
nodejs {
71+
}
72+
}
73+
74+
sourceSets.all {
75+
val suffixIndex = name.indexOfLast { it.isUpperCase() }
76+
val targetName = name.substring(0, suffixIndex)
77+
val suffix = name.substring(suffixIndex).toLowerCase(Locale.ROOT).takeIf { it != "main" }
78+
kotlin.srcDir("$targetName/${suffix ?: "src"}")
79+
resources.srcDir("$targetName/${suffix?.let { it + "Resources" } ?: "resources"}")
80+
}
81+
82+
targets.withType<org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget> {
83+
compilations["test"].kotlinOptions {
84+
freeCompilerArgs += listOf("-trw")
85+
}
86+
}
87+
88+
sourceSets {
89+
commonMain {
90+
dependencies {
91+
}
92+
}
93+
94+
commonTest {
95+
dependencies {
96+
api("org.jetbrains.kotlin:kotlin-test")
97+
api("org.jetbrains.kotlinx:kotlinx-serialization-json:$serializationVersion")
98+
}
99+
}
100+
}
101+
}

fake-kotlinx-time/common/src/Clock.kt

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
/*
2+
* Copyright 2019-2020 JetBrains s.r.o.
3+
* Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file.
4+
*/
5+
6+
package kotlinx.datetime
7+
8+
import kotlin.time.*
9+
10+
/**
11+
* A source of [Instant] values.
12+
*
13+
* See [Clock.System][Clock.System] for the clock instance that queries the operating system.
14+
*
15+
* It is not recommended to use [Clock.System] directly in the implementation. Instead, you can pass a
16+
* [Clock] explicitly to the necessary functions or classes.
17+
* This way, tests can be written deterministically by providing custom [Clock] implementations
18+
* to the system under test.
19+
*/
20+
public interface Clock {
21+
/**
22+
* Returns the [Instant] corresponding to the current time, according to this clock.
23+
*
24+
* Calling [now] later is not guaranteed to return a larger [Instant].
25+
* In particular, for [Clock.System], the opposite is completely expected,
26+
* and it must be taken into account.
27+
* See the [System] documentation for details.
28+
*
29+
* Even though [Instant] is defined to be on the UTC-SLS time scale, which enforces a specific way of handling
30+
* leap seconds, [now] is not guaranteed to handle leap seconds in any specific way.
31+
*/
32+
public fun now(): Instant
33+
34+
/**
35+
* The [Clock] instance that queries the platform-specific system clock as its source of time knowledge.
36+
*
37+
* Successive calls to [now] will not necessarily return increasing [Instant] values, and when they do,
38+
* these increases will not necessarily correspond to the elapsed time.
39+
*
40+
* For example, when using [Clock.System], the following could happen:
41+
* - [now] returns `2023-01-02T22:35:01Z`.
42+
* - The system queries the Internet and recognizes that its clock needs adjusting.
43+
* - [now] returns `2023-01-02T22:32:05Z`.
44+
*
45+
* When you need predictable intervals between successive measurements, consider using [TimeSource.Monotonic].
46+
*
47+
* For improved testability, you should avoid using [Clock.System] directly in the implementation
48+
* and pass a [Clock] explicitly instead. For example:
49+
*
50+
* @sample kotlinx.datetime.test.samples.ClockSamples.system
51+
* @sample kotlinx.datetime.test.samples.ClockSamples.dependencyInjection
52+
*/
53+
public object System : Clock {
54+
override fun now(): Instant = @Suppress("DEPRECATION_ERROR") Instant.now()
55+
}
56+
57+
/** A companion object used purely for namespacing. */
58+
public companion object {
59+
60+
}
61+
}
62+
63+
/**
64+
* Returns the current date at the given [time zone][timeZone], according to [this Clock][this].
65+
*
66+
* The time zone is important because the current date is not the same in all time zones at the same instant.
67+
*
68+
* @sample kotlinx.datetime.test.samples.ClockSamples.todayIn
69+
*/
70+
public fun Clock.todayIn(timeZone: TimeZone): LocalDate =
71+
now().toLocalDateTime(timeZone).date
72+
73+
/**
74+
* Returns a [TimeSource] that uses this [Clock] to mark a time instant and to find the amount of time elapsed since that mark.
75+
*
76+
* **Pitfall**: using this function with [Clock.System] is error-prone
77+
* because [Clock.System] is not well suited for measuring time intervals.
78+
* Please only use this conversion function on the [Clock] instances that are fully controlled programmatically.
79+
*/
80+
@ExperimentalTime
81+
public fun Clock.asTimeSource(): TimeSource.WithComparableMarks = object : TimeSource.WithComparableMarks {
82+
override fun markNow(): ComparableTimeMark = InstantTimeMark(now(), this@asTimeSource)
83+
}
84+
85+
@ExperimentalTime
86+
private class InstantTimeMark(private val instant: Instant, private val clock: Clock) : ComparableTimeMark {
87+
override fun elapsedNow(): Duration = saturatingDiff(clock.now(), instant)
88+
89+
override fun plus(duration: Duration): ComparableTimeMark = InstantTimeMark(instant.saturatingAdd(duration), clock)
90+
override fun minus(duration: Duration): ComparableTimeMark = InstantTimeMark(instant.saturatingAdd(-duration), clock)
91+
92+
override fun minus(other: ComparableTimeMark): Duration {
93+
if (other !is InstantTimeMark || other.clock != this.clock) {
94+
throw IllegalArgumentException("Subtracting or comparing time marks from different time sources is not possible: $this and $other")
95+
}
96+
return saturatingDiff(this.instant, other.instant)
97+
}
98+
99+
override fun equals(other: Any?): Boolean {
100+
return other is InstantTimeMark && this.clock == other.clock && this.instant == other.instant
101+
}
102+
103+
override fun hashCode(): Int = instant.hashCode()
104+
105+
override fun toString(): String = "InstantTimeMark($instant, $clock)"
106+
107+
private fun Instant.isSaturated() = this == Instant.MAX || this == Instant.MIN
108+
private fun Instant.saturatingAdd(duration: Duration): Instant {
109+
if (isSaturated()) {
110+
if (duration.isInfinite() && duration.isPositive() != this.isDistantFuture) {
111+
throw IllegalArgumentException("Summing infinities of different signs")
112+
}
113+
return this
114+
}
115+
return this + duration
116+
}
117+
private fun saturatingDiff(instant1: Instant, instant2: Instant): Duration = when {
118+
instant1 == instant2 ->
119+
Duration.ZERO
120+
instant1.isSaturated() || instant2.isSaturated() ->
121+
(instant1 - instant2) * Double.POSITIVE_INFINITY
122+
else ->
123+
instant1 - instant2
124+
}
125+
}
126+
127+
@Deprecated("Use Clock.todayIn instead", ReplaceWith("this.todayIn(timeZone)"), DeprecationLevel.WARNING)
128+
public fun Clock.todayAt(timeZone: TimeZone): LocalDate = todayIn(timeZone)

0 commit comments

Comments
 (0)