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,13 +72,32 @@ 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-         system_time_internal:: to_uefi ( & self . 0 ,  timezone,  daylight) 
75+     pub ( crate )  const  fn  to_uefi ( 
76+         self , 
77+         timezone :  i16 , 
78+         daylight :  u8 , 
79+     )  -> Result < r_efi:: efi:: Time ,  i16 >  { 
80+         // system_time_internal::to_uefi requires a valid timezone. In case of unspecified timezone, 
81+         // we just pass 0 since it is assumed that no timezone related adjustments are required. 
82+         if  timezone == r_efi:: efi:: UNSPECIFIED_TIMEZONE  { 
83+             system_time_internal:: to_uefi ( & self . 0 ,  0 ,  daylight) 
84+         }  else  { 
85+             system_time_internal:: to_uefi ( & self . 0 ,  timezone,  daylight) 
86+         } 
87+     } 
88+ 
89+     /// Create UEFI Time with the closest timezone (minute offset) that still allows the time to be 
90+ /// represented. 
91+ pub ( crate )  fn  to_uefi_loose ( self ,  timezone :  i16 ,  daylight :  u8 )  -> r_efi:: efi:: Time  { 
92+         match  self . to_uefi ( timezone,  daylight)  { 
93+             Ok ( x)  => x, 
94+             Err ( tz)  => self . to_uefi ( tz,  daylight) . unwrap ( ) , 
95+         } 
7696    } 
7797
7898    pub  fn  now ( )  -> SystemTime  { 
7999        system_time_internal:: now ( ) 
100+             . map ( Self :: from_uefi) 
80101            . unwrap_or_else ( || panic ! ( "time not implemented on this platform" ) ) 
81102    } 
82103
@@ -117,12 +138,11 @@ pub(crate) mod system_time_internal {
117138    use  crate :: mem:: MaybeUninit ; 
118139    use  crate :: ptr:: NonNull ; 
119140
120-     const  SECS_IN_MINUTE :  u64  = 60 ; 
121141    const  SECS_IN_HOUR :  u64  = SECS_IN_MINUTE  *  60 ; 
122142    const  SECS_IN_DAY :  u64  = SECS_IN_HOUR  *  24 ; 
123-     const  TIMEZONE_DELTA :  u64  = 1440  *  SECS_IN_MINUTE ; 
143+     const  SYSTEMTIME_TIMEZONE :  u64  = 1440  *  SECS_IN_MINUTE ; 
124144
125-     pub  fn  now ( )  -> Option < SystemTime >  { 
145+     pub ( crate )  fn  now ( )  -> Option < Time >  { 
126146        let  runtime_services:  NonNull < RuntimeServices >  = helpers:: runtime_services ( ) ?; 
127147        let  mut  t:  MaybeUninit < Time >  = MaybeUninit :: uninit ( ) ; 
128148        let  r = unsafe  { 
@@ -132,9 +152,7 @@ pub(crate) mod system_time_internal {
132152            return  None ; 
133153        } 
134154
135-         let  t = unsafe  {  t. assume_init ( )  } ; 
136- 
137-         Some ( SystemTime :: from_uefi ( t) ) 
155+         Some ( unsafe  {  t. assume_init ( )  } ) 
138156    } 
139157
140158    /// This algorithm is a modified form of the one described in the post 
@@ -175,7 +193,7 @@ pub(crate) mod system_time_internal {
175193            + ( t. hour  as  u64 )  *  SECS_IN_HOUR ; 
176194
177195        // Calculate the offset from 1/1/1900 at timezone -1440 min 
178-         let  adjusted_localtime_epoc:  u64  = localtime_epoch + TIMEZONE_DELTA ; 
196+         let  adjusted_localtime_epoc:  u64  = localtime_epoch + SYSTEMTIME_TIMEZONE ; 
179197
180198        let  epoch:  u64  = if  t. timezone  == r_efi:: efi:: UNSPECIFIED_TIMEZONE  { 
181199            adjusted_localtime_epoc
@@ -193,16 +211,24 @@ pub(crate) mod system_time_internal {
193211/// 
194212/// The changes are to use 1900-01-01-00:00:00 with timezone -1440 as anchor instead of UNIX 
195213/// epoch used in the original algorithm. 
196- pub ( crate )  const  fn  to_uefi ( dur :  & Duration ,  timezone :  i16 ,  daylight :  u8 )  -> Option < Time >  { 
214+ pub ( crate )  const  fn  to_uefi ( dur :  & Duration ,  timezone :  i16 ,  daylight :  u8 )  -> Result < Time ,  i16 >  { 
215+         const  MIN_IN_HOUR :  u64  = 60 ; 
216+         const  MIN_IN_DAY :  u64  = MIN_IN_HOUR  *  24 ; 
217+ 
197218        // Check timzone validity 
198219        assert ! ( timezone <= 1440  && timezone >= -1440 ) ; 
199220
200221        // FIXME(#126043): use checked_sub_signed once stabilized 
222+         // This cannot fail for valid SystemTime due to SYSTEMTIME_TIMEZONE 
201223        let  secs =
202224            dur. as_secs ( ) . checked_add_signed ( ( -timezone as  i64 )  *  SECS_IN_MINUTE  as  i64 ) . unwrap ( ) ; 
203225
204226        // Convert to seconds since 1900-01-01-00:00:00 in timezone. 
205-         let  Some ( secs)  = secs. checked_sub ( TIMEZONE_DELTA )  else  {  return  None  } ; 
227+         let  Some ( secs)  = secs. checked_sub ( SYSTEMTIME_TIMEZONE )  else  { 
228+             let  new_tz =
229+                 ( secs / SECS_IN_MINUTE  - if  secs % SECS_IN_MINUTE  == 0  {  0  }  else  {  1  } )  as  i16 ; 
230+             return  Err ( new_tz) ; 
231+         } ; 
206232
207233        let  days = secs / SECS_IN_DAY ; 
208234        let  remaining_secs = secs % SECS_IN_DAY ; 
@@ -225,9 +251,10 @@ pub(crate) mod system_time_internal {
225251        let  minute = ( ( remaining_secs % SECS_IN_HOUR )  / SECS_IN_MINUTE )  as  u8 ; 
226252        let  second = ( remaining_secs % SECS_IN_MINUTE )  as  u8 ; 
227253
228-         // Check Bounds 
229-         if  y >= 1900  && y <= 9999  { 
230-             Some ( Time  { 
254+         // At this point, invalid time will be greater than MAX representable time. It cannot be less 
255+         // than minimum time since we already take care of that case above. 
256+         if  y <= 9999  { 
257+             Ok ( Time  { 
231258                year :  y as  u16 , 
232259                month :  m as  u8 , 
233260                day :  d as  u8 , 
@@ -241,7 +268,17 @@ pub(crate) mod system_time_internal {
241268                pad2 :  0 , 
242269            } ) 
243270        }  else  { 
244-             None 
271+             assert ! ( y == 10000 ) ; 
272+             assert ! ( m == 1 ) ; 
273+ 
274+             let  delta = ( ( d - 1 )  as  u64  *  MIN_IN_DAY 
275+                 + hour as  u64  *  MIN_IN_HOUR 
276+                 + minute as  u64 
277+                 + if  second == 0  {  0  }  else  {  1  } )  as  i16 ; 
278+             let  new_tz = timezone + delta; 
279+ 
280+             assert ! ( new_tz <= 1440  && new_tz >= -1440 ) ; 
281+             Err ( new_tz) 
245282        } 
246283    } 
247284} 
0 commit comments