uefi_specs/uefi/
time.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4//! UEFI Time Services.
5
6use bitfield_struct::bitfield;
7use core::fmt::Display;
8use static_assertions::const_assert_eq;
9use zerocopy::FromBytes;
10use zerocopy::FromZeros;
11use zerocopy::Immutable;
12use zerocopy::IntoBytes;
13use zerocopy::KnownLayout;
14
15/// UEFI Time Structure
16///
17/// UEFI spec 8.3 - Time Services
18///
19/// ```text
20///  Year:       1900 - 9999
21///  Month:      1 - 12
22///  Day:        1 - 31
23///  Hour:       0 - 23
24///  Minute:     0 - 59
25///  Second:     0 - 59
26///  Nanosecond: 0 - 999,999,999
27///  TimeZone:   -1440 to 1440 or 2047
28/// ```
29#[repr(C)]
30#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout, PartialEq, Eq)]
31#[cfg_attr(feature = "inspect", derive(inspect::Inspect), inspect(display))]
32pub struct EFI_TIME {
33    pub year: u16,
34    pub month: u8,
35    pub day: u8,
36    pub hour: u8,
37    pub minute: u8,
38    pub second: u8,
39    pub pad1: u8,
40    pub nanosecond: u32,
41    pub timezone: EfiTimezone,
42    pub daylight: EfiDaylight,
43    pub pad2: u8,
44}
45
46// Default + FromBytes: The UEFI spec explicitly uses all-zero EFI_TIME as a
47// default value
48impl Default for EFI_TIME {
49    fn default() -> Self {
50        Self::new_zeroed()
51    }
52}
53
54const_assert_eq!(size_of::<EFI_TIME>(), 16);
55
56impl EFI_TIME {
57    /// EFI_TIME with all fields set to zero
58    pub const ZEROED: EFI_TIME = EFI_TIME {
59        year: 0,
60        month: 0,
61        day: 0,
62        hour: 0,
63        minute: 0,
64        second: 0,
65        pad1: 0,
66        nanosecond: 0,
67        timezone: EfiTimezone(0),
68        daylight: EfiDaylight::new(),
69        pad2: 0,
70    };
71}
72
73impl Display for EFI_TIME {
74    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
75        // ISO-8601: 2022-02-17T04:54:13Z
76        write!(
77            f,
78            "{:04}-{:02}-{:02}T{:02}:{:02}:{:02}",
79            self.year, self.month, self.day, self.hour, self.minute, self.second
80        )?;
81        if self.nanosecond != 0 {
82            write!(f, ".{:09}", self.nanosecond)?;
83        }
84        if self.timezone.0 == 0 {
85            write!(f, "Z")?;
86        } else if self.timezone != EFI_UNSPECIFIED_TIMEZONE {
87            let sign = if self.timezone.0 > 0 { '+' } else { '-' };
88            let timezone = (self.timezone.0 as i32).abs();
89            write!(f, "{sign}{:02}:{:02}", timezone / 60, timezone % 60)?;
90        }
91        Ok(())
92    }
93}
94
95/// Value Definition for EFI_TIME.TimeZone
96/// from UEFI spec 8.3 - Time Services
97pub const EFI_UNSPECIFIED_TIMEZONE: EfiTimezone = EfiTimezone(0x07FF);
98
99/// Timezone in minutes from UTC
100///
101/// Valid values include -1440 to 1440 or 2047 (EFI_UNSPECIFIED_TIMEZONE)
102#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout, PartialEq, Eq)]
103#[repr(transparent)]
104#[cfg_attr(feature = "inspect", derive(inspect::Inspect), inspect(transparent))]
105pub struct EfiTimezone(pub i16);
106
107impl EfiTimezone {
108    pub fn valid(&self) -> bool {
109        self.0 > -1440 && (self.0 < 1440 || *self == EFI_UNSPECIFIED_TIMEZONE)
110    }
111}
112
113/// Bit Definitions for EFI_TIME.EfiDaylight
114/// from UEFI spec 8.3 - Time Services
115#[bitfield(u8)]
116#[derive(IntoBytes, FromBytes, Immutable, KnownLayout, PartialEq, Eq)]
117#[cfg_attr(feature = "inspect", derive(inspect::Inspect), inspect(transparent))]
118pub struct EfiDaylight {
119    /// EFI_TIME_ADJUST_DAYLIGHT
120    ///
121    /// the time is affected by daylight savings time
122    pub adjust_daylight: bool,
123
124    /// EFI_TIME_IN_DAYLIGHT
125    ///
126    /// the time has been adjusted for daylight savings time
127    pub in_daylight: bool,
128
129    #[bits(6)]
130    rsvd: u8,
131}
132
133impl EfiDaylight {
134    pub fn valid(&self) -> bool {
135        self.rsvd() == 0
136    }
137}