Overview
The std.time module provides utilities for measuring time intervals, working with timestamps, and time unit conversions. It offers high-resolution monotonic timers and cross-platform time operations.
Time Constants
Nanosecond Conversions
pub const ns_per_us = 1000; // Nanoseconds per microsecond
pub const ns_per_ms = 1000 * ns_per_us; // Nanoseconds per millisecond
pub const ns_per_s = 1000 * ns_per_ms; // Nanoseconds per second
pub const ns_per_min = 60 * ns_per_s; // Nanoseconds per minute
pub const ns_per_hour = 60 * ns_per_min; // Nanoseconds per hour
pub const ns_per_day = 24 * ns_per_hour; // Nanoseconds per day
pub const ns_per_week = 7 * ns_per_day; // Nanoseconds per week
Microsecond Conversions
pub const us_per_ms = 1000; // Microseconds per millisecond
pub const us_per_s = 1000 * us_per_ms; // Microseconds per second
pub const us_per_min = 60 * us_per_s; // Microseconds per minute
pub const us_per_hour = 60 * us_per_min; // Microseconds per hour
pub const us_per_day = 24 * us_per_hour; // Microseconds per day
pub const us_per_week = 7 * us_per_day; // Microseconds per week
Millisecond Conversions
pub const ms_per_s = 1000; // Milliseconds per second
pub const ms_per_min = 60 * ms_per_s; // Milliseconds per minute
pub const ms_per_hour = 60 * ms_per_min; // Milliseconds per hour
pub const ms_per_day = 24 * ms_per_hour; // Milliseconds per day
pub const ms_per_week = 7 * ms_per_day; // Milliseconds per week
Second Conversions
pub const s_per_min = 60; // Seconds per minute
pub const s_per_hour = s_per_min * 60; // Seconds per hour
pub const s_per_day = s_per_hour * 24; // Seconds per day
pub const s_per_week = s_per_day * 7; // Seconds per week
Instant
pub const Instant = struct {
timestamp: /* platform-specific */,
};
Represents a single point in time with respect to the currently executing program. Ticks during suspend and uses the system’s fastest, most precise timer.
Instant.now
pub fn now() error{Unsupported}!Instant;
Queries the system for the current moment of time.
Example:
const std = @import("std");
const start = try std.time.Instant.now();
// Do some work...
const end = try std.time.Instant.now();
const elapsed = end.since(start);
std.debug.print("Elapsed: {} ns\n", .{elapsed});
Instant.order
pub fn order(self: Instant, other: Instant) std.math.Order;
Compares two instants.
Example:
const now = try std.time.Instant.now();
const later = try std.time.Instant.now();
if (later.order(now) == .gt) {
// later is after now
}
Instant.since
pub fn since(self: Instant, earlier: Instant) u64;
Returns elapsed time in nanoseconds since an earlier instant.
The earlier instant to measure from. Must be before or equal to self.
Example:
const start = try std.time.Instant.now();
// ... some operation ...
const end = try std.time.Instant.now();
const ns = end.since(start);
const ms = ns / std.time.ns_per_ms;
std.debug.print("Operation took {} ms\n", .{ms});
Timer
pub const Timer = struct {
started: Instant,
previous: Instant,
};
A monotonic, high-performance timer. Ensures monotonicity by saturating on the most previous sample. Use this when you need guaranteed monotonic elapsed time measurements.
Timer.start
pub fn start() Error!Timer;
Initializes the timer by querying for a supported clock.
Example:
var timer = try std.time.Timer.start();
Timer.read
pub fn read(self: *Timer) u64;
Reads the timer value in nanoseconds since start or last reset.
Example:
var timer = try std.time.Timer.start();
// Do some work
const elapsed = timer.read();
std.debug.print("Elapsed: {} ns\n", .{elapsed});
Timer.reset
pub fn reset(self: *Timer) void;
Resets the timer value to 0/now.
Example:
var timer = try std.time.Timer.start();
// Do work A
const time_a = timer.read();
timer.reset();
// Do work B
const time_b = timer.read();
Timer.lap
pub fn lap(self: *Timer) u64;
Returns the current value in nanoseconds, then resets the timer.
Elapsed nanoseconds before reset.
Example:
var timer = try std.time.Timer.start();
for (iterations) |_| {
// Do some work
const lap_time = timer.lap();
std.debug.print("Lap: {} ns\n", .{lap_time});
}
Time Conversion Examples
Nanoseconds to Other Units
const ns: u64 = 1_500_000_000; // 1.5 seconds in nanoseconds
const us = ns / std.time.ns_per_us; // 1,500,000 microseconds
const ms = ns / std.time.ns_per_ms; // 1,500 milliseconds
const seconds = ns / std.time.ns_per_s; // 1 second (truncated)
Other Units to Nanoseconds
const milliseconds: u64 = 500;
const ns = milliseconds * std.time.ns_per_ms; // 500,000,000 nanoseconds
const seconds: u64 = 10;
const ns_from_s = seconds * std.time.ns_per_s; // 10,000,000,000 nanoseconds
fn formatDuration(ns: u64) void {
const hours = ns / std.time.ns_per_hour;
const mins = (ns % std.time.ns_per_hour) / std.time.ns_per_min;
const secs = (ns % std.time.ns_per_min) / std.time.ns_per_s;
const ms = (ns % std.time.ns_per_s) / std.time.ns_per_ms;
std.debug.print("{}h {}m {}s {}ms\n", .{hours, mins, secs, ms});
}
Timing Patterns
Benchmarking
const std = @import("std");
fn benchmark(comptime func: anytype, iterations: usize) !u64 {
var timer = try std.time.Timer.start();
var i: usize = 0;
while (i < iterations) : (i += 1) {
func();
}
const total = timer.read();
return total / iterations; // Average time per iteration
}
// Usage
const avg_time = try benchmark(myFunction, 1000);
std.debug.print("Average: {} ns\n", .{avg_time});
Timeout Detection
fn doWorkWithTimeout(timeout_ms: u64) !void {
var timer = try std.time.Timer.start();
const timeout_ns = timeout_ms * std.time.ns_per_ms;
while (true) {
// Do some work
if (timer.read() > timeout_ns) {
return error.Timeout;
}
if (work_complete) break;
}
}
Rate Limiting
const RateLimiter = struct {
last_action: std.time.Instant,
min_interval_ns: u64,
pub fn canAct(self: *RateLimiter) !bool {
const now = try std.time.Instant.now();
const elapsed = now.since(self.last_action);
if (elapsed >= self.min_interval_ns) {
self.last_action = now;
return true;
}
return false;
}
};
Epoch Time
pub const epoch = @import("time/epoch.zig");
Utilities for working with Unix epoch timestamps and calendar dates.
Common Operations:
// Get seconds since Unix epoch
const timestamp = std.time.epoch.timestamp();
// Convert to date components
const date = std.time.epoch.EpochSeconds.fromTimestamp(timestamp);
const year = date.getEpochYear();
Clock Sources
- Linux: Uses
CLOCK_BOOTTIME (includes suspend time)
- macOS/Darwin: Uses
CLOCK_UPTIME_RAW (includes suspend time)
- Windows: Uses
QueryPerformanceCounter (includes suspend time)
- FreeBSD: Uses
CLOCK_MONOTONIC_FAST
- WASI: Uses
clock_time_get(MONOTONIC)
Resolution
Resolution varies by platform but is typically:
- Linux/macOS: ~1 nanosecond (limited by TSC/CPU frequency)
- Windows: ~100 nanoseconds
- WASI: Implementation-dependent
Monotonicity
While Instant and Timer strive for monotonicity, OS and hardware bugs may violate this. For critical use cases requiring strict monotonicity, Timer is preferred as it saturates on previous samples.
Best Practices
- Use Timer for elapsed time: Provides guaranteed monotonicity
- Use Instant for timestamps: Lightweight, suitable for ordering events
- Convert at display time: Keep times in nanoseconds internally, convert when formatting
- Handle errors:
Instant.now() can fail in hostile environments (e.g., seccomp restrictions)
- Avoid subtraction: Use
.since() method instead of manual timestamp arithmetic
Example:
// Good
const start = try std.time.Instant.now();
const end = try std.time.Instant.now();
const elapsed = end.since(start);
// Avoid (not guaranteed to be correct on all platforms)
const elapsed = end.timestamp - start.timestamp;