Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 13 additions & 3 deletions src/uu/date/src/date.rs
Original file line number Diff line number Diff line change
Expand Up @@ -828,7 +828,7 @@ fn tz_abbrev_to_iana(abbrev: &str) -> Option<&str> {
/// If an abbreviation is found and the date is parsable, returns `Some(Zoned)`.
/// Returns `None` if no abbreviation is detected or if parsing fails, indicating
/// that standard parsing should be attempted.
fn try_parse_with_abbreviation<S: AsRef<str>>(date_str: S) -> Option<Zoned> {
fn try_parse_with_abbreviation<S: AsRef<str>>(date_str: S, now: &Zoned) -> Option<Zoned> {
let s = date_str.as_ref();

// Look for timezone abbreviation at the end of the string
Expand All @@ -845,7 +845,9 @@ fn try_parse_with_abbreviation<S: AsRef<str>>(date_str: S) -> Option<Zoned> {
// Parse the date part (everything before the TZ abbreviation)
let date_part = s.trim_end_matches(last_word).trim();
// Parse in the target timezone so "10:30 EDT" means 10:30 in EDT
if let Ok(parsed) = parse_datetime::parse_datetime(date_part) {
if let Ok(parsed) =
parse_datetime::parse_datetime_at_date(now.clone(), date_part)
{
let dt = parsed.datetime();
if let Ok(zoned) = dt.to_zoned(tz) {
return Some(zoned);
Expand Down Expand Up @@ -898,7 +900,7 @@ fn parse_date<S: AsRef<str> + Clone>(
}

// First, try to parse any timezone abbreviations
if let Some(zoned) = try_parse_with_abbreviation(input_str) {
if let Some(zoned) = try_parse_with_abbreviation(input_str, now) {
if dbg_opts.debug {
eprintln!(
"date: parsed date part: (Y-M-D) {}",
Expand Down Expand Up @@ -1099,6 +1101,14 @@ mod tests {
assert_eq!(parse_military_timezone_with_offset("9m"), None); // Starts with digit
}

#[test]
fn test_abbreviation_resolves_relative_date_against_now() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please also add a test in tests/by-util/test_date.rs

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added

let now = "2025-03-15T20:00:00+00:00[UTC]".parse::<Zoned>().unwrap();
let result =
parse_date("yesterday 10:00 GMT", &now, DebugOptions::new(false, false)).unwrap();
assert_eq!(result.date(), jiff::civil::date(2025, 3, 14));
}

#[test]
fn test_utc_conversion_preserves_offset() {
let now = Zoned::now();
Expand Down
23 changes: 23 additions & 0 deletions tests/by-util/test_date.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1124,6 +1124,29 @@ fn test_date_tz_abbreviation_with_day_of_week() {
.no_stderr();
}

#[test]
fn test_date_tz_abbreviation_with_relative_date() {
// Verify that "yesterday" in "-u -d yesterday 10:00 GMT" is resolved
// relative to UTC, not the local TZ.
let expected = new_ucmd!()
.env("TZ", "UTC")
.arg("-u")
.arg("-d")
.arg("yesterday 10:00 GMT")
.arg("+%F %T %Z")
.succeeds()
.stdout_str()
.to_string();
new_ucmd!()
.env("TZ", "Australia/Sydney")
.arg("-u")
.arg("-d")
.arg("yesterday 10:00 GMT")
.arg("+%F %T %Z")
.succeeds()
.stdout_is(expected);
}

#[test]
fn test_date_tz_abbreviation_unknown() {
// Test that unknown timezone abbreviations fall back gracefully
Expand Down
Loading