Skip to content

Commit

Permalink
fix: add support for 'any' unit, when parsing <count> <unit> ago.
Browse files Browse the repository at this point in the history
Similar to Git, any unit is allowed and will default to seconds, like `60 flurps ago`
will mean a minute in the past.
  • Loading branch information
Byron committed Nov 25, 2024
1 parent 3082d40 commit a769fdd
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 18 deletions.
2 changes: 1 addition & 1 deletion gix-date/src/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ mod relative {
"month" => Span::new().try_months(units),
"year" => Span::new().try_years(units),
// Ignore values you don't know, assume seconds then (so does git)
_ => return None,
_anything => Span::new().try_seconds(units),
};
Some(result.map_err(|_| Error::RelativeTimeConversion))
}
Expand Down
47 changes: 30 additions & 17 deletions gix-date/tests/time/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,7 @@ mod relative {
// For comparison, a few are the same as in: https://github.com/git/git/blob/master/t/t0006-date.sh
let cases = [
("5 seconds ago", 5.seconds()),
("12345 florx ago", 12_345.seconds()), // Anything parses as seconds
("5 minutes ago", 5.minutes()),
("5 hours ago", 5.hours()),
("5 days ago", 5.days()),
Expand Down Expand Up @@ -222,34 +223,46 @@ mod relative {
("630720000 seconds ago", 630_720_000.seconds()), // 20 years
];

let with_times = cases.map(|(input, _)| {
let cases_with_times = cases.map(|(input, _)| {
let time = gix_date::parse(input, Some(now)).expect("relative time string should parse to a Time");
(input, time)
});
assert_eq!(with_times.map(|_| Sign::Plus), with_times.map(|(_, time)| time.sign));
assert_eq!(with_times.map(|_| 0), with_times.map(|(_, time)| time.offset));
assert_eq!(
cases_with_times.map(|(_, time)| time.sign),
cases_with_times.map(|_| Sign::Plus),
"Despite being in the past, the dates produced are positive, as they are still post-epoch"
);
assert_eq!(
cases_with_times.map(|(_, time)| time.offset),
cases_with_times.map(|_| 0),
"They don't pick up local time"
);

let with_expected = cases.map(|(input, span)| {
let expected = Zoned::try_from(now)
.expect("test needs to convert current time to a timestamp")
// account for the loss of precision when creating `Time` with seconds
.round(
jiff::ZonedRound::new()
.smallest(jiff::Unit::Second)
.mode(jiff::RoundMode::Trunc),
)
.expect("test needs to truncate current timestamp to seconds")
.saturating_sub(span)
.timestamp();
let expected = cases.map(|(input, span)| {
let expected = Zoned::new(
now.try_into().expect("system time is representable"),
// As relative dates are always UTC in Git, we do the same, and must
// compare to UTC as well or else time might be off due to daylight savings, etc.
jiff::tz::TimeZone::UTC,
)
// account for the loss of precision when creating `Time` with seconds
.round(
jiff::ZonedRound::new()
.smallest(jiff::Unit::Second)
.mode(jiff::RoundMode::Trunc),
)
.expect("test needs to truncate current timestamp to seconds")
.saturating_sub(span)
.timestamp();

(input, expected)
});
let with_actual = with_times.map(|(input, time)| {
let actual = cases_with_times.map(|(input, time)| {
let actual = jiff::Timestamp::from_second(time.seconds)
.expect("seconds obtained from a Time should convert to Timestamp");
(input, actual)
});
assert_eq!(with_actual, with_expected, "relative times differ");
assert_eq!(actual, expected);
}
}

Expand Down

0 comments on commit a769fdd

Please sign in to comment.