Skip to content

Commit b560562

Browse files
committed
std: sys: pal: uefi: tests: Add systemtime tests
Add tests to ensure that extream system times are still representable. Signed-off-by: Ayush Singh <[email protected]>
1 parent 40d31f8 commit b560562

File tree

2 files changed

+99
-17
lines changed

2 files changed

+99
-17
lines changed

library/std/src/sys/pal/uefi/tests.rs

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
11
use super::alloc::*;
2+
use super::time::system_time_internal::{from_uefi, to_uefi};
3+
use crate::time::Duration;
4+
5+
const SECS_IN_MINUTE: u64 = 60;
26

37
#[test]
48
fn align() {
@@ -19,3 +23,62 @@ fn align() {
1923
}
2024
}
2125
}
26+
27+
#[test]
28+
fn systemtime_start() {
29+
let t = r_efi::efi::Time {
30+
year: 1900,
31+
month: 1,
32+
day: 1,
33+
hour: 0,
34+
minute: 0,
35+
second: 0,
36+
pad1: 0,
37+
nanosecond: 0,
38+
timezone: -1440,
39+
daylight: 0,
40+
pad2: 0,
41+
};
42+
assert_eq!(from_uefi(&t), Duration::new(0, 0));
43+
assert_eq!(t, to_uefi(&from_uefi(&t), -1440, 0).unwrap());
44+
assert!(to_uefi(&from_uefi(&t), 0, 0).is_none());
45+
}
46+
47+
#[test]
48+
fn systemtime_utc_start() {
49+
let t = r_efi::efi::Time {
50+
year: 1900,
51+
month: 1,
52+
day: 1,
53+
hour: 0,
54+
minute: 0,
55+
second: 0,
56+
pad1: 0,
57+
nanosecond: 0,
58+
timezone: 0,
59+
daylight: 0,
60+
pad2: 0,
61+
};
62+
assert_eq!(from_uefi(&t), Duration::new(1440 * SECS_IN_MINUTE, 0));
63+
assert_eq!(t, to_uefi(&from_uefi(&t), 0, 0).unwrap());
64+
assert!(to_uefi(&from_uefi(&t), -1440, 0).is_some());
65+
}
66+
67+
#[test]
68+
fn systemtime_end() {
69+
let t = r_efi::efi::Time {
70+
year: 9999,
71+
month: 12,
72+
day: 31,
73+
hour: 23,
74+
minute: 59,
75+
second: 59,
76+
pad1: 0,
77+
nanosecond: 0,
78+
timezone: 1440,
79+
daylight: 0,
80+
pad2: 0,
81+
};
82+
assert!(to_uefi(&from_uefi(&t), 1440, 0).is_some());
83+
assert!(to_uefi(&from_uefi(&t), 1439, 0).is_none());
84+
}

library/std/src/sys/pal/uefi/time.rs

Lines changed: 36 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ pub struct Instant(Duration);
66
/// When a Timezone is specified, the stored Duration is in UTC. If timezone is unspecified, then
77
/// the timezone is assumed to be in UTC.
88
///
9-
/// UEFI SystemTime is stored as Duration from 1900-01-01-00:00:00
9+
/// UEFI SystemTime is stored as Duration from 1900-01-01-00:00:00 with timezone -1440 as anchor
1010
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
1111
pub struct SystemTime(Duration);
1212

@@ -24,6 +24,20 @@ pub const UNIX_EPOCH: SystemTime = SystemTime::from_uefi(r_efi::efi::Time {
2424
pad2: 0,
2525
});
2626

27+
const MAX_UEFI_TIME: SystemTime = SystemTime::from_uefi(r_efi::efi::Time {
28+
year: 9999,
29+
month: 12,
30+
day: 31,
31+
hour: 23,
32+
minute: 59,
33+
second: 59,
34+
nanosecond: 999_999_999,
35+
timezone: 1440,
36+
daylight: 0,
37+
pad1: 0,
38+
pad2: 0,
39+
});
40+
2741
impl Instant {
2842
pub fn now() -> Instant {
2943
// If we have a timestamp protocol, use it.
@@ -56,6 +70,7 @@ impl SystemTime {
5670
Self(system_time_internal::from_uefi(&t))
5771
}
5872

73+
#[expect(dead_code)]
5974
pub(crate) const fn to_uefi(self, timezone: i16, daylight: u8) -> Option<r_efi::efi::Time> {
6075
system_time_internal::to_uefi(&self.0, timezone, daylight)
6176
}
@@ -73,14 +88,11 @@ impl SystemTime {
7388
let temp = Self(self.0.checked_add(*other)?);
7489

7590
// Check if can be represented in UEFI
76-
if temp.to_uefi(0, 0).is_some() { Some(temp) } else { None }
91+
if temp <= MAX_UEFI_TIME { Some(temp) } else { None }
7792
}
7893

7994
pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
80-
let temp = Self(self.0.checked_sub(*other)?);
81-
82-
// Check if can be represented in UEFI
83-
if temp.to_uefi(0, 0).is_some() { Some(temp) } else { None }
95+
self.0.checked_sub(*other).map(Self)
8496
}
8597
}
8698

@@ -113,8 +125,19 @@ pub(crate) mod system_time_internal {
113125
}
114126

115127
pub(crate) const fn from_uefi(t: &Time) -> Duration {
116-
assert!(t.month <= 12);
117-
assert!(t.month != 0);
128+
assert!(t.month <= 12 && t.month != 0);
129+
assert!(t.year >= 1900 && t.year <= 9999);
130+
assert!(t.day <= 31 && t.day != 0);
131+
132+
assert!(t.second < 60);
133+
assert!(t.minute < 60);
134+
assert!(t.hour < 24);
135+
assert!(t.nanosecond < 1_000_000_000);
136+
137+
assert!(
138+
(t.timezone <= 1440 && t.timezone >= -1440)
139+
|| t.timezone == r_efi::efi::UNSPECIFIED_TIMEZONE
140+
);
118141

119142
const YEAR_BASE: u32 = 4800; /* Before min year, multiple of 400. */
120143

@@ -148,17 +171,13 @@ pub(crate) mod system_time_internal {
148171

149172
pub(crate) const fn to_uefi(dur: &Duration, timezone: i16, daylight: u8) -> Option<Time> {
150173
// Check timzone validity
151-
assert!(timezone <= 1440);
152-
assert!(timezone >= -1440);
174+
assert!(timezone <= 1440 && timezone >= -1440);
153175

154-
let secs: u64 = if timezone == r_efi::efi::UNSPECIFIED_TIMEZONE {
155-
dur.as_secs()
156-
} else {
157-
// FIXME: use checked_sub_signed once stablized
158-
dur.as_secs().checked_add_signed((-timezone as i64) * SECS_IN_MINUTE as i64).unwrap()
159-
};
176+
// FIXME(#126043): use checked_sub_signed once stablized
177+
let secs =
178+
dur.as_secs().checked_add_signed((-timezone as i64) * SECS_IN_MINUTE as i64).unwrap();
160179

161-
// Convert to UTC
180+
// Convert to seconds since 1900-01-01-00:00:00 in timezone.
162181
let Some(secs) = secs.checked_sub(TIMEZONE_DELTA) else { return None };
163182

164183
let days = secs / SECS_IN_DAY;

0 commit comments

Comments
 (0)