Skip to content

Commit

Permalink
Re-work clock implementation (#118)
Browse files Browse the repository at this point in the history
* Re-work the clock implementation on JVM

* Re-work new clock implementation to handle Darwin

* Minor clean up
  • Loading branch information
erikc5000 authored Aug 5, 2020
1 parent 4206b12 commit 2fb942e
Show file tree
Hide file tree
Showing 34 changed files with 900 additions and 369 deletions.
5 changes: 5 additions & 0 deletions core/src/commonMain/kotlin/io/islandtime/Instant.kt
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@ import io.islandtime.measures.internal.plusWithOverflow
import io.islandtime.parser.*
import io.islandtime.ranges.InstantInterval

/**
* A platform-specific representation of an instant in time.
*/
expect class PlatformInstant

/**
* An instant in time with nanosecond precision.
*/
Expand Down
287 changes: 107 additions & 180 deletions core/src/commonMain/kotlin/io/islandtime/clock/Clock.kt
Original file line number Diff line number Diff line change
@@ -1,11 +1,21 @@
@file:Suppress("FunctionName", "UNUSED_PARAMETER")

package io.islandtime.clock

import io.islandtime.Instant
import io.islandtime.PlatformInstant
import io.islandtime.TimeZone
import io.islandtime.internal.deprecatedToError
import io.islandtime.measures.*

/**
* A time source.
*
* For an implementation that uses the system's clock, see [SystemClock]. [FixedClock] is also available for testing
* purposes.
*
* @see SystemClock
* @see FixedClock
*/
interface Clock {
/**
Expand All @@ -14,190 +24,107 @@ interface Clock {
val zone: TimeZone

/**
* Get the current number of milliseconds since the Unix epoch of 1970-01-01T00:00 in UTC.
* Reads the current number of milliseconds that have elapsed since the Unix epoch of `1970-01-01T00:00` in UTC.
*/
fun read(): LongMilliseconds
fun readMilliseconds(): LongMilliseconds

/**
* Get the current [Instant].
* Reads the current [Instant].
*/
fun instant(): Instant = Instant(read())
}

/**
* A clock that provides the time from the current system.
*
* The time zone is treated as an immutable property of the clock, set when it is created. If you wish to follow
* changes to the system clock's configured time zone, you must create a new [SystemClock] in response to any time zone
* changes.
*
* @constructor Create a [SystemClock] with a specific time zone, defaulting to the system's current zone.
* @see currentZone
*/
class SystemClock(override val zone: TimeZone = TimeZone.systemDefault()) : Clock {
override fun read() = PlatformSystemClock.read()

override fun equals(other: Any?): Boolean {
return other is SystemClock && zone == other.zone
}

override fun hashCode(): Int = zone.hashCode() + 1
override fun toString(): String = "SystemClock[$zone]"

companion object {
/**
* A system clock in the UTC time zone.
*/
val UTC = SystemClock(TimeZone.UTC)

/**
* Get the current system time zone.
*/
@Deprecated(
"Use TimeZone.systemDefault() instead.",
ReplaceWith("TimeZone.systemDefault()"),
DeprecationLevel.WARNING
)
fun currentZone(): TimeZone = TimeZone.systemDefault()
}
}

/**
* Platform system clock implementation
*/
internal expect object PlatformSystemClock {
fun read(): LongMilliseconds
}

/**
* A clock with fixed time, suitable for testing.
*/
class FixedClock(
private var millisecondsSinceUnixEpoch: LongMilliseconds = 0L.milliseconds,
override val zone: TimeZone = TimeZone.UTC
) : Clock {

operator fun plusAssign(days: LongDays) {
millisecondsSinceUnixEpoch += days
}

operator fun plusAssign(days: IntDays) {
millisecondsSinceUnixEpoch += days
}

operator fun plusAssign(hours: LongHours) {
millisecondsSinceUnixEpoch += hours
}

operator fun plusAssign(hours: IntHours) {
millisecondsSinceUnixEpoch += hours
}

operator fun plusAssign(minutes: LongMinutes) {
millisecondsSinceUnixEpoch += minutes
}

operator fun plusAssign(minutes: IntMinutes) {
millisecondsSinceUnixEpoch += minutes
}

operator fun plusAssign(seconds: LongSeconds) {
millisecondsSinceUnixEpoch += seconds
}
fun readInstant(): Instant

operator fun plusAssign(seconds: IntSeconds) {
millisecondsSinceUnixEpoch += seconds
}

operator fun plusAssign(milliseconds: LongMilliseconds) {
millisecondsSinceUnixEpoch += milliseconds
}

operator fun plusAssign(milliseconds: IntMilliseconds) {
millisecondsSinceUnixEpoch += milliseconds
}

operator fun minusAssign(days: LongDays) {
millisecondsSinceUnixEpoch -= days
}

operator fun minusAssign(days: IntDays) {
millisecondsSinceUnixEpoch -= days
}

operator fun minusAssign(hours: LongHours) {
millisecondsSinceUnixEpoch -= hours
}

operator fun minusAssign(hours: IntHours) {
millisecondsSinceUnixEpoch -= hours
}

operator fun minusAssign(minutes: LongMinutes) {
millisecondsSinceUnixEpoch -= minutes
}

operator fun minusAssign(minutes: IntMinutes) {
millisecondsSinceUnixEpoch -= minutes
}

operator fun minusAssign(seconds: LongSeconds) {
millisecondsSinceUnixEpoch -= seconds
}

operator fun minusAssign(seconds: IntSeconds) {
millisecondsSinceUnixEpoch -= seconds
}

operator fun minusAssign(milliseconds: LongMilliseconds) {
millisecondsSinceUnixEpoch -= milliseconds
}

operator fun minusAssign(milliseconds: IntMilliseconds) {
millisecondsSinceUnixEpoch -= milliseconds
}

override fun read(): LongMilliseconds {
return millisecondsSinceUnixEpoch
}

override fun equals(other: Any?): Boolean {
return other is FixedClock &&
millisecondsSinceUnixEpoch == other.millisecondsSinceUnixEpoch &&
zone == other.zone
}

override fun hashCode(): Int {
return 31 * millisecondsSinceUnixEpoch.hashCode() + zone.hashCode()
}

override fun toString(): String = "FixedClock[${instant()}, $zone]"
/**
* Reads the current [PlatformInstant].
*/
fun readPlatformInstant(): PlatformInstant
}

@Suppress("FunctionName")
fun FixedClock(days: LongDays, zone: TimeZone = TimeZone.UTC) = FixedClock(days.inMilliseconds, zone)

@Suppress("FunctionName")
fun FixedClock(days: IntDays, zone: TimeZone = TimeZone.UTC) = FixedClock(days.inMilliseconds, zone)

@Suppress("FunctionName")
fun FixedClock(hours: LongHours, zone: TimeZone = TimeZone.UTC) = FixedClock(hours.inMilliseconds, zone)

@Suppress("FunctionName")
fun FixedClock(hours: IntHours, zone: TimeZone = TimeZone.UTC) = FixedClock(hours.inMilliseconds, zone)

@Suppress("FunctionName")
fun FixedClock(minutes: LongMinutes, zone: TimeZone = TimeZone.UTC) = FixedClock(minutes.inMilliseconds, zone)

@Suppress("FunctionName")
fun FixedClock(minutes: IntMinutes, zone: TimeZone = TimeZone.UTC) = FixedClock(minutes.inMilliseconds, zone)

@Suppress("FunctionName")
fun FixedClock(seconds: LongSeconds, zone: TimeZone = TimeZone.UTC) = FixedClock(seconds.inMilliseconds, zone)

@Suppress("FunctionName")
fun FixedClock(seconds: IntSeconds, zone: TimeZone = TimeZone.UTC) = FixedClock(seconds.inMilliseconds, zone)

@Suppress("FunctionName")
fun FixedClock(milliseconds: IntMilliseconds, zone: TimeZone = TimeZone.UTC) =
FixedClock(milliseconds.toLongMilliseconds(), zone)
@Deprecated(
message = "Specify the instant explicitly.",
replaceWith = ReplaceWith(
"FixedClock(Instant(days.inSeconds), zone)",
"io.islandtime.Instant"
),
level = DeprecationLevel.ERROR
)
fun FixedClock(days: LongDays, zone: TimeZone = TimeZone.UTC): FixedClock = deprecatedToError()

@Deprecated(
message = "Specify the instant explicitly.",
replaceWith = ReplaceWith(
"FixedClock(Instant(days.toLong().inSeconds), zone)",
"io.islandtime.Instant"
),
level = DeprecationLevel.ERROR
)
fun FixedClock(days: IntDays, zone: TimeZone = TimeZone.UTC): FixedClock = deprecatedToError()

@Deprecated(
message = "Specify the instant explicitly.",
replaceWith = ReplaceWith(
"FixedClock(Instant(hours.inSeconds), zone)",
"io.islandtime.Instant"
),
level = DeprecationLevel.ERROR
)
fun FixedClock(hours: LongHours, zone: TimeZone = TimeZone.UTC): FixedClock = deprecatedToError()

@Deprecated(
message = "Specify the instant explicitly.",
replaceWith = ReplaceWith(
"FixedClock(Instant(hours.toLong().inSeconds), zone)",
"io.islandtime.Instant"
),
level = DeprecationLevel.ERROR
)
fun FixedClock(hours: IntHours, zone: TimeZone = TimeZone.UTC): FixedClock = deprecatedToError()

@Deprecated(
message = "Specify the instant explicitly.",
replaceWith = ReplaceWith(
"FixedClock(Instant(minutes.inSeconds), zone)",
"io.islandtime.Instant"
),
level = DeprecationLevel.ERROR
)
fun FixedClock(minutes: LongMinutes, zone: TimeZone = TimeZone.UTC): FixedClock = deprecatedToError()

@Deprecated(
message = "Specify the instant explicitly.",
replaceWith = ReplaceWith(
"FixedClock(Instant(minutes.toLong().inSeconds), zone)",
"io.islandtime.Instant"
),
level = DeprecationLevel.ERROR
)
fun FixedClock(minutes: IntMinutes, zone: TimeZone = TimeZone.UTC): FixedClock = deprecatedToError()

@Deprecated(
message = "Specify the instant explicitly.",
replaceWith = ReplaceWith(
"FixedClock(Instant(seconds), zone)",
"io.islandtime.Instant"
),
level = DeprecationLevel.ERROR
)
fun FixedClock(seconds: LongSeconds, zone: TimeZone = TimeZone.UTC): FixedClock = deprecatedToError()

@Deprecated(
message = "Specify the instant explicitly.",
replaceWith = ReplaceWith(
"FixedClock(Instant(seconds.toLongSeconds()), zone)",
"io.islandtime.Instant"
),
level = DeprecationLevel.ERROR
)
fun FixedClock(seconds: IntSeconds, zone: TimeZone = TimeZone.UTC): FixedClock = deprecatedToError()

@Deprecated(
message = "Specify the instant explicitly.",
replaceWith = ReplaceWith(
"FixedClock(Instant(milliseconds.toLongMilliseconds()), zone)",
"io.islandtime.Instant"
),
level = DeprecationLevel.ERROR
)
fun FixedClock(milliseconds: IntMilliseconds, zone: TimeZone = TimeZone.UTC): FixedClock = deprecatedToError()
Loading

0 comments on commit 2fb942e

Please sign in to comment.