MicroUtils/klock/src/mingwMain/kotlin/Klockinternal.mingw.kt

69 lines
3.7 KiB
Kotlin

package korlibs.time.internal
import korlibs.time.*
import kotlinx.cinterop.*
import platform.posix.mingw_gettimeofday
import platform.posix.timeval
import platform.windows.FILETIME
import platform.windows.FileTimeToSystemTime
import platform.windows.GetTimeZoneInformation
import platform.windows.SYSTEMTIME
import platform.windows.SystemTimeToFileTime
import platform.windows.SystemTimeToTzSpecificLocalTime
import platform.windows.TIME_ZONE_INFORMATION
import platform.windows.TzSpecificLocalTimeToSystemTime
@OptIn(ExperimentalForeignApi::class)
internal actual object KlockInternal {
actual val currentTime: Double
get() = memScoped {
val timeVal = alloc<timeval>()
mingw_gettimeofday(timeVal.ptr, null) // mingw: doesn't expose gettimeofday, but mingw_gettimeofday
val sec = timeVal.tv_sec
val usec = timeVal.tv_usec
((sec * 1_000L) + (usec / 1_000L)).toDouble()
}
actual val now: TimeSpan
get() = memScoped {
val timeVal = alloc<timeval>()
mingw_gettimeofday(timeVal.ptr, null)
val sec = timeVal.tv_sec
val usec = timeVal.tv_usec
TimeSpan.fromSeconds(sec) + TimeSpan.fromMicroseconds(usec)
}
actual fun localTimezoneOffsetMinutes(time: DateTime): TimeSpan = memScoped {
val timeAsFileTime = UnixMillisecondsToWindowsTicks(time.unixMillisLong)
val utcFtime = FILETIME_fromWindowsTicks(this, timeAsFileTime)
val timezone = getTimeZoneInformation(this)
val utcStime = utcFtime.toSystemTime(this)
val localStime = utcStime.toTimezone(this, timezone)
val localUnix = localStime.toFiletime(this).toUnix()
val utcUnix = utcStime.toFiletime(this).toUnix()
return (localUnix - utcUnix).milliseconds
}
actual fun sleep(time: TimeSpan) {
val micros = time.microseconds.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())
}
fun FILETIME_fromWindowsTicks(scope: NativePlacement, ticks: Long): FILETIME = scope.run { alloc<FILETIME>().apply { dwHighDateTime = (ticks ushr 32).toUInt(); dwLowDateTime = ticks.toUInt() } }
fun getTimeZoneInformation(scope: NativePlacement) = scope.run { alloc<TIME_ZONE_INFORMATION>().apply { GetTimeZoneInformation(this.ptr) } }
fun FILETIME.toSystemTime(scope: NativePlacement): SYSTEMTIME = scope.run { alloc<SYSTEMTIME>().apply { FileTimeToSystemTime(this@toSystemTime.ptr, this.ptr) } }
fun SYSTEMTIME.toTimezone(scope: NativePlacement, tzi: TIME_ZONE_INFORMATION): SYSTEMTIME = scope.run { alloc<SYSTEMTIME>().apply { SystemTimeToTzSpecificLocalTime(tzi.ptr, this@toTimezone.ptr, this.ptr) } }
fun SYSTEMTIME.toUtc(scope: NativePlacement, tzi: TIME_ZONE_INFORMATION): SYSTEMTIME = scope.run { alloc<SYSTEMTIME>().apply { TzSpecificLocalTimeToSystemTime(tzi.ptr, this@toUtc.ptr, this.ptr) } }
fun SYSTEMTIME.toFiletime(scope: NativePlacement): FILETIME = scope.run { alloc<FILETIME>().apply { SystemTimeToFileTime(this@toFiletime.ptr, this.ptr) } }
fun FILETIME.toWindowsTicks() = ((dwHighDateTime.toULong() shl 32) or (dwLowDateTime.toULong())).toLong()
fun FILETIME.toUnix() = WindowsTickToUnixMilliseconds(toWindowsTicks())
fun FILETIME_fromUnix(scope: NativePlacement, unix: Long): FILETIME = FILETIME_fromWindowsTicks(scope, UnixMillisecondsToWindowsTicks(unix))
const val WINDOWS_TICK = 10_000L
const val MS_TO_UNIX_EPOCH = 11644473600_000L
fun WindowsTickToUnixMilliseconds(windowsTicks: Long) = (windowsTicks / WINDOWS_TICK - MS_TO_UNIX_EPOCH)
fun UnixMillisecondsToWindowsTicks(unix: Long) = ((unix + MS_TO_UNIX_EPOCH) * WINDOWS_TICK)
}