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.
This commit is contained in:
naoNao89
2025-10-26 22:09:02 +01:00
committed by Sylvestre Ledru
parent 4e605cc510
commit f4b66479f0
3 changed files with 26 additions and 15 deletions
Generated
+3 -4
View File
@@ -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",
]
+8 -9
View File
@@ -571,7 +571,13 @@ fn resolve_tz_abbreviation<S: AsRef<str>>(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<S: AsRef<str> + Clone>(
s: S,
) -> Result<Zoned, (String, parse_datetime::ParseDateTimeError)> {
@@ -579,14 +585,7 @@ fn parse_date<S: AsRef<str> + 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)),
}
}
+15 -2
View File
@@ -588,7 +588,7 @@ fn stat(path: &Path, follow: bool) -> std::io::Result<(FileTime, FileTime)> {
))
}
fn parse_date(ref_time: DateTime<Local>, s: &str) -> Result<FileTime, TouchError> {
fn parse_date(_ref_time: DateTime<Local>, s: &str) -> Result<FileTime, TouchError> {
// 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<Local>, s: &str) -> Result<FileTime, TouchError
}
}
if let Ok(dt) = parse_datetime::parse_datetime_at_date(ref_time, s) {
// **parse_datetime 0.13 API change:**
// Previously (0.11): parse_datetime_at_date(chrono) → chrono::DateTime
// Now (0.13): parse_datetime() → jiff::Zoned
//
// Since touch still uses chrono types internally, we convert:
// jiff::Zoned → Unix timestamp → chrono::DateTime
//
// TODO: Consider migrating touch to jiff to eliminate this conversion
if let Ok(zoned) = parse_datetime::parse_datetime(s) {
let timestamp = zoned.timestamp();
let dt =
DateTime::from_timestamp(timestamp.as_second(), timestamp.subsec_nanosecond() as u32)
.map(|dt| dt.with_timezone(&Local))
.ok_or_else(|| TouchError::InvalidDateFormat(s.to_owned()))?;
return Ok(datetime_to_filetime(&dt));
}