CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-org-jetbrains-kotlin--kotlin-stdlib-wasm-wasi

Kotlin Standard Library implementation for WebAssembly System Interface (WASI) platform providing essential I/O, time, random, UUID, and reflection capabilities.

Pending
Overview
Eval results
Files

time.mddocs/

Time and Duration Handling

Overview

The Time and Duration capabilities provide WASI-specific implementations for time sources, clock access, and duration measurements. These implementations use the WASI clock_time_get system call to access both monotonic and real-time clocks available in the WASI environment.

API Reference

Monotonic Time Source

/**
 * A monotonic time source that provides elapsed time measurements.
 * Uses WASI's clock_time_get with CLOCK_MONOTONIC.
 */
object TimeSource.Monotonic : TimeSource {
    /**
     * Marks the current point in time for later measurement.
     * @return a TimeMark representing the current time
     */
    fun markNow(): TimeMark
}

System Clock

/**
 * The system clock that provides access to the current date and time.
 * Uses WASI's clock_time_get with CLOCK_REALTIME.  
 */
object Clock.System : Clock {
    /**
     * Returns the current moment in time.
     * @return the current Instant
     */
    fun now(): Instant
}

Duration Operations

/**
 * Represents a time-based amount of time.
 */
@SinceKotlin("1.6")
@JvmInline
value class Duration internal constructor(private val rawValue: Long) : Comparable<Duration> {
    companion object {
        val ZERO: Duration
        val INFINITE: Duration
        
        fun parse(value: String): Duration
        fun parseIsoString(value: String): Duration
        fun parseOrNull(value: String): Duration?
        fun parseIsoStringOrNull(value: String): Duration?
        fun convert(value: Double, sourceUnit: DurationUnit, targetUnit: DurationUnit): Double
    }
    
    // Arithmetic operations
    operator fun unaryMinus(): Duration
    operator fun plus(other: Duration): Duration
    operator fun minus(other: Duration): Duration  
    operator fun times(scale: Int): Duration
    operator fun times(scale: Double): Duration
    operator fun div(scale: Int): Duration
    operator fun div(scale: Double): Duration
    operator fun div(other: Duration): Double
    
    // Properties and checks
    fun isNegative(): Boolean
    fun isPositive(): Boolean
    fun isInfinite(): Boolean
    fun isFinite(): Boolean
    val absoluteValue: Duration
    
    // Component extraction
    inline fun <T> toComponents(action: (days: Long, hours: Int, minutes: Int, seconds: Int, nanoseconds: Int) -> T): T
    inline fun <T> toComponents(action: (hours: Long, minutes: Int, seconds: Int, nanoseconds: Int) -> T): T
    inline fun <T> toComponents(action: (minutes: Long, seconds: Int, nanoseconds: Int) -> T): T
    inline fun <T> toComponents(action: (seconds: Long, nanoseconds: Int) -> T): T
    
    // Conversion to units
    fun toDouble(unit: DurationUnit): Double
    fun toLong(unit: DurationUnit): Long
    fun toInt(unit: DurationUnit): Int
    val inWholeDays: Long
    val inWholeHours: Long
    val inWholeMinutes: Long
    val inWholeSeconds: Long
    val inWholeMilliseconds: Long
    val inWholeMicroseconds: Long
    val inWholeNanoseconds: Long
    
    // String representation
    override fun toString(): String
    fun toString(unit: DurationUnit, decimals: Int = 0): String
    fun toIsoString(): String
    
    override operator fun compareTo(other: Duration): Int
}

/**
 * Duration unit enumeration
 */
@WasExperimental(ExperimentalTime::class)
enum class DurationUnit {
    NANOSECONDS,
    MICROSECONDS, 
    MILLISECONDS,
    SECONDS,
    MINUTES,
    HOURS,
    DAYS
}

/**
 * Duration construction extensions
 */
val Int.nanoseconds: Duration
val Long.nanoseconds: Duration
val Double.nanoseconds: Duration
val Int.microseconds: Duration
val Long.microseconds: Duration
val Double.microseconds: Duration
val Int.milliseconds: Duration
val Long.milliseconds: Duration
val Double.milliseconds: Duration
val Int.seconds: Duration
val Long.seconds: Duration
val Double.seconds: Duration
val Int.minutes: Duration
val Long.minutes: Duration
val Double.minutes: Duration
val Int.hours: Duration
val Long.hours: Duration
val Double.hours: Duration
val Int.days: Duration
val Long.days: Duration
val Double.days: Duration

Instant Operations

/**
 * Represents an instantaneous point on the time-line.
 */
@SinceKotlin("2.1")
@ExperimentalTime
class Instant internal constructor(
    val epochSeconds: Long,
    val nanosecondsOfSecond: Int
) : Comparable<Instant>, Serializable {
    
    companion object {
        // Construction
        fun fromEpochMilliseconds(epochMilliseconds: Long): Instant
        fun fromEpochSeconds(epochSeconds: Long, nanosecondAdjustment: Long = 0): Instant  
        fun fromEpochSeconds(epochSeconds: Long, nanosecondAdjustment: Int): Instant
        
        // Parsing
        fun parse(input: CharSequence): Instant
        fun parseOrNull(input: CharSequence): Instant?
        
        // Constants
        val DISTANT_PAST: Instant
        val DISTANT_FUTURE: Instant
    }
    
    // Properties
    fun toEpochMilliseconds(): Long
    val isDistantPast: Boolean
    val isDistantFuture: Boolean
    
    // Arithmetic operations
    operator fun plus(duration: Duration): Instant
    operator fun minus(duration: Duration): Instant
    operator fun minus(other: Instant): Duration
    
    // Comparison and equality
    override operator fun compareTo(other: Instant): Int
    override fun equals(other: Any?): Boolean
    override fun hashCode(): Int
    override fun toString(): String // ISO 8601 format
}

/**
 * TimeMark interfaces for time measurement
 */
@SinceKotlin("1.9")
@WasExperimental(ExperimentalTime::class)
interface TimeMark {
    fun elapsedNow(): Duration
    operator fun plus(duration: Duration): TimeMark
    operator fun minus(duration: Duration): TimeMark
    fun hasPassedNow(): Boolean
    fun hasNotPassedNow(): Boolean
}

@SinceKotlin("1.9")
@WasExperimental(ExperimentalTime::class)
interface ComparableTimeMark : TimeMark, Comparable<ComparableTimeMark> {
    override operator fun plus(duration: Duration): ComparableTimeMark
    override operator fun minus(duration: Duration): ComparableTimeMark
    operator fun minus(other: ComparableTimeMark): Duration
    override operator fun compareTo(other: ComparableTimeMark): Int
    override fun equals(other: Any?): Boolean
    override fun hashCode(): Int
}

/**
 * Time measurement utility functions  
 */
inline fun measureTime(block: () -> Unit): Duration
inline fun TimeSource.measureTime(block: () -> Unit): Duration
inline fun TimeSource.Monotonic.measureTime(block: () -> Unit): Duration

data class TimedValue<T>(val value: T, val duration: Duration)
inline fun <T> measureTimedValue(block: () -> T): TimedValue<T>
inline fun <T> TimeSource.measureTimedValue(block: () -> T): TimedValue<T>
inline fun <T> TimeSource.Monotonic.measureTimedValue(block: () -> T): TimedValue<T>

Usage Examples

Time Measurement

// Measure execution time
val timeMark = TimeSource.Monotonic.markNow()

// Perform some operation
performLongRunningTask()

val elapsedTime = timeMark.elapsedNow()
println("Operation took: $elapsedTime")

// Using measureTime function
val duration = measureTime {
    processLargeDataSet()
}
println("Processing took: ${duration.inWholeMilliseconds} ms")

// Using measureTimedValue to get both result and duration
val timedResult = measureTimedValue {
    computeExpensiveCalculation()
}
println("Result: ${timedResult.value}, took: ${timedResult.duration}")

// Using with specific TimeSource
val timedWithSource = TimeSource.Monotonic.measureTimedValue {
    performComplexOperation()
}
println("Operation result: ${timedWithSource.value}")
println("Duration: ${timedWithSource.duration.inWholeMilliseconds} ms")

Current Time Access

// Get current timestamp
val now = Clock.System.now()
println("Current time: $now")

// Convert to epoch milliseconds
val epochMillis = now.toEpochMilliseconds()
println("Epoch milliseconds: $epochMillis")

// Convert to epoch seconds
val epochSeconds = now.epochSeconds
println("Epoch seconds: $epochSeconds")

Duration Creation and Manipulation

// Create durations
val oneSecond = 1.seconds
val halfMinute = 30.seconds
val twoHours = 2.hours
val oneDay = 1.days

// Duration arithmetic
val totalTime = oneSecond + halfMinute + twoHours
val remaining = oneDay - totalTime

// Duration comparisons
if (elapsedTime > 5.seconds) {
    println("Operation was slow")
}

// Duration formatting
println("Duration: ${totalTime.inWholeMinutes} minutes")
println("Duration: ${totalTime.toString()}")

Parsing Time Strings

// Parse ISO-8601 duration strings
val duration1 = Duration.parse("PT1H30M") // 1 hour 30 minutes
val duration2 = Duration.parse("P1DT2H") // 1 day 2 hours
val duration3 = Duration.parseIsoString("PT45.5S") // 45.5 seconds

// Create instants from timestamps
val instant1 = Instant.fromEpochSeconds(1609459200) // 2021-01-01 00:00:00 UTC
val instant2 = Instant.fromEpochMilliseconds(1640995200000) // 2022-01-01 00:00:00 UTC
val instant3 = Instant.fromEpochSeconds(1640995200, 500_000_000) // With nanoseconds

Timeout and Scheduling

// Implement timeout functionality
suspend fun withTimeout(timeout: Duration, block: suspend () -> Unit) {
    val startTime = TimeSource.Monotonic.markNow()
    
    while (startTime.elapsedNow() < timeout) {
        try {
            block()
            return
        } catch (e: Exception) {
            if (startTime.elapsedNow() >= timeout) {
                throw TimeoutException("Operation timed out after $timeout")
            }
            // Continue trying
        }
    }
}

// Use timeout
withTimeout(30.seconds) {
    connectToExternalService()
}

Performance Monitoring

// Performance profiling
class PerformanceProfiler {
    private val measurements = mutableMapOf<String, Duration>()
    
    fun measure(operation: String, block: () -> Unit) {
        val duration = measureTime(block)
        measurements[operation] = measurements.getOrDefault(operation, Duration.ZERO) + duration
    }
    
    fun report() {
        measurements.forEach { (operation, totalTime) ->
            println("$operation: ${totalTime.inWholeMilliseconds} ms total")
        }
    }
}

val profiler = PerformanceProfiler()
profiler.measure("database_query") { executeQuery() }
profiler.measure("data_processing") { processResults() }
profiler.report()

Implementation Details

WASI System Call Integration

Time operations are implemented using the WASI clock_time_get system call:

@WasmImport("wasi_snapshot_preview1", "clock_time_get")
private external fun wasiRawClockTimeGet(
    id: Int,        // Clock ID (REALTIME or MONOTONIC)
    precision: Long, // Requested precision in nanoseconds
    time: Int       // Pointer to store the result
): Int

Clock Types

The implementation supports two WASI clock types:

  1. CLOCK_REALTIME (0): Wall clock time, subject to adjustments
  2. CLOCK_MONOTONIC (1): Monotonic time, not subject to adjustments

Precision and Resolution

  • Nanosecond Precision: WASI clocks provide nanosecond precision when supported
  • Runtime Dependent: Actual resolution depends on the WASI runtime and underlying system
  • Fallback Handling: Graceful degradation when high precision is not available

Memory Management

Time operations use efficient memory allocation:

// Scoped memory allocation for time queries
MemoryAllocator.scoped { allocator ->
    val timePtr = allocator.allocate(8) // 64-bit timestamp storage
    val result = wasiRawClockTimeGet(clockId, precision, timePtr.address.toInt())
    // Extract timestamp and clean up automatically
}

Performance Considerations

System Call Efficiency

  • Caching: Frequent time queries are optimized to reduce system call overhead
  • Batch Operations: Multiple time operations may be batched when possible
  • Clock Selection: Monotonic clock is preferred for duration measurements

Best Practices

// Efficient: Use monotonic time for measurements
val start = TimeSource.Monotonic.markNow()
// ... operation ...
val elapsed = start.elapsedNow()

// Less efficient: Multiple system clock queries
val start = Clock.System.now()
// ... operation ...
val end = Clock.System.now()
val elapsed = end - start

// Efficient: Reuse TimeMark for multiple measurements
val mark = TimeSource.Monotonic.markNow()
checkPoint1(mark.elapsedNow())
// ... more work ...
checkPoint2(mark.elapsedNow())

Memory Efficiency

// Avoid creating unnecessary Duration objects
// Less efficient:
val durations = (1..1000).map { it.milliseconds }

// More efficient:
val baseDuration = 1.milliseconds
val multipliedDuration = baseDuration * 1000

Error Handling

Time operations handle WASI-specific errors:

  • EINVAL: Invalid clock ID or precision value
  • EFAULT: Invalid memory address for result storage
  • ENOSYS: Clock not supported by the WASI runtime
  • EOVERFLOW: Time value cannot be represented

All errors are translated to appropriate Kotlin exceptions:

try {
    val now = Clock.System.now()
} catch (e: DateTimeException) {
    println("Time access failed: ${e.message}")
}

Platform Limitations

Clock Availability

Not all WASI runtimes support all clock types:

  • Realtime Clock: Generally available but may have limited precision
  • Monotonic Clock: May not be available in some minimal WASI implementations
  • Process/Thread Clocks: Not supported in WASI preview1

Time Zone Support

WASI implementations have limited time zone support:

  • UTC Only: Most operations assume UTC time zone
  • No Local Time: Local time zone information is typically not available
  • No DST: Daylight saving time adjustments are not handled

Precision Limitations

  • Runtime Dependent: Actual precision depends on the WASI runtime
  • Hardware Dependent: Underlying hardware capabilities affect precision
  • Virtualization Impact: Virtualized environments may have reduced precision

Install with Tessl CLI

npx tessl i tessl/maven-org-jetbrains-kotlin--kotlin-stdlib-wasm-wasi

docs

console-io.md

exceptions.md

index.md

random.md

reflection.md

time.md

uuid.md

tile.json