summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNathan Bellows <nbellows@amazon.com>2024-02-12 02:05:41 -0800
committerNathan Bellows <nbellows@amazon.com>2024-02-12 02:05:41 -0800
commitb0a8848f680ed9df2bd742b05997acb695df0b44 (patch)
tree523d6491eecda9bd208671b0a2e8266e49d6f273
parent969316cc0e87171273c6ea78ca73b6ee9ac3cb20 (diff)
Add support for @%s time format
-rw-r--r--CHANGELOG.md1
-rw-r--r--doc/fd.112
-rw-r--r--src/filter/time.rs30
3 files changed, 38 insertions, 5 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 08f447f..1717b85 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,6 +3,7 @@
## Features
- Add `dir` as an alias to `directory` when using `-t` \ `--type`, see #1460 and #1464 (@Ato2207).
+- Add support for @%s date format in time filters similar to GNU date (seconds since Unix epoch for --older/--newer), see #1493 (@nabellows)
## Bugfixes
diff --git a/doc/fd.1 b/doc/fd.1
index 8877317..1ac63c5 100644
--- a/doc/fd.1
+++ b/doc/fd.1
@@ -312,8 +312,9 @@ tebibytes
Filter results based on the file modification time.
Files with modification times greater than the argument will be returned.
The argument can be provided as a duration (\fI10h, 1d, 35min\fR) or as a specific point
-in time in either full RFC3339 format with time zone, or as a date or datetime in the
-local time zone (\fIYYYY-MM-DD\fR or \fIYYYY-MM-DD HH:MM:SS\fR).
+in time as full RFC3339 format with time zone, as a date or datetime in the
+local time zone (\fIYYYY-MM-DD\fR or \fIYYYY-MM-DD HH:MM:SS\fR), or as the prefix '@'
+followed by the number of seconds since the Unix epoch (@[0-9]+).
\fB\-\-change-newer-than\fR,
.B --newer
or
@@ -324,13 +325,15 @@ Examples:
\-\-changed-within 2weeks
\-\-change-newer-than "2018-10-27 10:00:00"
\-\-newer 2018-10-27
+ \-\-changed-after @1704067200
.TP
.BI "\-\-changed-before " date|duration
Filter results based on the file modification time.
Files with modification times less than the argument will be returned.
The argument can be provided as a duration (\fI10h, 1d, 35min\fR) or as a specific point
-in time in either full RFC3339 format with time zone, or as a date or datetime in the
-local time zone (\fIYYYY-MM-DD\fR or \fIYYYY-MM-DD HH:MM:SS\fR).
+in time as full RFC3339 format with time zone, as a date or datetime in the
+local time zone (\fIYYYY-MM-DD\fR or \fIYYYY-MM-DD HH:MM:SS\fR), or as the prefix '@'
+followed by the number of seconds since the Unix epoch (@[0-9]+).
.B --change-older-than
or
.B --older
@@ -339,6 +342,7 @@ can be used as aliases.
Examples:
\-\-changed-before "2018-10-27 10:00:00"
\-\-change-older-than 2weeks
+ \-\-older @1704067200
.TP
.BI "-o, \-\-owner " [user][:group]
Filter files by their user and/or group. Format: [(user|uid)][:(group|gid)]. Either side
diff --git a/src/filter/time.rs b/src/filter/time.rs
index 0070e5e..9631f13 100644
--- a/src/filter/time.rs
+++ b/src/filter/time.rs
@@ -1,4 +1,4 @@
-use chrono::{DateTime, Local, NaiveDate, NaiveDateTime};
+use chrono::{DateTime, Local, NaiveDate, NaiveDateTime, Utc};
use std::time::SystemTime;
@@ -31,6 +31,13 @@ impl TimeFilter {
.and_local_timezone(Local)
.latest()
})
+ .or_else(|| {
+ let timestamp_secs = s.strip_prefix('@')?.parse().ok()?;
+ NaiveDateTime::from_timestamp_opt(timestamp_secs, 0)?
+ .and_local_timezone(Utc)
+ .latest()
+ .map(Into::into)
+ })
.map(|dt| dt.into())
})
}
@@ -135,5 +142,26 @@ mod tests {
assert!(!TimeFilter::after(&ref_time, t10s_before)
.unwrap()
.applies_to(&t1m_ago));
+
+ let ref_timestamp = 1707723412u64; // Mon Feb 12 07:36:52 UTC 2024
+ let ref_time = DateTime::parse_from_rfc3339("2024-02-12T07:36:52+00:00")
+ .unwrap()
+ .into();
+ let t1m_ago = ref_time - Duration::from_secs(60);
+ let t1s_later = ref_time + Duration::from_secs(1);
+ // Timestamp only supported via '@' prefix
+ assert!(TimeFilter::before(&ref_time, &ref_timestamp.to_string()).is_none());
+ assert!(TimeFilter::before(&ref_time, &format!("@{}", ref_timestamp))
+ .unwrap()
+ .applies_to(&t1m_ago));
+ assert!(!TimeFilter::before(&ref_time, &format!("@{}", ref_timestamp))
+ .unwrap()
+ .applies_to(&t1s_later));
+ assert!(!TimeFilter::after(&ref_time, &format!("@{}", ref_timestamp))
+ .unwrap()
+ .applies_to(&t1m_ago));
+ assert!(TimeFilter::after(&ref_time, &format!("@{}", ref_timestamp))
+ .unwrap()
+ .applies_to(&t1s_later));
}
}