11use crate :: time:: Duration ;
22
3+ const SECS_IN_MINUTE : u64 = 60 ;
4+
35#[ derive( Copy , Clone , PartialEq , Eq , PartialOrd , Ord , Debug , Hash ) ]
46pub struct Instant ( Duration ) ;
57
@@ -70,11 +72,23 @@ impl SystemTime {
7072 Self ( system_time_internal:: from_uefi ( & t) )
7173 }
7274
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 > {
7580 system_time_internal:: to_uefi ( & self . 0 , timezone, daylight)
7681 }
7782
83+ /// Create UEFI Time with the closest 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+
7892 pub fn now ( ) -> SystemTime {
7993 system_time_internal:: now ( )
8094 . unwrap_or_else ( || panic ! ( "time not implemented on this platform" ) )
@@ -117,7 +131,6 @@ pub(crate) mod system_time_internal {
117131 use crate :: mem:: MaybeUninit ;
118132 use crate :: ptr:: NonNull ;
119133
120- const SECS_IN_MINUTE : u64 = 60 ;
121134 const SECS_IN_HOUR : u64 = SECS_IN_MINUTE * 60 ;
122135 const SECS_IN_DAY : u64 = SECS_IN_HOUR * 24 ;
123136 const TIMEZONE_DELTA : u64 = 1440 * SECS_IN_MINUTE ;
@@ -193,7 +206,10 @@ pub(crate) mod system_time_internal {
193206 ///
194207 /// The changes are to use 1900-01-01-00:00:00 with timezone -1440 as anchor instead of UNIX
195208 /// epoch used in the original algorithm.
196- pub ( crate ) const fn to_uefi ( dur : & Duration , timezone : i16 , daylight : u8 ) -> Option < Time > {
209+ pub ( crate ) const fn to_uefi ( dur : & Duration , timezone : i16 , daylight : u8 ) -> Result < Time , i16 > {
210+ const MIN_IN_HOUR : u64 = 60 ;
211+ const MIN_IN_DAY : u64 = MIN_IN_HOUR * 24 ;
212+
197213 // Check timzone validity
198214 assert ! ( timezone <= 1440 && timezone >= -1440 ) ;
199215
@@ -202,7 +218,11 @@ pub(crate) mod system_time_internal {
202218 dur. as_secs ( ) . checked_add_signed ( ( -timezone as i64 ) * SECS_IN_MINUTE as i64 ) . unwrap ( ) ;
203219
204220 // Convert to seconds since 1900-01-01-00:00:00 in timezone.
205- let Some ( secs) = secs. checked_sub ( TIMEZONE_DELTA ) else { return None } ;
221+ let Some ( secs) = secs. checked_sub ( TIMEZONE_DELTA ) else {
222+ let new_tz =
223+ ( secs / SECS_IN_MINUTE - if secs % SECS_IN_MINUTE == 0 { 0 } else { 1 } ) as i16 ;
224+ return Err ( new_tz) ;
225+ } ;
206226
207227 let days = secs / SECS_IN_DAY ;
208228 let remaining_secs = secs % SECS_IN_DAY ;
@@ -225,9 +245,10 @@ pub(crate) mod system_time_internal {
225245 let minute = ( ( remaining_secs % SECS_IN_HOUR ) / SECS_IN_MINUTE ) as u8 ;
226246 let second = ( remaining_secs % SECS_IN_MINUTE ) as u8 ;
227247
228- // Check Bounds
229- if y >= 1900 && y <= 9999 {
230- Some ( Time {
248+ // At this point, invalid time will be greater than MAX representable time. It cannot be less
249+ // than minimum time since we already take care of that case above.
250+ if y <= 9999 {
251+ Ok ( Time {
231252 year : y as u16 ,
232253 month : m as u8 ,
233254 day : d as u8 ,
@@ -241,7 +262,17 @@ pub(crate) mod system_time_internal {
241262 pad2 : 0 ,
242263 } )
243264 } else {
244- None
265+ assert ! ( y == 10000 ) ;
266+ assert ! ( m == 1 ) ;
267+
268+ let delta = ( ( d - 1 ) as u64 * MIN_IN_DAY
269+ + hour as u64 * MIN_IN_HOUR
270+ + minute as u64
271+ + if second == 0 { 0 } else { 1 } ) as i16 ;
272+ let new_tz = timezone + delta;
273+
274+ assert ! ( new_tz <= 1440 && new_tz >= -1440 ) ;
275+ Err ( new_tz)
245276 }
246277 }
247278}
0 commit comments