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
@@ -70,11 +72,23 @@ impl SystemTime {
70
72
Self ( system_time_internal:: from_uefi ( & t) )
71
73
}
72
74
73
- #[ expect( dead_code) ]
74
- pub ( crate ) const fn to_uefi ( self , timezone : i16 , daylight : u8 ) -> Option < r_efi:: efi:: Time > {
75
+ pub ( crate ) const fn to_uefi (
76
+ self ,
77
+ timezone : i16 ,
78
+ daylight : u8 ,
79
+ ) -> Result < r_efi:: efi:: Time , i16 > {
75
80
system_time_internal:: to_uefi ( & self . 0 , timezone, daylight)
76
81
}
77
82
83
+ /// Create UEFI Time with the closes timezone (minute offset) that still allows the time to be
84
+ /// represented.
85
+ pub ( crate ) fn to_uefi_loose ( self , timezone : i16 , daylight : u8 ) -> r_efi:: efi:: Time {
86
+ match self . to_uefi ( timezone, daylight) {
87
+ Ok ( x) => x,
88
+ Err ( tz) => self . to_uefi ( tz, daylight) . unwrap ( ) ,
89
+ }
90
+ }
91
+
78
92
pub fn now ( ) -> SystemTime {
79
93
system_time_internal:: now ( )
80
94
. unwrap_or_else ( || panic ! ( "time not implemented on this platform" ) )
@@ -104,7 +118,6 @@ pub(crate) mod system_time_internal {
104
118
use crate :: mem:: MaybeUninit ;
105
119
use crate :: ptr:: NonNull ;
106
120
107
- const SECS_IN_MINUTE : u64 = 60 ;
108
121
const SECS_IN_HOUR : u64 = SECS_IN_MINUTE * 60 ;
109
122
const SECS_IN_DAY : u64 = SECS_IN_HOUR * 24 ;
110
123
const TIMEZONE_DELTA : u64 = 1440 * SECS_IN_MINUTE ;
@@ -180,7 +193,10 @@ pub(crate) mod system_time_internal {
180
193
///
181
194
/// The changes are to use 1900-01-01-00:00:00 with timezone -1440 as anchor instead of UNIX
182
195
/// epoch used in the original algorithm.
183
- pub ( crate ) const fn to_uefi ( dur : & Duration , timezone : i16 , daylight : u8 ) -> Option < Time > {
196
+ pub ( crate ) const fn to_uefi ( dur : & Duration , timezone : i16 , daylight : u8 ) -> Result < Time , i16 > {
197
+ const MIN_IN_HOUR : u64 = 60 ;
198
+ const MIN_IN_DAY : u64 = MIN_IN_HOUR * 24 ;
199
+
184
200
// Check timzone validity
185
201
assert ! ( timezone <= 1440 && timezone >= -1440 ) ;
186
202
@@ -189,7 +205,11 @@ pub(crate) mod system_time_internal {
189
205
dur. as_secs ( ) . checked_add_signed ( ( -timezone as i64 ) * SECS_IN_MINUTE as i64 ) . unwrap ( ) ;
190
206
191
207
// Convert to seconds since 1900-01-01-00:00:00 in timezone.
192
- let Some ( secs) = secs. checked_sub ( TIMEZONE_DELTA ) else { return None } ;
208
+ let Some ( secs) = secs. checked_sub ( TIMEZONE_DELTA ) else {
209
+ let new_tz =
210
+ ( secs / SECS_IN_MINUTE - if secs % SECS_IN_MINUTE == 0 { 0 } else { 1 } ) as i16 ;
211
+ return Err ( new_tz) ;
212
+ } ;
193
213
194
214
let days = secs / SECS_IN_DAY ;
195
215
let remaining_secs = secs % SECS_IN_DAY ;
@@ -212,9 +232,10 @@ pub(crate) mod system_time_internal {
212
232
let minute = ( ( remaining_secs % SECS_IN_HOUR ) / SECS_IN_MINUTE ) as u8 ;
213
233
let second = ( remaining_secs % SECS_IN_MINUTE ) as u8 ;
214
234
215
- // Check Bounds
216
- if y >= 1900 && y <= 9999 {
217
- Some ( Time {
235
+ // At this point, invalid time will be greater than MAX representable time. It cannot be less
236
+ // than minimum time since we already take care of that case above.
237
+ if y <= 9999 {
238
+ Ok ( Time {
218
239
year : y as u16 ,
219
240
month : m as u8 ,
220
241
day : d as u8 ,
@@ -228,7 +249,17 @@ pub(crate) mod system_time_internal {
228
249
pad2 : 0 ,
229
250
} )
230
251
} else {
231
- None
252
+ assert ! ( y == 10000 ) ;
253
+ assert ! ( m == 1 ) ;
254
+
255
+ let delta = ( ( d - 1 ) as u64 * MIN_IN_DAY
256
+ + hour as u64 * MIN_IN_HOUR
257
+ + minute as u64
258
+ + if second == 0 { 0 } else { 1 } ) as i16 ;
259
+ let new_tz = timezone + delta;
260
+
261
+ assert ! ( new_tz <= 1440 && new_tz >= -1440 ) ;
262
+ Err ( new_tz)
232
263
}
233
264
}
234
265
}
0 commit comments