@@ -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