win_time_sys/system.rs
1// Copyright (c) 2026 Mike Grier
2//! System time, and the clocks that read it ([WT-D-3]).
3//!
4//! System time is UTC wall-clock time, so unlike interrupt time it means something after a
5//! restart and on another machine -- and unlike interrupt time it is not steady: it moves when the
6//! time is set or synchronised, backwards included. Elapsed time within one boot is interrupt
7//! time's to measure.
8//!
9//! Both clocks return the same `FILETIME`, so they share one timeline and their readings compare;
10//! they differ only in how fresh the reading is. The coarse clock is as fresh as the last system
11//! clock tick. The precise clock is documented as "the highest possible level of precision
12//! (<1us)". What each costs on a given machine is `WT-1.6`'s probe to measure.
13//!
14//! [WT-D-3]: https://github.com/MikeGrier/windows-threadpool-sys/blob/main/crates/win-time-sys/DESIGN-NOTES.md#wt-d-3
15
16use core::num::NonZeroU64;
17
18use windows_sys::Win32::Foundation::FILETIME;
19use windows_sys::Win32::System::SystemInformation::{
20 GetSystemTimeAsFileTime, GetSystemTimePreciseAsFileTime,
21};
22
23use crate::clock::Clock;
24use crate::timeline::{HUNDRED_NANOSECOND_TICKS, TimePoint, Timeline};
25
26#[cfg(test)]
27mod tests;
28
29/// System time: 100 ns ticks since midnight at the start of 1 January 1601, UTC -- Windows'
30/// `FILETIME`.
31///
32/// Its points do not compare with interrupt time's, which share its unit but not its zero:
33///
34/// ```compile_fail,E0308
35/// use win_time_sys::{Clock, InterruptClock, PreciseSystemClock};
36///
37/// let _ = PreciseSystemClock.now() < InterruptClock.now();
38/// ```
39pub enum FileTime {}
40
41impl Timeline for FileTime {
42 fn ticks_per_second() -> NonZeroU64 {
43 HUNDRED_NANOSECOND_TICKS
44 }
45}
46
47/// [`FileTime`] as of the last system clock tick, through `GetSystemTimeAsFileTime`.
48#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
49pub struct CoarseSystemClock;
50
51impl Clock for CoarseSystemClock {
52 type Timeline = FileTime;
53
54 fn now(&self) -> TimePoint<FileTime> {
55 let mut time = FILETIME::default();
56 // SAFETY: the out-parameter is a live, writable local for the duration of the call.
57 unsafe { GetSystemTimeAsFileTime(&mut time) };
58 point(time)
59 }
60}
61
62/// [`FileTime`] to under a microsecond, through `GetSystemTimePreciseAsFileTime`: finer than
63/// [`CoarseSystemClock`], and its readings compare with it. `std::time::SystemTime::now` reads the
64/// same call.
65#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
66pub struct PreciseSystemClock;
67
68impl Clock for PreciseSystemClock {
69 type Timeline = FileTime;
70
71 fn now(&self) -> TimePoint<FileTime> {
72 let mut time = FILETIME::default();
73 // SAFETY: the out-parameter is a live, writable local for the duration of the call.
74 unsafe { GetSystemTimePreciseAsFileTime(&mut time) };
75 point(time)
76 }
77}
78
79/// A `FILETIME`'s two halves, as the one count they are.
80fn point(time: FILETIME) -> TimePoint<FileTime> {
81 TimePoint::from_ticks((u64::from(time.dwHighDateTime) << 32) | u64::from(time.dwLowDateTime))
82}