# 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 ```zig 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: ```zig const start = std.Io.Clock.Timestamp.now(io, .boot); ``` ## Duration ```zig const d1 = std.Io.Duration.fromMilliseconds(16); const d2 = std.Io.Duration.fromSeconds(1); const ns = d1.toNanoseconds(); _ = .{ d2, ns }; ``` Formatting: ```zig try writer.print("{f}", .{std.Io.Duration.fromMilliseconds(250)}); ``` Do not use the removed `{D}` format specifier. ## Elapsed Time ```zig 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: ```zig 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. ```zig 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. ```zig 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: ```zig 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`?