11use std:: { str:: FromStr , time:: SystemTime } ;
22
3+ use crate :: Error ;
4+ use gix_error:: { ensure, ParseError , Result , ResultExt } ;
35use jiff:: { tz:: TimeZone , Span , Timestamp , Zoned } ;
46
5- use crate :: parse:: Error ;
6-
77fn parse_inner ( input : & str ) -> Option < Result < Span , Error > > {
88 let mut split = input. split_whitespace ( ) ;
99 let units = i64:: from_str ( split. next ( ) ?) . ok ( ) ?;
@@ -15,26 +15,24 @@ fn parse_inner(input: &str) -> Option<Result<Span, Error>> {
1515}
1616
1717pub fn parse ( input : & str , now : Option < SystemTime > ) -> Option < Result < Zoned , Error > > {
18- parse_inner ( input) . map ( |result| {
18+ parse_inner ( input) . map ( |result| -> Result < Zoned , Error > {
1919 let span = result?;
2020 // This was an error case in a previous version of this code, where
2121 // it would fail when converting from a negative signed integer
2222 // to an unsigned integer. This preserves that failure case even
2323 // though the code below handles it okay.
24- if span. is_negative ( ) {
25- return Err ( Error :: RelativeTimeConversion ) ;
26- }
27- now. ok_or ( Error :: MissingCurrentTime ) . and_then ( |now| {
28- let ts = Timestamp :: try_from ( now) . map_err ( |_| Error :: RelativeTimeConversion ) ?;
29- // N.B. This matches the behavior of this code when it was
30- // written with `time`, but we might consider using the system
31- // time zone here. If we did, then it would implement "1 day
32- // ago" correctly, even when it crosses DST transitions. Since
33- // we're in the UTC time zone here, which has no DST, 1 day is
34- // in practice always 24 hours. ---AG
35- let zdt = ts. to_zoned ( TimeZone :: UTC ) ;
36- zdt. checked_sub ( span) . map_err ( |_| Error :: RelativeTimeConversion )
37- } )
24+ ensure ! ( !span. is_negative( ) , ParseError :: new( "" ) ) ;
25+ let now = now. ok_or ( ParseError :: new ( "Missing current time" ) ) ?;
26+ let ts: Timestamp = Timestamp :: try_from ( now) . or_raise ( || Error :: new ( "Could not convert current time" ) ) ?;
27+ // N.B. This matches the behavior of this code when it was
28+ // written with `time`, but we might consider using the system
29+ // time zone here. If we did, then it would implement "1 day
30+ // ago" correctly, even when it crosses DST transitions. Since
31+ // we're in the UTC time zone here, which has no DST, 1 day is
32+ // in practice always 24 hours. ---AG
33+ let zdt = ts. to_zoned ( TimeZone :: UTC ) ;
34+ zdt. checked_sub ( span)
35+ . or_raise ( || Error :: new ( format ! ( "Failed to subtract {zdt} from {span}" ) ) )
3836 } )
3937}
4038
@@ -51,7 +49,7 @@ fn span(period: &str, units: i64) -> Option<Result<Span, Error>> {
5149 // Ignore values you don't know, assume seconds then (so does git)
5250 _anything => Span :: new ( ) . try_seconds ( units) ,
5351 } ;
54- Some ( result. map_err ( |_ | Error :: RelativeTimeConversion ) )
52+ Some ( result. or_raise ( | | Error :: new ( format ! ( "Couldn't parse span from '{period} {units}'" ) ) ) )
5553}
5654
5755#[ cfg( test) ]
0 commit comments