Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ jobs:
strategy:
matrix:
args:
- --default-features
- --features std
- --no-default-features
- --target wasm32-unknown-unknown
steps:
Expand Down
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,14 @@

-->

## Unreleased

### Breaking changes

- Remove `set_global_time_context` function (https://github.com/shadowylab/universal-time/pull/1)
- Link errors if the time provider is missing (https://github.com/shadowylab/universal-time/pull/1)
- Require `define_time_provider!` macro on `no_std`/`WASM-unknown` (https://github.com/shadowylab/universal-time/pull/1)

## v0.1.0 - 2026/02/23

First release.
6 changes: 5 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,17 @@
name = "universal-time"
version = "0.1.0"
edition = "2021"
description = "Cross-platform time primitives"
description = "Cross-platform time primitives with compile-time guarantees — no runtime panics!"
authors = ["Yuki Kishimoto <yukikishimoto@protonmail.com>"]
homepage = "https://github.com/shadowylab/universal-time"
repository = "https://github.com/shadowylab/universal-time.git"
license = "MIT"
rust-version = "1.70.0"

[package.metadata.docs.rs]
no-default-features = true
rustdoc-args = ["--cfg", "docsrs"]

[features]
default = ["std"]
std = []
91 changes: 70 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,45 +1,94 @@
# universal-time

Cross-platform time primitives for Rust that can run in any envuironment.
Cross-platform time primitives with **compile-time guarantees** — no runtime panics!

## Why
This library provides `Instant` (monotonic time) and `SystemTime` (wall-clock time) that work consistently across all platforms with zero runtime overhead.

`universal-time` gives you a single API for:
## Why?

- `Instant` for monotonic elapsed-time measurements
- `SystemTime` for wall-clock timestamps
- Trait-based clock injection for platforms without built-in time access
This library **fails at link time** if you try to build without a time provider on platforms that need one. This means:

- ✅ **Zero runtime panics** from missing time sources
- ✅ **Compile-time verification** that time is available
- ✅ **Single consistent API** across all platforms
- ✅ **No overhead** – compiles away to platform calls

## Quick Start

### With `std` (default)

Works automatically with `std::time`:

```rust,no_run
use universal_time::{Instant, SystemTime, UNIX_EPOCH};

fn main() {
let start = Instant::now();
let now = SystemTime::now();
let elapsed = start.elapsed();
let since_epoch = now.duration_since(UNIX_EPOCH).unwrap_or_default();

println!("elapsed = {:?}", elapsed);
println!("since epoch = {:?}", since_epoch);
let now = SystemTime::now();
let since_epoch = now.duration_since(UNIX_EPOCH).unwrap();

println!("Elapsed: {:?}", elapsed);
println!("Since Unix epoch: {:?}", since_epoch);
}
```

### Without `std` (embedded, WASM unknown)

Define a custom time provider using the `define_time_provider!` macro:

```rust,ignore
# use core::time::Duration;
# use universal_time::{define_time_provider, Instant, SystemTime, WallClock, MonotonicClock};
struct MyTimeProvider;

impl WallClock for MyTimeProvider {
fn system_time(&self) -> SystemTime {
// Your platform-specific implementation
# SystemTime::from_unix_duration(Duration::from_secs(0))
}
}

impl MonotonicClock for MyTimeProvider {
fn instant(&self) -> Instant {
// Your platform-specific implementation
# Instant::from_ticks(Duration::from_secs(0))
}
}

define_time_provider!(MyTimeProvider);
# fn main() {
# // Now Instant::now() and SystemTime::now() work!
# let _now = Instant::now();
# }
```

## How It Works

The library uses **extern symbols** to enforce time provider availability at **link time**:

| Platform | Behavior |
|--------------------------------------|----------------------------------------|
| Linux/macOS/Windows with `std` | Uses `std::time` automatically |
| `no_std` and `wasm*-unknown-unknown` | Requires `define_time_provider!` macro |
| Other WASM targets with `std` | Uses `std::time` automatically |

**Without a provider on no_std**, you get a clear link error:
```text
error: undefined reference to '__universal_time_provider'
```

For more examples, check out the [examples](examples) directory.
**Duplicate provider?** Link error: "duplicate symbol" – catches configuration mistakes at compile time!

## Panic Behavior
## Features

In `no_std` mode, and in `std` mode on `wasm32-unknown-unknown`, both
`Instant::now()` and `SystemTime::now()` panic when:
- `std` (enabled by default) - Uses `std::time` on supported platforms

- no global context has been installed, or
- installed context returns `None` for that clock type
## Changelog

This is intentional so missing time sources fail fast instead of silently returning fake timestamps.
All notable changes to this library are documented in the [CHANGELOG.md](CHANGELOG.md).

## Concurrency Notes
## License

- `std`: global context uses `OnceLock`
- `no_std` with atomics: global context uses lock-free once initialization
- `no_std` without atomics: fallback expects single-threaded startup initialization
This project is distributed under the MIT software license – see the [LICENSE](./LICENSE) file for details
49 changes: 0 additions & 49 deletions examples/custom.rs

This file was deleted.

11 changes: 0 additions & 11 deletions examples/standard.rs

This file was deleted.

Loading
Loading