Skip to content

Commit fc08fa1

Browse files
committed
ls: Print dates in the future as "old" ones
ls has different time format for recent (< 6 months) and older files. Files in the future (even by just a second), are considered old, which makes sense as we probably want the date to be printed in that case.
1 parent 4901f37 commit fc08fa1

File tree

2 files changed

+85
-3
lines changed

2 files changed

+85
-3
lines changed

src/uu/ls/src/ls.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
use std::collections::HashMap;
99
use std::iter;
10+
use std::ops::RangeInclusive;
1011
#[cfg(unix)]
1112
use std::os::unix::fs::{FileTypeExt, MetadataExt};
1213
#[cfg(windows)]
@@ -1959,7 +1960,7 @@ struct ListState<'a> {
19591960
uid_cache: HashMap<u32, String>,
19601961
#[cfg(unix)]
19611962
gid_cache: HashMap<u32, String>,
1962-
recent_time_threshold: SystemTime,
1963+
recent_time_range: RangeInclusive<SystemTime>,
19631964
}
19641965

19651966
#[allow(clippy::cognitive_complexity)]
@@ -1976,8 +1977,11 @@ pub fn list(locs: Vec<&Path>, config: &Config) -> UResult<()> {
19761977
uid_cache: HashMap::new(),
19771978
#[cfg(unix)]
19781979
gid_cache: HashMap::new(),
1980+
// Time range for which to use the "recent" format. Anything from 0.5 year in the past to now
1981+
// (files with modification time in the future use "old" format).
19791982
// According to GNU a Gregorian year has 365.2425 * 24 * 60 * 60 == 31556952 seconds on the average.
1980-
recent_time_threshold: SystemTime::now() - Duration::new(31_556_952 / 2, 0),
1983+
recent_time_range: (SystemTime::now() - Duration::new(31_556_952 / 2, 0))
1984+
..=SystemTime::now(),
19811985
};
19821986

19831987
for loc in locs {
@@ -2961,7 +2965,7 @@ fn display_date(
29612965
// Use "recent" format if the given date is considered recent (i.e., in the last 6 months),
29622966
// or if no "older" format is available.
29632967
let fmt = match &config.time_format_older {
2964-
Some(time_format_older) if time <= state.recent_time_threshold => time_format_older,
2968+
Some(time_format_older) if !state.recent_time_range.contains(&time) => time_format_older,
29652969
_ => &config.time_format_recent,
29662970
};
29672971

tests/by-util/test_ls.rs

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2132,6 +2132,84 @@ fn test_ls_time_styles() {
21322132
.stdout_matches(&re_long_recent);
21332133
}
21342134

2135+
#[test]
2136+
fn test_ls_time_recent_future() {
2137+
let scene = TestScenario::new(util_name!());
2138+
let at = &scene.fixtures;
2139+
let f = at.make_file("test");
2140+
2141+
let re_iso_recent =
2142+
Regex::new(r"[a-z-]* \d* [\w.]* [\w.]* \d* \d{2}-\d{2} \d{2}:\d{2} test\n").unwrap();
2143+
let re_iso_old =
2144+
Regex::new(r"[a-z-]* \d* [\w.]* [\w.]* \d* \d{4}-\d{2}-\d{2} test\n").unwrap();
2145+
2146+
// `test` has just been created, so it's recent
2147+
scene
2148+
.ucmd()
2149+
.arg("-l")
2150+
.arg("--time-style=iso")
2151+
.succeeds()
2152+
.stdout_matches(&re_iso_recent);
2153+
2154+
// 100 days ago is still recent (<0.5 years)
2155+
f.set_modified(SystemTime::now() - Duration::from_secs(3600 * 24 * 100))
2156+
.unwrap();
2157+
scene
2158+
.ucmd()
2159+
.arg("-l")
2160+
.arg("--time-style=iso")
2161+
.succeeds()
2162+
.stdout_matches(&re_iso_recent);
2163+
2164+
// 200 days ago is not recent
2165+
f.set_modified(SystemTime::now() - Duration::from_secs(3600 * 24 * 200))
2166+
.unwrap();
2167+
scene
2168+
.ucmd()
2169+
.arg("-l")
2170+
.arg("--time-style=iso")
2171+
.succeeds()
2172+
.stdout_matches(&re_iso_old);
2173+
2174+
// A timestamp in the future (even just a minute), is not considered "recent"
2175+
f.set_modified(SystemTime::now() + Duration::from_secs(60))
2176+
.unwrap();
2177+
scene
2178+
.ucmd()
2179+
.arg("-l")
2180+
.arg("--time-style=iso")
2181+
.succeeds()
2182+
.stdout_matches(&re_iso_old);
2183+
2184+
// Also test that we can set a format that varies for recent of older files.
2185+
//+FORMAT_RECENT\nFORMAT_OLD
2186+
f.set_modified(SystemTime::now()).unwrap();
2187+
scene
2188+
.ucmd()
2189+
.arg("-l")
2190+
.arg("--time-style=+RECENT\nOLD")
2191+
.succeeds()
2192+
.stdout_contains("RECENT");
2193+
2194+
// Old file
2195+
f.set_modified(SystemTime::now() - Duration::from_secs(3600 * 24 * 200))
2196+
.unwrap();
2197+
scene
2198+
.ucmd()
2199+
.arg("-l")
2200+
.arg("--time-style=+RECENT\nOLD")
2201+
.succeeds()
2202+
.stdout_contains("OLD");
2203+
2204+
// RECENT format is still used if no "OLD" one provided.
2205+
scene
2206+
.ucmd()
2207+
.arg("-l")
2208+
.arg("--time-style=+RECENT")
2209+
.succeeds()
2210+
.stdout_contains("RECENT");
2211+
}
2212+
21352213
#[test]
21362214
fn test_ls_order_time() {
21372215
let scene = TestScenario::new(util_name!());

0 commit comments

Comments
 (0)