1
1
use crate :: time:: Duration ;
2
2
3
+ const SECS_IN_MINUTE : u64 = 60 ;
4
+
3
5
#[ derive( Copy , Clone , PartialEq , Eq , PartialOrd , Ord , Debug , Hash ) ]
4
6
pub struct Instant ( Duration ) ;
5
7
@@ -66,17 +68,32 @@ impl Instant {
66
68
}
67
69
68
70
impl SystemTime {
71
+ pub ( crate ) const ZERO : Self = Self ( Duration :: ZERO ) ;
72
+
69
73
pub ( crate ) const fn from_uefi ( t : r_efi:: efi:: Time ) -> Self {
70
74
Self ( system_time_internal:: from_uefi ( & t) )
71
75
}
72
76
73
- #[ expect( dead_code) ]
74
- pub ( crate ) const fn to_uefi ( self , timezone : i16 , daylight : u8 ) -> Option < r_efi:: efi:: Time > {
77
+ pub ( crate ) const fn to_uefi (
78
+ self ,
79
+ timezone : i16 ,
80
+ daylight : u8 ,
81
+ ) -> Result < r_efi:: efi:: Time , i16 > {
75
82
system_time_internal:: to_uefi ( & self . 0 , timezone, daylight)
76
83
}
77
84
85
+ /// Create UEFI Time with the closest timezone (minute offset) that still allows the time to be
86
+ /// represented.
87
+ pub ( crate ) fn to_uefi_loose ( self , timezone : i16 , daylight : u8 ) -> r_efi:: efi:: Time {
88
+ match self . to_uefi ( timezone, daylight) {
89
+ Ok ( x) => x,
90
+ Err ( tz) => self . to_uefi ( tz, daylight) . unwrap ( ) ,
91
+ }
92
+ }
93
+
78
94
pub fn now ( ) -> SystemTime {
79
95
system_time_internal:: now ( )
96
+ . map ( Self :: from_uefi)
80
97
. unwrap_or_else ( || panic ! ( "time not implemented on this platform" ) )
81
98
}
82
99
@@ -117,12 +134,11 @@ pub(crate) mod system_time_internal {
117
134
use crate :: mem:: MaybeUninit ;
118
135
use crate :: ptr:: NonNull ;
119
136
120
- const SECS_IN_MINUTE : u64 = 60 ;
121
137
const SECS_IN_HOUR : u64 = SECS_IN_MINUTE * 60 ;
122
138
const SECS_IN_DAY : u64 = SECS_IN_HOUR * 24 ;
123
139
const TIMEZONE_DELTA : u64 = 1440 * SECS_IN_MINUTE ;
124
140
125
- pub fn now ( ) -> Option < SystemTime > {
141
+ pub ( crate ) fn now ( ) -> Option < Time > {
126
142
let runtime_services: NonNull < RuntimeServices > = helpers:: runtime_services ( ) ?;
127
143
let mut t: MaybeUninit < Time > = MaybeUninit :: uninit ( ) ;
128
144
let r = unsafe {
@@ -132,9 +148,7 @@ pub(crate) mod system_time_internal {
132
148
return None ;
133
149
}
134
150
135
- let t = unsafe { t. assume_init ( ) } ;
136
-
137
- Some ( SystemTime :: from_uefi ( t) )
151
+ Some ( unsafe { t. assume_init ( ) } )
138
152
}
139
153
140
154
/// This algorithm is a modified form of the one described in the post
@@ -193,7 +207,10 @@ pub(crate) mod system_time_internal {
193
207
///
194
208
/// The changes are to use 1900-01-01-00:00:00 with timezone -1440 as anchor instead of UNIX
195
209
/// epoch used in the original algorithm.
196
- pub ( crate ) const fn to_uefi ( dur : & Duration , timezone : i16 , daylight : u8 ) -> Option < Time > {
210
+ pub ( crate ) const fn to_uefi ( dur : & Duration , timezone : i16 , daylight : u8 ) -> Result < Time , i16 > {
211
+ const MIN_IN_HOUR : u64 = 60 ;
212
+ const MIN_IN_DAY : u64 = MIN_IN_HOUR * 24 ;
213
+
197
214
// Check timzone validity
198
215
assert ! ( timezone <= 1440 && timezone >= -1440 ) ;
199
216
@@ -202,7 +219,11 @@ pub(crate) mod system_time_internal {
202
219
dur. as_secs ( ) . checked_add_signed ( ( -timezone as i64 ) * SECS_IN_MINUTE as i64 ) . unwrap ( ) ;
203
220
204
221
// Convert to seconds since 1900-01-01-00:00:00 in timezone.
205
- let Some ( secs) = secs. checked_sub ( TIMEZONE_DELTA ) else { return None } ;
222
+ let Some ( secs) = secs. checked_sub ( TIMEZONE_DELTA ) else {
223
+ let new_tz =
224
+ ( secs / SECS_IN_MINUTE - if secs % SECS_IN_MINUTE == 0 { 0 } else { 1 } ) as i16 ;
225
+ return Err ( new_tz) ;
226
+ } ;
206
227
207
228
let days = secs / SECS_IN_DAY ;
208
229
let remaining_secs = secs % SECS_IN_DAY ;
@@ -225,9 +246,10 @@ pub(crate) mod system_time_internal {
225
246
let minute = ( ( remaining_secs % SECS_IN_HOUR ) / SECS_IN_MINUTE ) as u8 ;
226
247
let second = ( remaining_secs % SECS_IN_MINUTE ) as u8 ;
227
248
228
- // Check Bounds
229
- if y >= 1900 && y <= 9999 {
230
- Some ( Time {
249
+ // At this point, invalid time will be greater than MAX representable time. It cannot be less
250
+ // than minimum time since we already take care of that case above.
251
+ if y <= 9999 {
252
+ Ok ( Time {
231
253
year : y as u16 ,
232
254
month : m as u8 ,
233
255
day : d as u8 ,
@@ -241,7 +263,17 @@ pub(crate) mod system_time_internal {
241
263
pad2 : 0 ,
242
264
} )
243
265
} else {
244
- None
266
+ assert ! ( y == 10000 ) ;
267
+ assert ! ( m == 1 ) ;
268
+
269
+ let delta = ( ( d - 1 ) as u64 * MIN_IN_DAY
270
+ + hour as u64 * MIN_IN_HOUR
271
+ + minute as u64
272
+ + if second == 0 { 0 } else { 1 } ) as i16 ;
273
+ let new_tz = timezone + delta;
274
+
275
+ assert ! ( new_tz <= 1440 && new_tz >= -1440 ) ;
276
+ Err ( new_tz)
245
277
}
246
278
}
247
279
}
0 commit comments