diff --git a/lib/std/os/uefi.zig b/lib/std/os/uefi.zig index 7ad01e58e7..165c3df249 100644 --- a/lib/std/os/uefi.zig +++ b/lib/std/os/uefi.zig @@ -131,6 +131,31 @@ pub const Time = extern struct { /// Time is to be interpreted as local time pub const unspecified_timezone: i16 = 0x7ff; + + fn daysInYear(year: u16, maxMonth: u4) u32 { + const leapYear: std.time.epoch.YearLeapKind = if (std.time.epoch.isLeapYear(year)) .leap else .not_leap; + var days: u32 = 0; + var month: u4 = 0; + while (month < maxMonth) : (month += 1) { + days += std.time.epoch.getDaysInMonth(leapYear, @enumFromInt(month + 1)); + } + return days; + } + + pub fn toEpoch(self: std.os.uefi.Time) u64 { + var year: u16 = 0; + var days: u32 = 0; + + while (year < (self.year - 1971)) : (year += 1) { + days += daysInYear(year + 1970, 12); + } + + days += daysInYear(self.year, @as(u4, @intCast(self.month)) - 1) + self.day; + const hours = self.hour + (days * 24); + const minutes = self.minute + (hours * 60); + const seconds = self.second + (minutes * std.time.s_per_min); + return self.nanosecond + (seconds * std.time.ns_per_s); + } }; /// Capabilities of the clock device diff --git a/lib/std/time.zig b/lib/std/time.zig index c078e97793..dad81385e9 100644 --- a/lib/std/time.zig +++ b/lib/std/time.zig @@ -114,6 +114,13 @@ pub fn nanoTimestamp() i128 { return ns; } + if (builtin.os.tag == .uefi) { + var value: std.os.uefi.Time = undefined; + const status = std.os.uefi.system_table.runtime_services.getTime(&value, null); + assert(status == .Success); + return value.toEpoch(); + } + var ts: os.timespec = undefined; os.clock_gettime(os.CLOCK.REALTIME, &ts) catch |err| switch (err) { error.UnsupportedClock, error.Unexpected => return 0, // "Precision of timing depends on hardware and OS". @@ -176,7 +183,7 @@ pub const Instant = struct { // true if we should use clock_gettime() const is_posix = switch (builtin.os.tag) { .wasi => builtin.link_libc, - .windows => false, + .windows, .uefi => false, else => true, }; @@ -197,6 +204,13 @@ pub const Instant = struct { return Instant{ .timestamp = ns }; } + if (builtin.os.tag == .uefi) { + var value: std.os.uefi.Time = undefined; + const status = std.os.uefi.system_table.runtime_services.getTime(&value, null); + if (status != .Success) return error.Unsupported; + return Instant{ .timestamp = value.toEpoch() }; + } + // On darwin, use UPTIME_RAW instead of MONOTONIC as it ticks while suspended. // On linux, use BOOTTIME instead of MONOTONIC as it ticks while suspended. // On freebsd derivatives, use MONOTONIC_FAST as currently there's no precision tradeoff.