klock
一言で表すと
Kotlin/MPP向けの時間を扱うライブラリ
時間を表す型やそれを文字列にformatするメソッドなどを提供する。
概要
Current Time
code:kotlin
val utc = DateTime.now()
val local = DateTimeTz.nowLocal()
Unix Timestamp
code:kotlin
val unix = DateTime.now().unixMillis // or DateTime.nowUnix()
val date = DateTime.fromUnix(unix) // UTC date
Components
code:kotlin
val time = DateTime.now()
val year: Year = time.year
val year: Int = time.yearInt
val month: Month = time.month
val month0: Int = time.month0
val month1: Int = time.month1
val yearMonth: YearMonth = time.yearMonth
val dayOfMonth: Int = time.dayOfMonth
val dayOfWeek: DayOfWeek = time.dayOfWeek
val dayOfWeek: Int = time.dayOfWeekInt
val dayOfYear: Int = time.dayOfYear
val hours: Int = time.hours
val minutes: Int = time.minutes
val seconds: Int = time.seconds
val milliseconds: Int = time.milliseconds
Formating and Parsing Dates
code:kotlin
val dateFormat: DateFormat = DateFormat("EEE, dd MMM yyyy HH:mm:ss z") // Construct a new DateFormat from a String
val date: DateTimeTz = dateFormat.parse("Sat, 08 Sep 2018 04:08:09 UTC") // Parse a Date from a String
val dateStr: String = DateTime.now().format(dateFormat) // Format a Date using a specific DateFormat.
Mori Atsushi.icon 大事なやつ
TimeSpan
code:kotlin
val time = 1_000_000_000.nanoseconds
val time = 1_000_000.microseconds
val time = 1_000.milliseconds
val time = 1.seconds
val time = 0.5.seconds
val time = 60.minutes
val time = 24.hours
val time = 1.days
val time = 1.weeks
Mori Atsushi.icon こういうの、自分でも作りたくなっちゃう
Mori Atsushi.icon 返り値はTimeSpan型
中はmillisecondsのLog型っぽい
各プラットフォーム依存の実装を見てみる(一部抜粋)
JVM
code:kotlin
internal actual object KlockInternal {
actual val currentTime: Double get() = CurrentKlockInternalJvm.currentTime
actual val hrNow: HRTimeSpan get() = CurrentKlockInternalJvm.hrNow
actual fun localTimezoneOffsetMinutes(time: DateTime): TimeSpan = CurrentKlockInternalJvm.localTimezoneOffsetMinutes(time)
actual fun sleep(time: HRTimeSpan) {
val nanos = time.nanosecondsDouble.toLong()
Thread.sleep(nanos / 1_000_000, (nanos % 1_000_000).toInt())
}
}
interface KlockInternalJvm {
val currentTime: Double get() = (System.currentTimeMillis()).toDouble()
val microClock: Double get() = hrNow.microsecondsDouble
val hrNow: HRTimeSpan get() = HRTimeSpan.fromNanoseconds(System.nanoTime().toDouble())
fun localTimezoneOffsetMinutes(time: DateTime): TimeSpan = TimeZone.getDefault().getOffset(time.unixMillisLong).milliseconds
}
JS
code:kotlin
private val isNode = jsTypeOf(window) == "undefined"
private val initialHrTime by klockAtomicLazy { process.hrtime() }
internal actual object KlockInternal {
actual val currentTime: Double get() = (js("Date.now()").unsafeCast<Double>())
actual val hrNow: HRTimeSpan get() = when {
isNode -> {
val result: Array<Double> = process.hrtime(initialHrTime).unsafeCast<Array<Double>>()
HRTimeSpan.fromSeconds(result0) + HRTimeSpan.fromNanoseconds(result1) }
else -> {
HRTimeSpan.fromMilliseconds(window.performance.now())
}
}
actual fun localTimezoneOffsetMinutes(time: DateTime): TimeSpan {
@Suppress("UNUSED_VARIABLE")
val rtime = time.unixMillisDouble
return js("-(new Date(rtime)).getTimezoneOffset()").unsafeCast<Int>().minutes
}
actual fun sleep(time: HRTimeSpan) {
spinlock(time)
}
}
Posix
code:kotlin
internal actual object KlockInternal {
actual val currentTime: Double get() = memScoped {
val timeVal = alloc<timeval>()
gettimeofday(timeVal.ptr, null)
val sec = timeVal.tv_sec
val usec = timeVal.tv_usec
((sec * 1_000L) + (usec / 1_000L)).toDouble()
}
actual val hrNow: HRTimeSpan get() = memScoped {
val timeVal = alloc<timeval>()
gettimeofday(timeVal.ptr, null)
val sec = timeVal.tv_sec
val usec = timeVal.tv_usec
HRTimeSpan.fromSeconds(sec.toInt()) + HRTimeSpan.fromMicroseconds(usec.toInt())
}
actual fun sleep(time: HRTimeSpan) {
val micros = time.microsecondsDouble.toLong()
val s = micros / 1_000_000
val u = micros % 1_000_000
if (s > 0) platform.posix.sleep(s.convert())
if (u > 0) platform.posix.usleep(u.convert())
}
//private val microStart = kotlin.system.getTimeMicros()
//actual fun currentTimeMillis(): Long = kotlin.system.getTimeMillis()
//actual fun microClock(): Double = (kotlin.system.getTimeMicros() - microStart).toDouble()
actual fun localTimezoneOffsetMinutes(time: DateTime): TimeSpan = memScoped {
val t = alloc<time_tVar>()
val tm = alloc<tm>()
t.value = (time.unixMillisLong / 1000L).convert()
localtime_r(t.ptr, tm.ptr)
tm.tm_gmtoff.toInt().seconds
}
}
気になるポイント
メモ
commonでほとんどの部分を実装しつつ最小限のプラットフォーム依存の処理を各targetでしてて、プラットフォームの差異を吸収するライブラリとしては割と理想的なKotlin/MPPのプロジェクト構成になってるのでは?
普通にライブラリとして便利なのでMPPじゃなくても使っていいかも
Mori Atsushi.icon JVMでもJava系への依存を減らしていくのが良いのかな?
コメント
Go.icon1_000みたいなNumber型の使い方を知らなんだ