Use local times for time functions

This patch uses Chrono for explicit date or datetime parsing, only using
humantime for its relative time parsing. The following formats are accepted:

1. Full RFC3339 parsing, requiring an explicit timezone
2. `YY-MM-DD`, defaulting to time `00:00:00` for the given date in the
   local time zone
3. `YY-MM-DD HH:MM:SS` in the local time zone

Fixes #631, #794
This commit is contained in:
Jacob Mischka 2020-10-25 06:30:38 -05:00 committed by David Peter
parent 4e04d13215
commit ba60a163fe
5 changed files with 228 additions and 64 deletions

View File

@ -8,6 +8,7 @@
- fd cannot search files under a RAM disk, see #752
- fd doesn't show substituted drive on Windows, see #365
- Properly handle write errors to devices that are full, see #737
- Use local time zone for time functions (`--change-newer-than`, `--change-older-than`), see #631 (@jacobmischka)
## Changes

219
Cargo.lock generated
View File

@ -31,9 +31,21 @@ dependencies = [
[[package]]
name = "anyhow"
version = "1.0.42"
version = "1.0.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "595d3cfa7a60d4555cb5067b99f07142a08ea778de5cf993f7b75c7d8fabc486"
checksum = "85bb70cc08ec97ca5450e6eba421deeea5f172c0fc61f78b5357b2a8e8be195f"
[[package]]
name = "arrayref"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544"
[[package]]
name = "arrayvec"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8"
[[package]]
name = "atty"
@ -48,9 +60,15 @@ dependencies = [
[[package]]
name = "autocfg"
version = "1.0.1"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d"
[[package]]
name = "base64"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b41b7ea54a0c9d92199de89e20e58d49f02f8e699814ef3fdf266f6f748d15c7"
[[package]]
name = "bitflags"
@ -59,19 +77,30 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
[[package]]
name = "bstr"
version = "0.2.14"
name = "blake2b_simd"
version = "0.5.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "473fc6b38233f9af7baa94fb5852dca389e3d95b8e21c8e3719301462c5d9faf"
checksum = "d8fb2d74254a3a0b5cac33ac9f8ed0e44aa50378d9dbb2e5d83bd21ed1dc2c8a"
dependencies = [
"arrayref",
"arrayvec",
"constant_time_eq",
]
[[package]]
name = "bstr"
version = "0.2.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "31accafdb70df7871592c058eca3985b71104e15ac32f64706022c58867da931"
dependencies = [
"memchr",
]
[[package]]
name = "cc"
version = "1.0.66"
version = "1.0.53"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c0496836a84f8d0495758516b8621a622beb77c0fed418570e50764093ced48"
checksum = "404b1fe4f65288577753b17e3b36a04596ee784493ec249bf81c7f2d2acd751c"
[[package]]
name = "cfg-if"
@ -86,10 +115,23 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "clap"
version = "2.33.3"
name = "chrono"
version = "0.4.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002"
checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73"
dependencies = [
"libc",
"num-integer",
"num-traits",
"time",
"winapi",
]
[[package]]
name = "clap"
version = "2.33.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bdfa80d47f954d53a35a64987ca1422f495b8d6483c0fe9f7117b36c2a792129"
dependencies = [
"ansi_term 0.11.0",
"atty",
@ -102,21 +144,27 @@ dependencies = [
]
[[package]]
name = "crossbeam-utils"
version = "0.8.1"
name = "constant_time_eq"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "02d96d1e189ef58269ebe5b97953da3274d83a93af647c2ddd6f9dab28cedb8d"
checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc"
[[package]]
name = "crossbeam-utils"
version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8"
dependencies = [
"autocfg",
"cfg-if 1.0.0",
"cfg-if 0.1.10",
"lazy_static",
]
[[package]]
name = "ctrlc"
version = "3.1.9"
version = "3.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "232295399409a8b7ae41276757b5a1cc21032848d42bff2352261f958b3ca29a"
checksum = "7a4ba686dff9fa4c1c9636ce1010b0cf98ceb421361b0bb3d6faeec43bd217a7"
dependencies = [
"nix",
"winapi",
@ -140,9 +188,9 @@ dependencies = [
[[package]]
name = "dirs-sys-next"
version = "0.1.1"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "99de365f605554ae33f115102a02057d4fc18b01f3284d6870be0938743cfe7d"
checksum = "9c60f7b8a8953926148223260454befb50c751d3c50e1c178c4fd1ace4083c9a"
dependencies = [
"libc",
"redox_users",
@ -156,6 +204,7 @@ dependencies = [
"ansi_term 0.12.1",
"anyhow",
"atty",
"chrono",
"clap",
"ctrlc",
"diff",
@ -197,9 +246,9 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
[[package]]
name = "fs_extra"
version = "1.2.0"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2022715d62ab30faffd124d40b76f4134a550a87792276512b18d63272333394"
checksum = "5f2a4a2034423744d2cc7ca2068453168dcdb82c438419e639a26bd87839c674"
[[package]]
name = "fuchsia-cprng"
@ -209,20 +258,20 @@ checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
[[package]]
name = "getrandom"
version = "0.1.15"
version = "0.1.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc587bc0ec293155d5bfa6b9891ec18a1e330c234f896ea47fbada4cadbe47e6"
checksum = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb"
dependencies = [
"cfg-if 0.1.10",
"libc",
"wasi",
"wasi 0.9.0+wasi-snapshot-preview1",
]
[[package]]
name = "globset"
version = "0.4.8"
version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "10463d9ff00a2a068db14231982f5132edebad0d7660cd956a1c30292dbcbfbd"
checksum = "7ad1da430bd7281dde2576f44c84cc3f0f7b475e7202cd503042dff01a8c8120"
dependencies = [
"aho-corasick",
"bstr",
@ -233,24 +282,24 @@ dependencies = [
[[package]]
name = "hermit-abi"
version = "0.1.17"
version = "0.1.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5aca5565f760fb5b220e499d72710ed156fdb74e631659e99377d9ebfbd13ae8"
checksum = "91780f809e750b0a89f5544be56617ff6b1227ee485bcb06ebe10cdf89bd3b71"
dependencies = [
"libc",
]
[[package]]
name = "humantime"
version = "2.0.1"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c1ad908cc71012b7bea4d0c53ba96a8cba9962f048fa68d143376143d863b7a"
checksum = "b9b6c53306532d3c8e8087b44e6580e10db51a023cf9b433cea2ac38066b92da"
[[package]]
name = "ignore"
version = "0.4.17"
version = "0.4.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b287fb45c60bb826a0dc68ff08742b9d88a2fea13d6e0c286b3172065aaf878c"
checksum = "128b9e89d15a3faa642ee164c998fd4fae3d89d054463cddb2c25a7baad3a352"
dependencies = [
"crossbeam-utils",
"globset",
@ -293,24 +342,24 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libc"
version = "0.2.98"
version = "0.2.70"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "320cfe77175da3a483efed4bc0adc1968ca050b098ce4f2f1c13a56626128790"
checksum = "3baa92041a6fec78c687fa0cc2b3fae8884f743d672cf551bed1d6dac6988d0f"
[[package]]
name = "log"
version = "0.4.11"
version = "0.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b"
checksum = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7"
dependencies = [
"cfg-if 0.1.10",
]
[[package]]
name = "lscolors"
version = "0.7.1"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d24b894c45c9da468621cdd615a5a79ee5e5523dd4f75c76ebc03d458940c16e"
checksum = "1f77452267149eac960ded529fe5f5460ddf792845a1d71b5d0cfcee5642e47e"
dependencies = [
"ansi_term 0.12.1",
]
@ -323,14 +372,15 @@ checksum = "b16bd47d9e329435e309c58469fe0791c2d0d1ba96ec0954152a5ae2b04387dc"
[[package]]
name = "nix"
version = "0.20.0"
version = "0.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa9b4819da1bc61c0ea48b63b7bc8604064dd43013e7cc325df098d49cd7c18a"
checksum = "50e4785f2c3b7589a0d0c1dd60285e1188adac4006e8abd6dd578e1567027363"
dependencies = [
"bitflags",
"cc",
"cfg-if 1.0.0",
"cfg-if 0.1.10",
"libc",
"void",
]
[[package]]
@ -342,6 +392,25 @@ dependencies = [
"winapi",
]
[[package]]
name = "num-integer"
version = "0.1.43"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8d59457e662d541ba17869cf51cf177c0b5f0cbf476c66bdc90bf1edac4f875b"
dependencies = [
"autocfg",
"num-traits",
]
[[package]]
name = "num-traits"
version = "0.2.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac267bcc07f48ee5f8935ab0d24f316fb722d7a1292e2913f0cc196b29ffd611"
dependencies = [
"autocfg",
]
[[package]]
name = "num_cpus"
version = "1.13.0"
@ -391,9 +460,9 @@ dependencies = [
[[package]]
name = "redox_syscall"
version = "0.1.57"
version = "0.1.56"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce"
checksum = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84"
[[package]]
name = "redox_syscall"
@ -406,12 +475,13 @@ dependencies = [
[[package]]
name = "redox_users"
version = "0.3.5"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "de0737333e7a9502c789a36d7c7fa6092a49895d4faa31ca5df163857ded2e9d"
checksum = "09b23093265f8d200fa7b4c2c76297f47e681c655f6f1285a8780d6a022f7431"
dependencies = [
"getrandom",
"redox_syscall 0.1.57",
"redox_syscall 0.1.56",
"rust-argon2",
]
[[package]]
@ -433,13 +503,25 @@ checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
[[package]]
name = "remove_dir_all"
version = "0.5.3"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7"
checksum = "4a83fa3702a688b9359eccba92d153ac33fd2e8462f9e0e3fdf155239ea7792e"
dependencies = [
"winapi",
]
[[package]]
name = "rust-argon2"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2bc8af4bda8e1ff4932523b94d3dd20ee30a87232323eda55903ffd71d2fb017"
dependencies = [
"base64",
"blake2b_simd",
"constant_time_eq",
"crossbeam-utils",
]
[[package]]
name = "same-file"
version = "1.0.6"
@ -495,10 +577,21 @@ dependencies = [
]
[[package]]
name = "unicode-width"
version = "0.1.8"
name = "time"
version = "0.1.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3"
checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255"
dependencies = [
"libc",
"wasi 0.10.0+wasi-snapshot-preview1",
"winapi",
]
[[package]]
name = "unicode-width"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "caaa9d531767d1ff2150b9332433f32a24622147e5ebb1f26409d5da67afd479"
[[package]]
name = "users"
@ -518,9 +611,15 @@ checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
[[package]]
name = "version_check"
version = "0.9.3"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe"
checksum = "078775d0255232fb988e6fccf26ddc9d1ac274299aaedcedce21c6f72cc533ce"
[[package]]
name = "void"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
[[package]]
name = "walkdir"
@ -540,10 +639,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
[[package]]
name = "winapi"
version = "0.3.9"
name = "wasi"
version = "0.10.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f"
[[package]]
name = "winapi"
version = "0.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6"
dependencies = [
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",

View File

@ -48,6 +48,7 @@ globset = "0.4"
anyhow = "1.0"
dirs-next = "2.0"
normpath = "0.3"
chrono = "0.4"
[dependencies.clap]
version = "2.31.2"

14
doc/fd.1 vendored
View File

@ -216,8 +216,11 @@ tebibytes
.RE
.TP
.BI "\-\-changed-within " date|duration
Filter results based on the file modification time. The argument can be provided as a specific
point in time (\fIYYYY-MM-DD HH:MM:SS\fR) or as a duration (\fI10h, 1d, 35min\fR).
Filter results based on the file modification time.
Files with modification times greater than or equal to 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).
.B --change-newer-than
can be used as an alias.
@ -226,8 +229,11 @@ Examples:
\-\-change-newer-than "2018-10-27 10:00:00"
.TP
.BI "\-\-changed-before " date|duration
Filter results based on the file modification time. The argument can be provided as a specific
point in time (\fIYYYY-MM-DD HH:MM:SS\fR) or as a duration (\fI10h, 1d, 35min\fR).
Filter results based on the file modification time.
Files with modification times less than or equal to 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).
.B --change-older-than
can be used as an alias.

View File

@ -1,3 +1,5 @@
use chrono::{offset::TimeZone, DateTime, Local, NaiveDate};
use std::time::SystemTime;
/// Filter based on time ranges.
@ -11,9 +13,20 @@ impl TimeFilter {
fn from_str(ref_time: &SystemTime, s: &str) -> Option<SystemTime> {
humantime::parse_duration(s)
.map(|duration| *ref_time - duration)
.or_else(|_| humantime::parse_rfc3339_weak(s))
.or_else(|_| humantime::parse_rfc3339_weak(&(s.to_owned() + " 00:00:00")))
.ok()
.or_else(|| {
DateTime::parse_from_rfc3339(s)
.map(|dt| dt.into())
.ok()
.or_else(|| {
NaiveDate::parse_from_str(s, "%F")
.map(|nd| nd.and_hms(0, 0, 0))
.ok()
.and_then(|ndt| Local.from_local_datetime(&ndt).single())
})
.or_else(|| Local.datetime_from_str(s, "%F %T").ok())
.map(|dt| dt.into())
})
}
pub fn before(ref_time: &SystemTime, s: &str) -> Option<TimeFilter> {
@ -39,7 +52,11 @@ mod tests {
#[test]
fn is_time_filter_applicable() {
let ref_time = humantime::parse_rfc3339("2010-10-10T10:10:10Z").unwrap();
let ref_time = Local
.datetime_from_str("2010-10-10 10:10:10", "%F %T")
.unwrap()
.into();
assert!(TimeFilter::after(&ref_time, "1min")
.unwrap()
.applies_to(&ref_time));
@ -76,5 +93,39 @@ mod tests {
assert!(!TimeFilter::after(&ref_time, t10s_before)
.unwrap()
.applies_to(&t1m_ago));
let same_day = "2010-10-10";
assert!(!TimeFilter::before(&ref_time, same_day)
.unwrap()
.applies_to(&ref_time));
assert!(!TimeFilter::before(&ref_time, same_day)
.unwrap()
.applies_to(&t1m_ago));
assert!(TimeFilter::after(&ref_time, same_day)
.unwrap()
.applies_to(&ref_time));
assert!(TimeFilter::after(&ref_time, same_day)
.unwrap()
.applies_to(&t1m_ago));
let ref_time = DateTime::parse_from_rfc3339("2010-10-10T10:10:10+00:00")
.unwrap()
.into();
let t1m_ago = ref_time - Duration::from_secs(60);
let t10s_before = "2010-10-10T10:10:00+00:00";
assert!(!TimeFilter::before(&ref_time, t10s_before)
.unwrap()
.applies_to(&ref_time));
assert!(TimeFilter::before(&ref_time, t10s_before)
.unwrap()
.applies_to(&t1m_ago));
assert!(TimeFilter::after(&ref_time, t10s_before)
.unwrap()
.applies_to(&ref_time));
assert!(!TimeFilter::after(&ref_time, t10s_before)
.unwrap()
.applies_to(&t1m_ago));
}
}