145. Duration::from_nanos_u128 — Round-Trip Nanoseconds Without the u64 Cast
Duration::as_nanos() hands you a u128. Duration::from_nanos() takes a u64. You feed one into the other and the compiler yells at you — or worse, you cast and quietly truncate at 584 years. Rust 1.93 closed the loop with from_nanos_u128.
The mismatched-types papercut
The old API was asymmetric. Going from Duration to nanos was 128-bit:
| |
Coming back, though, you only got from_nanos(_: u64) — so the round-trip needed a cast:
| |
That as u64 silently truncates anything past u64::MAX — and u64::MAX nanoseconds is roughly 584 years. Inside a calendar app you’ll never notice. Inside a scientific or simulation context, you absolutely will.
from_nanos_u128 matches as_nanos
Rust 1.93 stabilised Duration::from_nanos_u128, a const fn that takes the full 128-bit value:
| |
Same shape on both sides. No cast, no truncation, no silent wraparound.
Past the 584-year ceiling
Where the new constructor actually earns its keep is when you have nanoseconds counts that wouldn’t fit in a u64:
| |
Duration itself stores (u64 seconds, u32 nanos), so it has plenty of room — the old from_nanos was just bottlenecked by its argument type.
One thing to watch
from_nanos_u128 panics if you hand it more than Duration::MAX worth of nanoseconds. If you’re pulling values from user input or untrusted sources, guard the upper bound yourself — there isn’t a checked_from_nanos_u128 (yet).
When to reach for it
Use from_nanos_u128 whenever you already have a u128 of nanoseconds — typically because it came out of as_nanos, an arithmetic accumulator, or a high-precision external clock. Stick with the plain from_nanos(_: u64) for short-lived timeouts and durations measured in milliseconds or seconds; the u64 is plenty.
Stabilised in Rust 1.93 (January 2026). Available as const fn, so it works in const contexts too.