0
# Time and Duration Handling
1
2
## Overview
3
4
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.
5
6
## API Reference
7
8
### Monotonic Time Source
9
10
```kotlin { .api }
11
/**
12
* A monotonic time source that provides elapsed time measurements.
13
* Uses WASI's clock_time_get with CLOCK_MONOTONIC.
14
*/
15
object TimeSource.Monotonic : TimeSource {
16
/**
17
* Marks the current point in time for later measurement.
18
* @return a TimeMark representing the current time
19
*/
20
fun markNow(): TimeMark
21
}
22
```
23
24
### System Clock
25
26
```kotlin { .api }
27
/**
28
* The system clock that provides access to the current date and time.
29
* Uses WASI's clock_time_get with CLOCK_REALTIME.
30
*/
31
object Clock.System : Clock {
32
/**
33
* Returns the current moment in time.
34
* @return the current Instant
35
*/
36
fun now(): Instant
37
}
38
```
39
40
### Duration Operations
41
42
```kotlin { .api }
43
/**
44
* Represents a time-based amount of time.
45
*/
46
@SinceKotlin("1.6")
47
@JvmInline
48
value class Duration internal constructor(private val rawValue: Long) : Comparable<Duration> {
49
companion object {
50
val ZERO: Duration
51
val INFINITE: Duration
52
53
fun parse(value: String): Duration
54
fun parseIsoString(value: String): Duration
55
fun parseOrNull(value: String): Duration?
56
fun parseIsoStringOrNull(value: String): Duration?
57
fun convert(value: Double, sourceUnit: DurationUnit, targetUnit: DurationUnit): Double
58
}
59
60
// Arithmetic operations
61
operator fun unaryMinus(): Duration
62
operator fun plus(other: Duration): Duration
63
operator fun minus(other: Duration): Duration
64
operator fun times(scale: Int): Duration
65
operator fun times(scale: Double): Duration
66
operator fun div(scale: Int): Duration
67
operator fun div(scale: Double): Duration
68
operator fun div(other: Duration): Double
69
70
// Properties and checks
71
fun isNegative(): Boolean
72
fun isPositive(): Boolean
73
fun isInfinite(): Boolean
74
fun isFinite(): Boolean
75
val absoluteValue: Duration
76
77
// Component extraction
78
inline fun <T> toComponents(action: (days: Long, hours: Int, minutes: Int, seconds: Int, nanoseconds: Int) -> T): T
79
inline fun <T> toComponents(action: (hours: Long, minutes: Int, seconds: Int, nanoseconds: Int) -> T): T
80
inline fun <T> toComponents(action: (minutes: Long, seconds: Int, nanoseconds: Int) -> T): T
81
inline fun <T> toComponents(action: (seconds: Long, nanoseconds: Int) -> T): T
82
83
// Conversion to units
84
fun toDouble(unit: DurationUnit): Double
85
fun toLong(unit: DurationUnit): Long
86
fun toInt(unit: DurationUnit): Int
87
val inWholeDays: Long
88
val inWholeHours: Long
89
val inWholeMinutes: Long
90
val inWholeSeconds: Long
91
val inWholeMilliseconds: Long
92
val inWholeMicroseconds: Long
93
val inWholeNanoseconds: Long
94
95
// String representation
96
override fun toString(): String
97
fun toString(unit: DurationUnit, decimals: Int = 0): String
98
fun toIsoString(): String
99
100
override operator fun compareTo(other: Duration): Int
101
}
102
103
/**
104
* Duration unit enumeration
105
*/
106
@WasExperimental(ExperimentalTime::class)
107
enum class DurationUnit {
108
NANOSECONDS,
109
MICROSECONDS,
110
MILLISECONDS,
111
SECONDS,
112
MINUTES,
113
HOURS,
114
DAYS
115
}
116
117
/**
118
* Duration construction extensions
119
*/
120
val Int.nanoseconds: Duration
121
val Long.nanoseconds: Duration
122
val Double.nanoseconds: Duration
123
val Int.microseconds: Duration
124
val Long.microseconds: Duration
125
val Double.microseconds: Duration
126
val Int.milliseconds: Duration
127
val Long.milliseconds: Duration
128
val Double.milliseconds: Duration
129
val Int.seconds: Duration
130
val Long.seconds: Duration
131
val Double.seconds: Duration
132
val Int.minutes: Duration
133
val Long.minutes: Duration
134
val Double.minutes: Duration
135
val Int.hours: Duration
136
val Long.hours: Duration
137
val Double.hours: Duration
138
val Int.days: Duration
139
val Long.days: Duration
140
val Double.days: Duration
141
```
142
143
### Instant Operations
144
145
```kotlin { .api }
146
/**
147
* Represents an instantaneous point on the time-line.
148
*/
149
@SinceKotlin("2.1")
150
@ExperimentalTime
151
class Instant internal constructor(
152
val epochSeconds: Long,
153
val nanosecondsOfSecond: Int
154
) : Comparable<Instant>, Serializable {
155
156
companion object {
157
// Construction
158
fun fromEpochMilliseconds(epochMilliseconds: Long): Instant
159
fun fromEpochSeconds(epochSeconds: Long, nanosecondAdjustment: Long = 0): Instant
160
fun fromEpochSeconds(epochSeconds: Long, nanosecondAdjustment: Int): Instant
161
162
// Parsing
163
fun parse(input: CharSequence): Instant
164
fun parseOrNull(input: CharSequence): Instant?
165
166
// Constants
167
val DISTANT_PAST: Instant
168
val DISTANT_FUTURE: Instant
169
}
170
171
// Properties
172
fun toEpochMilliseconds(): Long
173
val isDistantPast: Boolean
174
val isDistantFuture: Boolean
175
176
// Arithmetic operations
177
operator fun plus(duration: Duration): Instant
178
operator fun minus(duration: Duration): Instant
179
operator fun minus(other: Instant): Duration
180
181
// Comparison and equality
182
override operator fun compareTo(other: Instant): Int
183
override fun equals(other: Any?): Boolean
184
override fun hashCode(): Int
185
override fun toString(): String // ISO 8601 format
186
}
187
188
/**
189
* TimeMark interfaces for time measurement
190
*/
191
@SinceKotlin("1.9")
192
@WasExperimental(ExperimentalTime::class)
193
interface TimeMark {
194
fun elapsedNow(): Duration
195
operator fun plus(duration: Duration): TimeMark
196
operator fun minus(duration: Duration): TimeMark
197
fun hasPassedNow(): Boolean
198
fun hasNotPassedNow(): Boolean
199
}
200
201
@SinceKotlin("1.9")
202
@WasExperimental(ExperimentalTime::class)
203
interface ComparableTimeMark : TimeMark, Comparable<ComparableTimeMark> {
204
override operator fun plus(duration: Duration): ComparableTimeMark
205
override operator fun minus(duration: Duration): ComparableTimeMark
206
operator fun minus(other: ComparableTimeMark): Duration
207
override operator fun compareTo(other: ComparableTimeMark): Int
208
override fun equals(other: Any?): Boolean
209
override fun hashCode(): Int
210
}
211
212
/**
213
* Time measurement utility functions
214
*/
215
inline fun measureTime(block: () -> Unit): Duration
216
inline fun TimeSource.measureTime(block: () -> Unit): Duration
217
inline fun TimeSource.Monotonic.measureTime(block: () -> Unit): Duration
218
219
data class TimedValue<T>(val value: T, val duration: Duration)
220
inline fun <T> measureTimedValue(block: () -> T): TimedValue<T>
221
inline fun <T> TimeSource.measureTimedValue(block: () -> T): TimedValue<T>
222
inline fun <T> TimeSource.Monotonic.measureTimedValue(block: () -> T): TimedValue<T>
223
```
224
225
## Usage Examples
226
227
### Time Measurement
228
229
```kotlin
230
// Measure execution time
231
val timeMark = TimeSource.Monotonic.markNow()
232
233
// Perform some operation
234
performLongRunningTask()
235
236
val elapsedTime = timeMark.elapsedNow()
237
println("Operation took: $elapsedTime")
238
239
// Using measureTime function
240
val duration = measureTime {
241
processLargeDataSet()
242
}
243
println("Processing took: ${duration.inWholeMilliseconds} ms")
244
245
// Using measureTimedValue to get both result and duration
246
val timedResult = measureTimedValue {
247
computeExpensiveCalculation()
248
}
249
println("Result: ${timedResult.value}, took: ${timedResult.duration}")
250
251
// Using with specific TimeSource
252
val timedWithSource = TimeSource.Monotonic.measureTimedValue {
253
performComplexOperation()
254
}
255
println("Operation result: ${timedWithSource.value}")
256
println("Duration: ${timedWithSource.duration.inWholeMilliseconds} ms")
257
```
258
259
### Current Time Access
260
261
```kotlin
262
// Get current timestamp
263
val now = Clock.System.now()
264
println("Current time: $now")
265
266
// Convert to epoch milliseconds
267
val epochMillis = now.toEpochMilliseconds()
268
println("Epoch milliseconds: $epochMillis")
269
270
// Convert to epoch seconds
271
val epochSeconds = now.epochSeconds
272
println("Epoch seconds: $epochSeconds")
273
```
274
275
### Duration Creation and Manipulation
276
277
```kotlin
278
// Create durations
279
val oneSecond = 1.seconds
280
val halfMinute = 30.seconds
281
val twoHours = 2.hours
282
val oneDay = 1.days
283
284
// Duration arithmetic
285
val totalTime = oneSecond + halfMinute + twoHours
286
val remaining = oneDay - totalTime
287
288
// Duration comparisons
289
if (elapsedTime > 5.seconds) {
290
println("Operation was slow")
291
}
292
293
// Duration formatting
294
println("Duration: ${totalTime.inWholeMinutes} minutes")
295
println("Duration: ${totalTime.toString()}")
296
```
297
298
### Parsing Time Strings
299
300
```kotlin
301
// Parse ISO-8601 duration strings
302
val duration1 = Duration.parse("PT1H30M") // 1 hour 30 minutes
303
val duration2 = Duration.parse("P1DT2H") // 1 day 2 hours
304
val duration3 = Duration.parseIsoString("PT45.5S") // 45.5 seconds
305
306
// Create instants from timestamps
307
val instant1 = Instant.fromEpochSeconds(1609459200) // 2021-01-01 00:00:00 UTC
308
val instant2 = Instant.fromEpochMilliseconds(1640995200000) // 2022-01-01 00:00:00 UTC
309
val instant3 = Instant.fromEpochSeconds(1640995200, 500_000_000) // With nanoseconds
310
```
311
312
### Timeout and Scheduling
313
314
```kotlin
315
// Implement timeout functionality
316
suspend fun withTimeout(timeout: Duration, block: suspend () -> Unit) {
317
val startTime = TimeSource.Monotonic.markNow()
318
319
while (startTime.elapsedNow() < timeout) {
320
try {
321
block()
322
return
323
} catch (e: Exception) {
324
if (startTime.elapsedNow() >= timeout) {
325
throw TimeoutException("Operation timed out after $timeout")
326
}
327
// Continue trying
328
}
329
}
330
}
331
332
// Use timeout
333
withTimeout(30.seconds) {
334
connectToExternalService()
335
}
336
```
337
338
### Performance Monitoring
339
340
```kotlin
341
// Performance profiling
342
class PerformanceProfiler {
343
private val measurements = mutableMapOf<String, Duration>()
344
345
fun measure(operation: String, block: () -> Unit) {
346
val duration = measureTime(block)
347
measurements[operation] = measurements.getOrDefault(operation, Duration.ZERO) + duration
348
}
349
350
fun report() {
351
measurements.forEach { (operation, totalTime) ->
352
println("$operation: ${totalTime.inWholeMilliseconds} ms total")
353
}
354
}
355
}
356
357
val profiler = PerformanceProfiler()
358
profiler.measure("database_query") { executeQuery() }
359
profiler.measure("data_processing") { processResults() }
360
profiler.report()
361
```
362
363
## Implementation Details
364
365
### WASI System Call Integration
366
367
Time operations are implemented using the WASI `clock_time_get` system call:
368
369
```kotlin
370
@WasmImport("wasi_snapshot_preview1", "clock_time_get")
371
private external fun wasiRawClockTimeGet(
372
id: Int, // Clock ID (REALTIME or MONOTONIC)
373
precision: Long, // Requested precision in nanoseconds
374
time: Int // Pointer to store the result
375
): Int
376
```
377
378
### Clock Types
379
380
The implementation supports two WASI clock types:
381
382
1. **CLOCK_REALTIME** (0): Wall clock time, subject to adjustments
383
2. **CLOCK_MONOTONIC** (1): Monotonic time, not subject to adjustments
384
385
### Precision and Resolution
386
387
- **Nanosecond Precision**: WASI clocks provide nanosecond precision when supported
388
- **Runtime Dependent**: Actual resolution depends on the WASI runtime and underlying system
389
- **Fallback Handling**: Graceful degradation when high precision is not available
390
391
### Memory Management
392
393
Time operations use efficient memory allocation:
394
395
```kotlin
396
// Scoped memory allocation for time queries
397
MemoryAllocator.scoped { allocator ->
398
val timePtr = allocator.allocate(8) // 64-bit timestamp storage
399
val result = wasiRawClockTimeGet(clockId, precision, timePtr.address.toInt())
400
// Extract timestamp and clean up automatically
401
}
402
```
403
404
## Performance Considerations
405
406
### System Call Efficiency
407
408
- **Caching**: Frequent time queries are optimized to reduce system call overhead
409
- **Batch Operations**: Multiple time operations may be batched when possible
410
- **Clock Selection**: Monotonic clock is preferred for duration measurements
411
412
### Best Practices
413
414
```kotlin
415
// Efficient: Use monotonic time for measurements
416
val start = TimeSource.Monotonic.markNow()
417
// ... operation ...
418
val elapsed = start.elapsedNow()
419
420
// Less efficient: Multiple system clock queries
421
val start = Clock.System.now()
422
// ... operation ...
423
val end = Clock.System.now()
424
val elapsed = end - start
425
426
// Efficient: Reuse TimeMark for multiple measurements
427
val mark = TimeSource.Monotonic.markNow()
428
checkPoint1(mark.elapsedNow())
429
// ... more work ...
430
checkPoint2(mark.elapsedNow())
431
```
432
433
### Memory Efficiency
434
435
```kotlin
436
// Avoid creating unnecessary Duration objects
437
// Less efficient:
438
val durations = (1..1000).map { it.milliseconds }
439
440
// More efficient:
441
val baseDuration = 1.milliseconds
442
val multipliedDuration = baseDuration * 1000
443
```
444
445
## Error Handling
446
447
Time operations handle WASI-specific errors:
448
449
- **EINVAL**: Invalid clock ID or precision value
450
- **EFAULT**: Invalid memory address for result storage
451
- **ENOSYS**: Clock not supported by the WASI runtime
452
- **EOVERFLOW**: Time value cannot be represented
453
454
All errors are translated to appropriate Kotlin exceptions:
455
456
```kotlin
457
try {
458
val now = Clock.System.now()
459
} catch (e: DateTimeException) {
460
println("Time access failed: ${e.message}")
461
}
462
```
463
464
## Platform Limitations
465
466
### Clock Availability
467
468
Not all WASI runtimes support all clock types:
469
470
- **Realtime Clock**: Generally available but may have limited precision
471
- **Monotonic Clock**: May not be available in some minimal WASI implementations
472
- **Process/Thread Clocks**: Not supported in WASI preview1
473
474
### Time Zone Support
475
476
WASI implementations have limited time zone support:
477
478
- **UTC Only**: Most operations assume UTC time zone
479
- **No Local Time**: Local time zone information is typically not available
480
- **No DST**: Daylight saving time adjustments are not handled
481
482
### Precision Limitations
483
484
- **Runtime Dependent**: Actual precision depends on the WASI runtime
485
- **Hardware Dependent**: Underlying hardware capabilities affect precision
486
- **Virtualization Impact**: Virtualized environments may have reduced precision