diff --git a/src/uu/date/src/date.rs b/src/uu/date/src/date.rs index 02321c0c5f4..ccba21c6d0b 100644 --- a/src/uu/date/src/date.rs +++ b/src/uu/date/src/date.rs @@ -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>(date_str: S) -> Option { +fn try_parse_with_abbreviation>(date_str: S, now: &Zoned) -> Option { let s = date_str.as_ref(); // Look for timezone abbreviation at the end of the string @@ -845,7 +845,9 @@ fn try_parse_with_abbreviation>(date_str: S) -> Option { // 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); @@ -898,7 +900,7 @@ fn parse_date + 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) {}", @@ -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() { + let now = "2025-03-15T20:00:00+00:00[UTC]".parse::().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(); diff --git a/tests/by-util/test_date.rs b/tests/by-util/test_date.rs index 9eade4a0e59..5b9218697c0 100644 --- a/tests/by-util/test_date.rs +++ b/tests/by-util/test_date.rs @@ -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