@@ -77,11 +77,8 @@ pub(crate) mod function {
7777
7878    use  crate :: { 
7979        parse:: { relative,  Error } , 
80-         time:: { 
81-             format:: { DEFAULT ,  GITOXIDE ,  ISO8601 ,  ISO8601_STRICT ,  SHORT } , 
82-             Sign , 
83-         } , 
84-         SecondsSinceUnixEpoch ,  Time , 
80+         time:: format:: { DEFAULT ,  GITOXIDE ,  ISO8601 ,  ISO8601_STRICT ,  SHORT } , 
81+         OffsetInSeconds ,  SecondsSinceUnixEpoch ,  Time , 
8582    } ; 
8683
8784    /// Parse `input` as any time that Git can parse when inputting a date. 
@@ -169,46 +166,73 @@ pub(crate) mod function {
169166        }  else  if  let  Ok ( val)  = SecondsSinceUnixEpoch :: from_str ( input)  { 
170167            // Format::Unix 
171168            Time :: new ( val,  0 ) 
169+         }  else  if  let  Some ( val)  = relative:: parse ( input,  now) . transpose ( ) ? { 
170+             Time :: new ( val. timestamp ( ) . as_second ( ) ,  val. offset ( ) . seconds ( ) ) 
172171        }  else  if  let  Some ( val)  = parse_header ( input)  { 
173172            // Format::Raw 
174173            val
175-         }  else  if  let  Some ( val)  = relative:: parse ( input,  now) . transpose ( ) ? { 
176-             Time :: new ( val. timestamp ( ) . as_second ( ) ,  val. offset ( ) . seconds ( ) ) 
177174        }  else  { 
178175            return  Err ( Error :: InvalidDateString  {  input :  input. into ( )  } ) ; 
179176        } ) 
180177    } 
181178
182179    /// Unlike [`parse()`] which handles all kinds of input, this function only parses the commit-header format 
183180     /// like `1745582210 +0200`. 
181+      /// 
182+      /// Note that failure to parse the time zone isn't fatal, instead it will default to `0`. To know if 
183+      /// the time is wonky, serialize the return value to see if it matches the `input.` 
184184     pub  fn  parse_header ( input :  & str )  -> Option < Time >  { 
185-         let  mut  split = input. split_whitespace ( ) ; 
186-         let  seconds:  SecondsSinceUnixEpoch  = split. next ( ) ?. parse ( ) . ok ( ) ?; 
187-         let  offset = split. next ( ) ?; 
188-         if  ( offset. len ( )  != 5 )  && ( offset. len ( )  != 7 )  || split. next ( ) . is_some ( )  { 
189-             return  None ; 
185+         pub  enum  Sign  { 
186+             Plus , 
187+             Minus , 
190188        } 
191-         let  sign = match  offset. get ( ..1 ) ? { 
192-             "-"  => Some ( Sign :: Minus ) , 
193-             "+"  => Some ( Sign :: Plus ) , 
194-             _ => None , 
195-         } ?; 
196-         let  hours:  i32  = offset. get ( 1 ..3 ) ?. parse ( ) . ok ( ) ?; 
197-         let  minutes:  i32  = offset. get ( 3 ..5 ) ?. parse ( ) . ok ( ) ?; 
198-         let  offset_seconds:  i32  = if  offset. len ( )  == 7  { 
199-             offset. get ( 5 ..7 ) ?. parse ( ) . ok ( ) ?
200-         }  else  { 
201-             0 
202-         } ; 
203-         let  mut  offset_in_seconds = hours *  3600  + minutes *  60  + offset_seconds; 
204-         if  sign == Sign :: Minus  { 
205-             offset_in_seconds *= -1 ; 
189+         fn  parse_offset ( offset :  & str )  -> Option < OffsetInSeconds >  { 
190+             if  ( offset. len ( )  != 5 )  && ( offset. len ( )  != 7 )  { 
191+                 return  None ; 
192+             } 
193+             let  sign = match  offset. get ( ..1 ) ? { 
194+                 "-"  => Some ( Sign :: Minus ) , 
195+                 "+"  => Some ( Sign :: Plus ) , 
196+                 _ => None , 
197+             } ?; 
198+             if  offset. as_bytes ( ) . get ( 1 ) . is_some_and ( |b| !b. is_ascii_digit ( ) )  { 
199+                 return  None ; 
200+             } 
201+             let  hours:  i32  = offset. get ( 1 ..3 ) ?. parse ( ) . ok ( ) ?; 
202+             let  minutes:  i32  = offset. get ( 3 ..5 ) ?. parse ( ) . ok ( ) ?; 
203+             let  offset_seconds:  i32  = if  offset. len ( )  == 7  { 
204+                 offset. get ( 5 ..7 ) ?. parse ( ) . ok ( ) ?
205+             }  else  { 
206+                 0 
207+             } ; 
208+             let  mut  offset_in_seconds = hours *  3600  + minutes *  60  + offset_seconds; 
209+             if  matches ! ( sign,  Sign :: Minus )  { 
210+                 offset_in_seconds *= -1 ; 
211+             } 
212+             Some ( offset_in_seconds) 
206213        } 
207-         let  time = Time  { 
208-             seconds, 
209-             offset :  offset_in_seconds, 
210-             sign, 
214+ 
215+         let  mut  split = input. split_whitespace ( ) ; 
216+         let  seconds = split. next ( ) ?; 
217+         let  seconds = match  seconds. parse :: < SecondsSinceUnixEpoch > ( )  { 
218+             Ok ( s)  => s, 
219+             Err ( _err)  => { 
220+                 // Inefficient, but it's not the common case. 
221+                 let  first_digits:  String  = seconds. chars ( ) . take_while ( |b| b. is_ascii_digit ( ) ) . collect ( ) ; 
222+                 first_digits. parse ( ) . ok ( ) ?
223+             } 
224+         } ; 
225+         let  offset = match  split. next ( )  { 
226+             None  => 0 , 
227+             Some ( offset)  => { 
228+                 if  split. next ( ) . is_some ( )  { 
229+                     0 
230+                 }  else  { 
231+                     parse_offset ( offset) . unwrap_or_default ( ) 
232+                 } 
233+             } 
211234        } ; 
235+         let  time = Time  {  seconds,  offset } ; 
212236        Some ( time) 
213237    } 
214238
0 commit comments