From a5d42f370da44afa0b6c2724ccdcc0b918b680b0 Mon Sep 17 00:00:00 2001 From: Ryan Liptak Date: Tue, 4 Nov 2025 15:21:07 -0800 Subject: [PATCH] std.Io: Standardize the epoch as 1970-01-01T00:00:00Z Enforcing a standard epoch in the Io.Clock API allows usage to be simplified, as it allows users to not have to constantly deal with implementation-defined epochs. For example, this change fixes #25776 because on Windows (which previously would return a value relative to a different epoch), the crypto.Certificate code would compare a Unix timestamp to the value returned by the `.real` clock. To fix this while keeping the implementation-defined epoch, every usage of Clock.real would have to be audited and deal with converting between epochs in a platform-specific way. Note also that Windows is the only odd-one out in the current implementation: - WASI uses the 1970-01-01T00:00:00Z epoch: https://github.com/WebAssembly/WASI/blob/9ea0e7534f46f0c39f28b386fa2becf00923a857/legacy/preview0/docs.md?plain=1#L30-L32 - POSIX uses the 1970-01-01T00:00:00Z epoch: https://pubs.opengroup.org/onlinepubs/9699919799/ and https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/V1_chap03.html#tag_03_125 --- lib/std/Io.zig | 6 +++--- lib/std/Io/Threaded.zig | 3 ++- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/lib/std/Io.zig b/lib/std/Io.zig index 810a7a8102b2..f648322a8474 100644 --- a/lib/std/Io.zig +++ b/lib/std/Io.zig @@ -734,7 +734,7 @@ pub const Clock = enum { /// A settable system-wide clock that measures real (i.e. wall-clock) /// time. This clock is affected by discontinuous jumps in the system /// time (e.g., if the system administrator manually changes the - /// clock), and by frequency adjust‐ ments performed by NTP and similar + /// clock), and by frequency adjustments performed by NTP and similar /// applications. /// /// This clock normally counts the number of seconds since 1970-01-01 @@ -742,8 +742,8 @@ pub const Clock = enum { /// leap seconds; near a leap second it is typically adjusted by NTP to /// stay roughly in sync with UTC. /// - /// The epoch is implementation-defined. For example NTFS/Windows uses - /// 1601-01-01. + /// The epoch is 1970-01-01T00:00:00Z, which corresponds to a clock + /// value of zero. real, /// A nonsettable system-wide clock that represents time since some /// unspecified point in the past. diff --git a/lib/std/Io/Threaded.zig b/lib/std/Io/Threaded.zig index 11f9b149caf5..3f17f53e554e 100644 --- a/lib/std/Io/Threaded.zig +++ b/lib/std/Io/Threaded.zig @@ -2864,7 +2864,8 @@ fn nowWindows(userdata: ?*anyopaque, clock: Io.Clock) Io.Clock.Error!Io.Timestam .real => { // RtlGetSystemTimePrecise() has a granularity of 100 nanoseconds // and uses the NTFS/Windows epoch, which is 1601-01-01. - return .{ .nanoseconds = @as(i96, windows.ntdll.RtlGetSystemTimePrecise()) * 100 }; + const epoch_100_ns = std.time.epoch.windows * (std.time.ns_per_s / 100); + return .{ .nanoseconds = @as(i96, windows.ntdll.RtlGetSystemTimePrecise() + epoch_100_ns) * 100 }; }, .awake, .boot => { // QPC on windows doesn't fail on >= XP/2000 and includes time suspended.