zig-skills/references/std-time.md

3.7 KiB

Time and Timing (Zig 0.16.0)

Primary release-note source: https://ziglang.org/download/0.16.0/release-notes.html

Zig 0.16 moves time APIs that depend on the runtime behind std.Io. Use std.Io.Timestamp, std.Io.Duration, and std.Io.Clock.

Migration Summary

Choose an explicit clock when migrating old time APIs. Use std.Io.Timestamp.now(io, .real) for wall time and .boot or .awake for elapsed-time measurements; Timestamp is not a one-for-one timer replacement.

  • {D} duration formatting -> format std.Io.Duration with {f}

std.time still provides constants and calendar helpers such as ns_per_ms, ns_per_s, and std.time.epoch.

Clocks

std.Io.Clock values:

  • .real: wall-clock Unix/POSIX time, affected by clock changes.
  • .awake: monotonic-style clock intended to exclude suspend time where possible.
  • .boot: monotonic-style clock intended to include suspend time where possible.
  • .cpu_process: CPU time used by current process.
  • .cpu_thread: CPU time used by current thread.

Current Timestamp

const wall = std.Io.Timestamp.now(io, .real);
const boot = std.Io.Timestamp.now(io, .boot);
const awake = std.Io.Timestamp.now(io, .awake);

Clock-specific wrapper:

const start = std.Io.Clock.Timestamp.now(io, .boot);

Duration

const d1 = std.Io.Duration.fromMilliseconds(16);
const d2 = std.Io.Duration.fromSeconds(1);
const ns = d1.toNanoseconds();
_ = .{ d2, ns };

Formatting:

try writer.print("{f}", .{std.Io.Duration.fromMilliseconds(250)});

Do not use the removed {D} format specifier.

Elapsed Time

const start = std.Io.Timestamp.now(io, .boot);

// work

const end = std.Io.Timestamp.now(io, .boot);
const elapsed = start.durationTo(end);

Or with clock-tagged timestamps:

const start = std.Io.Clock.Timestamp.now(io, .boot);

// work

const elapsed = start.untilNow(io);

Sleeping

Use clock-aware durations/timestamps so sleeping cooperates with the selected std.Io backend and propagates cancelation.

try std.Io.Clock.Duration{
    .raw = std.Io.Duration.fromMilliseconds(10),
    .clock = .boot,
}.sleep(io);

Resolution

Clock resolution may fail or return zero for unsupported clocks.

const clock: std.Io.Clock = .boot;
const resolution = try clock.resolution(io);
if (resolution.nanoseconds == 0) {
    return error.ClockUnavailable;
}

Epoch and Calendar Helpers

Use std.time.epoch for calendar conversion. Timestamps can be converted to seconds:

const now = std.Io.Timestamp.now(io, .real);
const seconds: u64 = @intCast(now.toSeconds());
const epoch_seconds = std.time.epoch.EpochSeconds{ .secs = seconds };

This conversion is only valid for non-negative Unix timestamps and truncates sub-second precision. Guard pre-epoch values or retain a signed representation.

Application Guidance

  • Put common wall-clock timestamp reads behind a shared application helper when consistent clock selection matters.
  • Store/pass std.Io on timer systems that sample time repeatedly.
  • Avoid direct std.time.microTimestamp-style callsites in new code; route through the shared helper.
  • Use .boot or .awake for elapsed-time measurement; use .real for timestamps intended to correspond to wall-clock time.

Review Checklist

  • Is the code using std.Io.Timestamp.now(io, clock) rather than old std.time.timestamp helpers?
  • Is the clock choice documented by usage (.real for wall time, monotonic clocks for elapsed time)?
  • Is duration formatting using {f} with std.Io.Duration?
  • Does the API receive or store io rather than constructing a fallback locally?
  • Does sleeping use a clock-aware std.Io API and handle error.Canceled?