clock-lib 0.4.0

Monotonic and wall-clock time readings for Rust, with a mockable clock for deterministic testing. Simple Tier-1 API, zero dependencies, no unsafe.
Documentation

Features

Two Kinds of Time, Clearly Separated

  • Monotonic readings — for measuring elapsed time; never goes backwards
  • Wall-clock readings — for timestamps and calendar time
  • Type-level separation — the API makes it impossible to subtract a wall-clock time from a monotonic one

Mockable Clock (the killer feature)

  • SystemClock — reads the OS in production
  • ManualClock — advance time instantly in tests, fully deterministic
  • Clock trait — inject time into any system for testability

Simple Tier-1 API

  • now() — monotonic reading
  • elapsed(earlier) — duration since a monotonic reading
  • wall() — wall-clock reading
  • unix() / unix_ms() / unix_ns() — unix time conveniences

Lean & Correct

  • Zero runtime dependencies — wraps std::time
  • No unsafe code
  • no_std support — via the default-off path
  • Cross-platform — Linux, macOS, Windows

This crate deliberately does not do calendar math, date formatting, or timezones. For that, use chrono or time. clock-lib is the lean primitive layer beneath them.

Installation

[dependencies]
clock-lib = "0.4"

Quick Start

use clock_lib as clock;

// Measure elapsed time (monotonic — safe)
let start = clock::now();
// ... do work ...
let took = clock::elapsed(start);

// Get a timestamp (wall-clock)
let unix_seconds = clock::unix();

Reach for the typed surface when you need it — Monotonic for elapsed-time math, Wall for timestamps. The compiler refuses to mix the two, so you cannot accidentally measure an interval with a clock that can step backwards.

Deterministic Time in Tests

use clock_lib::{Clock, ManualClock, Monotonic};
use std::time::Duration;

fn expired<C: Clock>(clock: &C, stamp: Monotonic, ttl: Duration) -> bool {
    clock.now().duration_since(stamp) >= ttl
}

let clock = ManualClock::new();
let stamp = clock.now();
assert!(!expired(&clock, stamp, Duration::from_secs(60)));

clock.advance(Duration::from_secs(60));   // instant, no sleep
assert!(expired(&clock, stamp, Duration::from_secs(60)));

Inject Clock into anything time-driven (rate limiters, TTL caches, timeouts) and your test suite drops every thread::sleep it had.

Documentation

Contributing

Contributions are welcome under the project's dual license. Before opening a pull request, please make sure:

  1. cargo fmt --all -- --check passes.
  2. cargo clippy --all-targets --all-features -- -D warnings is clean.
  3. cargo test --all-features passes.
  4. New public items include documentation and at least one example.
  5. The API reference and CHANGELOG are updated alongside code changes.