Two clocks: Instant and SystemTime¶
Level: 201 · working knowledge
One line: Instant is a stopwatch and SystemTime is a calendar — the first measures how long and never runs backwards, the second tells you what time it is and can be set — so you pick by the question you are asking, not by precision.
use std::time::{Instant, SystemTime, UNIX_EPOCH};
fn main() {
// How long? Ask the stopwatch.
let start = Instant::now();
let total: u64 = (1..=1_000).sum();
let took = start.elapsed(); // a Duration
// What time is it? Ask the calendar.
let since_epoch = SystemTime::now().duration_since(UNIX_EPOCH); // a Result
println!("{total} {}", since_epoch.is_ok()); // 500500 true
println!("{took:?}"); // a different Duration every run
}
| Clock | Answers | What now() reads |
Can it go backwards? | C++ |
|---|---|---|---|---|
Instant ↗ |
how long | clock_gettime with CLOCK_MONOTONIC on Unix and CLOCK_UPTIME_RAW on macOS; QueryPerformanceCounter on Windows |
no | steady_clock |
SystemTime ↗ |
what time | clock_gettime's realtime clock; GetSystemTimePreciseAsFileTime or GetSystemTimeAsFileTime on Windows |
yes | system_clock |
The reads column is std's own table for 1.98.0, which adds "These system calls might change over time." Precision differs by platform too: on Windows a SystemTime counts in 100-nanosecond steps, where Linux can represent single nanoseconds.
Instant: only differences¶
An Instant holds no number you can read. Its docs call it "Opaque and useful only with Duration": two can be compared, one can be subtracted from another, a Duration can be added to one, and that is the whole interface. There is no as_secs, because the zero point is whatever the operating system picked — on Linux, CLOCK_MONOTONIC counts from boot — and a raw reading would mean nothing on another machine, or on this one after a restart.
Its promise is a direction: "monotonically nondecreasing", each instant "no less than any previously measured instant". The example below takes a thousand readings in a row and checks. What it does not promise is a rate:
Note, however, that instants are not guaranteed to be steady. In other words, each tick of the underlying clock might not be the same length (e.g. some seconds may be longer than others). An instant may jump forwards or experience time dilation (slow down or speed up), but it will never go backwards.
Nor does it promise anything about sleep: it is "not specified whether system suspends count as elapsed time or not". On this Mac they do not count — CLOCK_UPTIME_RAW "does not increment while the system is asleep", per man clock_gettime — and on Linux CLOCK_MONOTONIC "does not count time that the system is suspended" either. An Instant taken before you close a laptop and read after you open it has missed the time the lid was shut.
C++ chose the other answer on the same Mac. libc++'s steady_clock reads CLOCK_MONOTONIC_RAW, which does count sleep — its source says that is why it was picked — and on 2026-09-10, a week after this Mac booted, the two clocks stood 2.35 days apart: 7.206 days against 4.859 (measured on the C++ side ↗). Two monotonic stopwatches, and they disagree about how long the lid was shut.
SystemTime: a date, and it can be set¶
SystemTime reads the clock that NTP, an administrator or the user can set, and its docs put the consequence first: "Distinct from the Instant type, this time measurement is not monotonic." Save a file, save another, and the second can carry the earlier time. So every method that asks it for a length — duration_since, elapsed — returns a Result rather than a Duration. The next page is about that Result, and about the subtraction it replaces.
Its fixed point is UNIX_EPOCH ↗, defined as "1970-01-01 00:00:00 UTC" on all systems. duration_since(UNIX_EPOCH) is the POSIX timestamp, and UNIX_EPOCH + duration builds a SystemTime for any date — which is how the example below gets one that is the same on every run. Leap seconds are not counted.
The same clock, a stronger promise in C++¶
C++'s steady_clock promises more than Instant does. Its is_steady is true, and the standard's clock requirements (time.clock.req ↗, Table 131 in the current draft) define true as "t1 <= t2 is always true and the time between clock ticks is constant". On Linux, libstdc++'s steady_clock::now() ↗ reads CLOCK_MONOTONIC — the clock Instant reads there — and Linux's man page ↗ says that clock "is affected by frequency adjustments": NTP slews it, running it slightly fast or slow to steer it toward true time.
So one clock carries two statements. C++ promises constant ticks over a clock the kernel deliberately speeds up and slows down; Rust promises only the direction.
No third clock¶
C++'s third clock, high_resolution_clock, "may be a synonym for system_clock or steady_clock" (time.clock.hires ↗), and the two standard libraries on this Mac chose differently:
#include <chrono>
#include <cstdio>
#include <type_traits>
namespace sc = std::chrono;
int main() {
std::printf("steady_clock::is_steady %d\n", sc::steady_clock::is_steady);
std::printf("system_clock::is_steady %d\n", sc::system_clock::is_steady);
std::printf("is_same_v<high_resolution_clock, steady_clock> %d\n",
std::is_same_v<sc::high_resolution_clock, sc::steady_clock>);
std::printf("is_same_v<high_resolution_clock, system_clock> %d\n",
std::is_same_v<sc::high_resolution_clock, sc::system_clock>);
}
steady_clock::is_steady 1
system_clock::is_steady 0
is_same_v<high_resolution_clock, steady_clock> 0
is_same_v<high_resolution_clock, system_clock> 1
steady_clock::is_steady 1
system_clock::is_steady 0
is_same_v<high_resolution_clock, steady_clock> 1
is_same_v<high_resolution_clock, system_clock> 0
A C++ benchmark timed with high_resolution_clock therefore reads a clock that can be set backwards when it is built with GCC, and one that cannot when it is built with Clang — from the same source. Rust has no such clock: how long is Instant, and there is nothing else to pick.
std has no Clock trait either. C++ describes a clock as requirements any type can meet — a now(), a time_point, an is_steady — so steady_clock, system_clock and a fake clock in a test all satisfy them, and a function can be generic over "some clock". Instant and SystemTime share nothing, and code that wants to swap in a fake clock needs a trait of its own.
The verified output¶
Verified output of two_clocks.rs — regenerated by tools/run_examples.py, never hand-typed.
1. Instant: a stopwatch
Instant::now() <= Instant::now() true
1,000 readings, each >= the last true
b - a is a core::time::Duration
a.elapsed() is a core::time::Duration
2. SystemTime: a calendar
now.duration_since(UNIX_EPOCH).is_ok() true
now.duration_since(UNIX_EPOCH) is a
core::result::Result<core::time::Duration, std::time::SystemTimeError>
now.elapsed() is a
core::result::Result<core::time::Duration, std::time::SystemTimeError>
3. The epoch is a fixed point, so a SystemTime can be built from it
(UNIX_EPOCH + 86_400 s).duration_since(UNIX_EPOCH) = Ok(86400s)
The two long types in section 2 are the difference between the clocks, one line each: the stopwatch answers with a Duration, the calendar with a Result. They say core::time::Duration because std::time::Duration is core's type, re-exported.
If you are coming from another language¶
- C++.
steady_clockisInstantandsystem_clockisSystemTime, down to the system call on Linux. The differences are the three sections above: C++ promises steady ticks where Rust promises only a direction, C++ has a third clock whose meaning depends on the standard library, and C++ has a clock concept where Rust has two unrelated types. The C++ side of this page is Three clocks ↗. - Python.
time.monotonic()andtime.perf_counter()areInstant;time.time()isSystemTime. Python's docs give the two stopwatches the same opaqueness: "The reference point of the returned value is undefined, so that only the difference between the results of two calls is valid." On this Mac they are the same clock asInstant, too —time.get_clock_info()namesmach_absolute_time()behind both (Python 3.14.7), andman clock_gettimesaysCLOCK_UPTIME_RAWis "identical to the result of mach_absolute_time()" once converted — whiletime.time()namesclock_gettime(CLOCK_REALTIME), the clockSystemTimereads. What changes is the type. All three return afloat, so nothing stopstime.time() - time.monotonic(): it runs, and produces a number of seconds that means nothing. The next page is Rust refusing to compile exactly that. - ABAP. (Not machine-checked — CI cannot run ABAP; this is from the ABAP keyword documentation.)
GET RUN TIME FIELDis the stopwatch: its first execution in an internal session sets the field to0, and each later one sets it to the microseconds elapsed since that first execution — a value with no meaning on its own, useful only as a difference, exactly like anInstant.GET TIME STAMP FIELDis the calendar: a UTC time stamp taken from the application server's system time and date, in a packedTIMESTAMP, or aTIMESTAMPLwith seven decimal places of seconds. One difference worth knowing: the stopwatch's field is ani, and the documentation says not to measure sections longer than 1,000 seconds, so that its value range is not exceeded.
See also¶
- An
Instantis not aSystemTime— what happens when you subtract one from the other - A
Durationcannot be negative — the type both clocks answer in - Timing a block — the stopwatch in use
OptionvsResult— why the calendar's answer is aResult
Po polsku¶
W Ruscie są dwa zegary i wybiera się je według pytania, a nie według precyzji. Instant odpowiada na pytanie „jak długo?” — to stoper. SystemTime odpowiada na pytanie „która godzina?” — to kalendarz. Po polsku Instant najlepiej oddaje słowo chwila (instant): punkt w czasie, którego nie da się odczytać jako liczby, tylko porównać z inną chwilą albo od niej odjąć. Zero tego zegara wybiera system operacyjny — na Linuksie jest to start systemu — więc sama wartość nic by nie znaczyła.
Instant czyta zegar monotoniczny (monotonic clock), czyli taki, który nigdy się nie cofa. Dokumentacja Rusta obiecuje jednak tylko kierunek, nie tempo: zegar może przyspieszać i zwalniać, bo NTP go koryguje, a to, czy liczy czas uśpienia (suspend), nie jest określone — na macOS nie liczy. C++ obiecuje więcej: steady_clock::is_steady znaczy według normy, że odstęp między tyknięciami jest stały, choć na Linuksie oba języki czytają ten sam CLOCK_MONOTONIC.
SystemTime to czas systemowy (system time, potocznie wall-clock time): data i godzina, które administrator, NTP albo użytkownik mogą przestawić, także wstecz. Dlatego każde pytanie o odstęp — duration_since, elapsed — zwraca Result, a nie Duration. Punktem odniesienia jest epoka Uniksa (Unix epoch), UNIX_EPOCH, czyli 1970-01-01 00:00:00 UTC, a sekundy przestępne (leap seconds) nie są liczone. Trzeciego zegara, jak high_resolution_clock w C++, Rust nie ma — i dobrze, bo w C++ ten sam kod dostaje z nim inny zegar zależnie od biblioteki standardowej.
Szukaj po polsku: zegar monotoniczny · czas uniksowy · epoka Uniksa · rust Instant vs SystemTime · clock_gettime CLOCK_MONOTONIC