zig-skills/references/std-time.md

129 lines
3.7 KiB
Markdown

# 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`?