diff --git a/lib/std/os/uefi.zig b/lib/std/os/uefi.zig index f67fe5623e..f7e51c63aa 100644 --- a/lib/std/os/uefi.zig +++ b/lib/std/os/uefi.zig @@ -113,31 +113,39 @@ pub const Time = extern struct { /// 0 - 59 second: u8, + _pad1: u8, + /// 0 - 999999999 nanosecond: u32, /// The time's offset in minutes from UTC. /// Allowed values are -1440 to 1440 or unspecified_timezone timezone: i16, - daylight: packed struct { - _pad1: u6, - + daylight: packed struct(u8) { /// If true, the time has been adjusted for daylight savings time. in_daylight: bool, /// If true, the time is affected by daylight savings time. adjust_daylight: bool, + + _: u6, }, + _pad2: u8, + + comptime { + std.debug.assert(@sizeOf(Time) == 16); + } + /// 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; + fn daysInYear(year: u16, max_month: u4) u9 { + const leap_year: std.time.epoch.YearLeapKind = if (std.time.epoch.isLeapYear(year)) .leap else .not_leap; + var days: u9 = 0; var month: u4 = 0; - while (month < maxMonth) : (month += 1) { - days += std.time.epoch.getDaysInMonth(leapYear, @enumFromInt(month + 1)); + while (month < max_month) : (month += 1) { + days += std.time.epoch.getDaysInMonth(leap_year, @enumFromInt(month + 1)); } return days; } @@ -151,9 +159,9 @@ pub const Time = extern struct { } 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); + const hours: u64 = self.hour + (days * 24); + const minutes: u64 = self.minute + (hours * 60); + const seconds: u64 = self.second + (minutes * std.time.s_per_min); return self.nanosecond + (seconds * std.time.ns_per_s); } }; diff --git a/lib/std/time.zig b/lib/std/time.zig index b4fd271205..b9808cf747 100644 --- a/lib/std/time.zig +++ b/lib/std/time.zig @@ -135,7 +135,7 @@ pub const Instant = struct { const clock_id = switch (builtin.os.tag) { .windows => { // QPC on windows doesn't fail on >= XP/2000 and includes time suspended. - return Instant{ .timestamp = windows.QueryPerformanceCounter() }; + return .{ .timestamp = windows.QueryPerformanceCounter() }; }, .wasi => { var ns: std.os.wasi.timestamp_t = undefined; @@ -147,7 +147,7 @@ pub const Instant = struct { 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() }; + return .{ .timestamp = value.toEpoch() }; }, // On darwin, use UPTIME_RAW instead of MONOTONIC as it ticks while // suspended. @@ -185,36 +185,38 @@ pub const Instant = struct { /// This assumes that the `earlier` Instant represents a moment in time before or equal to `self`. /// This also assumes that the time that has passed between both Instants fits inside a u64 (~585 yrs). pub fn since(self: Instant, earlier: Instant) u64 { - if (builtin.os.tag == .windows) { - // We don't need to cache QPF as it's internally just a memory read to KUSER_SHARED_DATA - // (a read-only page of info updated and mapped by the kernel to all processes): - // https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/ntddk/ns-ntddk-kuser_shared_data - // https://www.geoffchappell.com/studies/windows/km/ntoskrnl/inc/api/ntexapi_x/kuser_shared_data/index.htm - const qpc = self.timestamp - earlier.timestamp; - const qpf = windows.QueryPerformanceFrequency(); + switch (builtin.os.tag) { + .windows => { + // We don't need to cache QPF as it's internally just a memory read to KUSER_SHARED_DATA + // (a read-only page of info updated and mapped by the kernel to all processes): + // https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/ntddk/ns-ntddk-kuser_shared_data + // https://www.geoffchappell.com/studies/windows/km/ntoskrnl/inc/api/ntexapi_x/kuser_shared_data/index.htm + const qpc = self.timestamp - earlier.timestamp; + const qpf = windows.QueryPerformanceFrequency(); - // 10Mhz (1 qpc tick every 100ns) is a common enough QPF value that we can optimize on it. - // https://github.com/microsoft/STL/blob/785143a0c73f030238ef618890fd4d6ae2b3a3a0/stl/inc/chrono#L694-L701 - const common_qpf = 10_000_000; - if (qpf == common_qpf) { - return qpc * (ns_per_s / common_qpf); - } + // 10Mhz (1 qpc tick every 100ns) is a common enough QPF value that we can optimize on it. + // https://github.com/microsoft/STL/blob/785143a0c73f030238ef618890fd4d6ae2b3a3a0/stl/inc/chrono#L694-L701 + const common_qpf = 10_000_000; + if (qpf == common_qpf) { + return qpc * (ns_per_s / common_qpf); + } - // Convert to ns using fixed point. - const scale = @as(u64, std.time.ns_per_s << 32) / @as(u32, @intCast(qpf)); - const result = (@as(u96, qpc) * scale) >> 32; - return @as(u64, @truncate(result)); + // Convert to ns using fixed point. + const scale = @as(u64, std.time.ns_per_s << 32) / @as(u32, @intCast(qpf)); + const result = (@as(u96, qpc) * scale) >> 32; + return @as(u64, @truncate(result)); + }, + .uefi, .wasi => { + // UEFI and WASI timestamps are directly in nanoseconds + return self.timestamp - earlier.timestamp; + }, + else => { + // Convert timespec diff to ns + const seconds = @as(u64, @intCast(self.timestamp.sec - earlier.timestamp.sec)); + const elapsed = (seconds * ns_per_s) + @as(u32, @intCast(self.timestamp.nsec)); + return elapsed - @as(u32, @intCast(earlier.timestamp.nsec)); + }, } - - // WASI timestamps are directly in nanoseconds - if (builtin.os.tag == .wasi) { - return self.timestamp - earlier.timestamp; - } - - // Convert timespec diff to ns - const seconds = @as(u64, @intCast(self.timestamp.sec - earlier.timestamp.sec)); - const elapsed = (seconds * ns_per_s) + @as(u32, @intCast(self.timestamp.nsec)); - return elapsed - @as(u32, @intCast(earlier.timestamp.nsec)); } };