From 00a2c9aec70db12bd41d7256be44379f20fe3c54 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 4 Oct 2025 16:44:57 +0000 Subject: [PATCH 1/5] chore(deps): update rust crate parse_datetime to 0.13.0 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 56b7c742fde..311ad95c6cb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -352,7 +352,7 @@ num-prime = "0.4.4" num-traits = "0.2.19" number_prefix = "0.4" onig = { version = "~6.5.1", default-features = false } -parse_datetime = "0.11.0" +parse_datetime = "0.13.0" phf = "0.13.1" phf_codegen = "0.13.1" platform-info = "2.0.3" From b77341cd369e1a4fd469ff3e98016cf37c6da08c Mon Sep 17 00:00:00 2001 From: naoNao89 <90588855+naoNao89@users.noreply.github.com> Date: Wed, 8 Oct 2025 13:46:37 +0700 Subject: [PATCH 2/5] date, touch: adapt to parse_datetime 0.13.0 API changes Fixes #8754 parse_datetime 0.13.0 fixes the bug where parsing large second values like "12345.123456789 seconds ago" would fail with "invalid date". However, parse_datetime 0.13.0 introduced a breaking API change: - Old (0.11.0): Returns chrono::DateTime - New (0.13.0): Returns jiff::Zoned This commit adapts both date and touch utilities to work with the new API: date.rs changes: - Simplified parse_date() to directly return jiff::Zoned - Removed unnecessary chrono -> jiff conversion code - parse_datetime now returns the exact type date utility uses - Added detailed comments explaining the API change and issue #8754 touch.rs changes: - Added jiff::Zoned -> chrono::DateTime conversion in parse_date() - Changed from parse_datetime_at_date to parse_datetime - Marked ref_time parameter as unused (preserved for future use) - Added detailed comments about API change and future migration path Note: 3 integration tests fail due to timezone handling changes in parse_datetime 0.13. These are separate issues that will be addressed in follow-up commits. --- Cargo.lock | 7 +++---- src/uu/date/src/date.rs | 17 ++++++++--------- src/uu/touch/src/touch.rs | 17 +++++++++++++++-- 3 files changed, 26 insertions(+), 15 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3cd7a493961..4e2996c83a4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2135,13 +2135,12 @@ dependencies = [ [[package]] name = "parse_datetime" -version = "0.11.0" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5b77d27257a460cefd73a54448e5f3fd4db224150baf6ca3e02eedf4eb2b3e9" +checksum = "77d45119ed61100f40b2389d8ed12e51ec869046d4279afbb5a7c73a4733be36" dependencies = [ - "chrono", + "jiff", "num-traits", - "regex", "winnow", ] diff --git a/src/uu/date/src/date.rs b/src/uu/date/src/date.rs index e8a0af266bc..e101c1c979e 100644 --- a/src/uu/date/src/date.rs +++ b/src/uu/date/src/date.rs @@ -571,7 +571,13 @@ fn resolve_tz_abbreviation>(date_str: S) -> String { /// Parse a `String` into a `DateTime`. /// If it fails, return a tuple of the `String` along with its `ParseError`. -// TODO: Convert `parse_datetime` to jiff and remove wrapper from chrono to jiff structures. +/// +/// **Update for parse_datetime 0.13:** +/// - parse_datetime 0.11: returned `chrono::DateTime` → required conversion to `jiff::Zoned` +/// - parse_datetime 0.13: returns `jiff::Zoned` directly → no conversion needed +/// +/// This change was necessary to fix issue #8754 (parsing large second values like +/// "12345.123456789 seconds ago" which failed in 0.11 but works in 0.13). fn parse_date + Clone>( s: S, ) -> Result { @@ -579,14 +585,7 @@ fn parse_date + Clone>( let resolved = resolve_tz_abbreviation(s.as_ref()); match parse_datetime::parse_datetime(&resolved) { - Ok(date) => { - let timestamp = - Timestamp::new(date.timestamp(), date.timestamp_subsec_nanos() as i32).unwrap(); - Ok(Zoned::new( - timestamp, - TimeZone::try_system().unwrap_or(TimeZone::UTC), - )) - } + Ok(date) => Ok(date), Err(e) => Err((s.as_ref().into(), e)), } } diff --git a/src/uu/touch/src/touch.rs b/src/uu/touch/src/touch.rs index 98d87e3367b..7f74640949e 100644 --- a/src/uu/touch/src/touch.rs +++ b/src/uu/touch/src/touch.rs @@ -588,7 +588,7 @@ fn stat(path: &Path, follow: bool) -> std::io::Result<(FileTime, FileTime)> { )) } -fn parse_date(ref_time: DateTime, s: &str) -> Result { +fn parse_date(_ref_time: DateTime, s: &str) -> Result { // This isn't actually compatible with GNU touch, but there doesn't seem to // be any simple specification for what format this parameter allows and I'm // not about to implement GNU parse_datetime. @@ -637,7 +637,20 @@ fn parse_date(ref_time: DateTime, s: &str) -> Result Date: Wed, 15 Oct 2025 09:21:09 +0700 Subject: [PATCH 3/5] touch: fix parse_datetime 0.13 API usage for deterministic relative dates The previous implementation incorrectly used parse_datetime() instead of parse_datetime_at_date(), causing relative date strings like 'yesterday' or '2 days ago' to be calculated from the current system time instead of the caller-specified reference time. This fix: - Uses parse_datetime_at_date() with proper chrono->jiff->chrono conversions - Restores deterministic behavior for relative date parsing - Adds jiff 0.2.15 as direct dependency (not workspace) to avoid feature conflicts - Ensures tests/touch/relative passes in CI Note on jiff dependency: parse_datetime 0.13 depends on jiff ^0.2.15 with specific features. Adding jiff via workspace dependency causes feature unification conflicts across platforms. Using a direct dependency with version 0.2.15 resolves this while maintaining compatibility with parse_datetime's requirements. --- Cargo.lock | 7 ++++--- src/uu/touch/Cargo.toml | 1 + src/uu/touch/src/touch.rs | 36 +++++++++++++++++++++++++++++------- 3 files changed, 34 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4e2996c83a4..833f1151655 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -508,7 +508,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "117725a109d387c937a1533ce01b450cbde6b88abceea8473c4d7a85853cda3c" dependencies = [ "lazy_static", - "windows-sys 0.59.0", + "windows-sys 0.52.0", ] [[package]] @@ -1074,7 +1074,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cea14ef9355e3beab063703aa9dab15afd25f0667c341310c1e5274bb1d0da18" dependencies = [ "libc", - "windows-sys 0.59.0", + "windows-sys 0.52.0", ] [[package]] @@ -1667,7 +1667,7 @@ dependencies = [ "portable-atomic", "portable-atomic-util", "serde", - "windows-sys 0.59.0", + "windows-sys 0.52.0", ] [[package]] @@ -4127,6 +4127,7 @@ dependencies = [ "clap", "filetime", "fluent", + "jiff", "parse_datetime", "thiserror 2.0.17", "uucore", diff --git a/src/uu/touch/Cargo.toml b/src/uu/touch/Cargo.toml index 55ac39bd89b..f5409ec7a5a 100644 --- a/src/uu/touch/Cargo.toml +++ b/src/uu/touch/Cargo.toml @@ -22,6 +22,7 @@ path = "src/touch.rs" filetime = { workspace = true } clap = { workspace = true } chrono = { workspace = true } +jiff = "0.2.15" parse_datetime = { workspace = true } thiserror = { workspace = true } uucore = { workspace = true, features = ["libc", "parser"] } diff --git a/src/uu/touch/src/touch.rs b/src/uu/touch/src/touch.rs index 7f74640949e..b1581f8f073 100644 --- a/src/uu/touch/src/touch.rs +++ b/src/uu/touch/src/touch.rs @@ -15,6 +15,7 @@ use chrono::{ use clap::builder::{PossibleValue, ValueParser}; use clap::{Arg, ArgAction, ArgGroup, ArgMatches, Command}; use filetime::{FileTime, set_file_times, set_symlink_file_times}; +use jiff::{Timestamp, Zoned}; use std::borrow::Cow; use std::ffi::OsString; use std::fs::{self, File}; @@ -588,7 +589,7 @@ fn stat(path: &Path, follow: bool) -> std::io::Result<(FileTime, FileTime)> { )) } -fn parse_date(_ref_time: DateTime, s: &str) -> Result { +fn parse_date(ref_time: DateTime, s: &str) -> Result { // This isn't actually compatible with GNU touch, but there doesn't seem to // be any simple specification for what format this parameter allows and I'm // not about to implement GNU parse_datetime. @@ -638,14 +639,35 @@ fn parse_date(_ref_time: DateTime, s: &str) -> Result Date: Sun, 26 Oct 2025 20:47:13 +0100 Subject: [PATCH 4/5] date: fix parse_datetime 0.13 API compatibility issues --- Cargo.lock | 6 +++--- fuzz/Cargo.lock | 7 +++---- src/uu/date/src/date.rs | 37 +++++++++++++++++++++++-------------- 3 files changed, 29 insertions(+), 21 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 833f1151655..8a1579edc45 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -508,7 +508,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "117725a109d387c937a1533ce01b450cbde6b88abceea8473c4d7a85853cda3c" dependencies = [ "lazy_static", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -1074,7 +1074,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cea14ef9355e3beab063703aa9dab15afd25f0667c341310c1e5274bb1d0da18" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -1667,7 +1667,7 @@ dependencies = [ "portable-atomic", "portable-atomic-util", "serde", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] diff --git a/fuzz/Cargo.lock b/fuzz/Cargo.lock index b7c7e85cf2e..1f8eeab9fbf 100644 --- a/fuzz/Cargo.lock +++ b/fuzz/Cargo.lock @@ -1071,13 +1071,12 @@ checksum = "1a80800c0488c3a21695ea981a54918fbb37abf04f4d0720c453632255e2ff0e" [[package]] name = "parse_datetime" -version = "0.11.0" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5b77d27257a460cefd73a54448e5f3fd4db224150baf6ca3e02eedf4eb2b3e9" +checksum = "77d45119ed61100f40b2389d8ed12e51ec869046d4279afbb5a7c73a4733be36" dependencies = [ - "chrono", + "jiff", "num-traits", - "regex", "winnow", ] diff --git a/src/uu/date/src/date.rs b/src/uu/date/src/date.rs index e101c1c979e..d38905988d5 100644 --- a/src/uu/date/src/date.rs +++ b/src/uu/date/src/date.rs @@ -459,8 +459,9 @@ fn make_format_string(settings: &Settings) -> &str { /// - MST: Mountain Standard Time (US) preferred over Malaysia Standard Time /// - PST: Pacific Standard Time (US) - widely used abbreviation /// - GMT: Alias for UTC (universal) +/// - Australian timezones: AWST, ACST, AEST (cannot be dynamically discovered) /// -/// All other timezones (AWST, JST, CET, etc.) are dynamically resolved from IANA database. // spell-checker:disable-line +/// All other timezones (JST, CET, etc.) are dynamically resolved from IANA database. // spell-checker:disable-line static PREFERRED_TZ_MAPPINGS: &[(&str, &str)] = &[ // Universal (no ambiguity, but commonly used) ("UTC", "UTC"), @@ -476,6 +477,12 @@ static PREFERRED_TZ_MAPPINGS: &[(&str, &str)] = &[ ("EDT", "America/New_York"), // Other highly ambiguous cases ("IST", "Asia/Kolkata"), // Ambiguous: India vs Israel vs Ireland // spell-checker:disable-line + // Australian timezones (cannot be discovered from IANA location names) + ("AWST", "Australia/Perth"), // Australian Western Standard Time + ("ACST", "Australia/Adelaide"), // Australian Central Standard Time + ("ACDT", "Australia/Adelaide"), // Australian Central Daylight Time + ("AEST", "Australia/Sydney"), // Australian Eastern Standard Time + ("AEDT", "Australia/Sydney"), // Australian Eastern Daylight Time ]; /// Lazy-loaded timezone abbreviation lookup map built from IANA database. @@ -547,18 +554,15 @@ fn resolve_tz_abbreviation>(date_str: S) -> String { // Try to parse the date with UTC first to get timestamp let date_with_utc = format!("{date_part} +00:00"); if let Ok(parsed) = parse_datetime::parse_datetime(&date_with_utc) { - // Create timestamp from parsed date - if let Ok(ts) = Timestamp::new( - parsed.timestamp(), - parsed.timestamp_subsec_nanos() as i32, - ) { - // Get the offset for this specific timestamp in the target timezone - let zoned = ts.to_zoned(tz); - let offset_str = format!("{}", zoned.offset()); - - // Replace abbreviation with offset - return format!("{date_part} {offset_str}"); - } + // Get timestamp from parsed date (which is already a Zoned) + let ts = parsed.timestamp(); + + // Get the offset for this specific timestamp in the target timezone + let zoned = ts.to_zoned(tz); + let offset_str = format!("{}", zoned.offset()); + + // Replace abbreviation with offset + return format!("{date_part} {offset_str}"); } } } @@ -585,7 +589,12 @@ fn parse_date + Clone>( let resolved = resolve_tz_abbreviation(s.as_ref()); match parse_datetime::parse_datetime(&resolved) { - Ok(date) => Ok(date), + Ok(date) => { + // Convert to system timezone for display + // (parse_datetime 0.13 returns Zoned in the input's timezone) + let timestamp = date.timestamp(); + Ok(timestamp.to_zoned(TimeZone::try_system().unwrap_or(TimeZone::UTC))) + } Err(e) => Err((s.as_ref().into(), e)), } } From 149c7a6e60eada3c1b1ff9503fcd17846d49c4c6 Mon Sep 17 00:00:00 2001 From: Sylvestre Ledru Date: Sun, 26 Oct 2025 21:10:53 +0100 Subject: [PATCH 5/5] Fix spell-checker directive for IST timezone entry --- src/uu/date/src/date.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/uu/date/src/date.rs b/src/uu/date/src/date.rs index d38905988d5..c3381dfbd2a 100644 --- a/src/uu/date/src/date.rs +++ b/src/uu/date/src/date.rs @@ -3,7 +3,7 @@ // For the full copyright and license information, please view the LICENSE // file that was distributed with this source code. -// spell-checker:ignore strtime ; (format) DATEFILE MMDDhhmm ; (vars) datetime datetimes getres +// spell-checker:ignore strtime ; (format) DATEFILE MMDDhhmm ; (vars) datetime datetimes getres AWST ACST AEST use clap::{Arg, ArgAction, Command}; use jiff::fmt::strtime; @@ -476,13 +476,15 @@ static PREFERRED_TZ_MAPPINGS: &[(&str, &str)] = &[ ("EST", "America/New_York"), // Ambiguous: US vs Australia ("EDT", "America/New_York"), // Other highly ambiguous cases - ("IST", "Asia/Kolkata"), // Ambiguous: India vs Israel vs Ireland // spell-checker:disable-line + /* spell-checker: disable */ + ("IST", "Asia/Kolkata"), // Ambiguous: India vs Israel vs Ireland // Australian timezones (cannot be discovered from IANA location names) ("AWST", "Australia/Perth"), // Australian Western Standard Time ("ACST", "Australia/Adelaide"), // Australian Central Standard Time ("ACDT", "Australia/Adelaide"), // Australian Central Daylight Time ("AEST", "Australia/Sydney"), // Australian Eastern Standard Time ("AEDT", "Australia/Sydney"), // Australian Eastern Daylight Time + /* spell-checker: enable */ ]; /// Lazy-loaded timezone abbreviation lookup map built from IANA database.