Skip to content

Commit 6c73ef6

Browse files
committed
uucore: time: Add options for format_system_time
Depending on the caller, we want the number of seconds, that and an error printed out, or seconds+nanoseconds.
1 parent 6eb75f2 commit 6c73ef6

File tree

4 files changed

+105
-17
lines changed

4 files changed

+105
-17
lines changed

src/uu/du/src/du.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ use uucore::locale::{get_message, get_message_with_args};
2727
use uucore::parser::parse_glob;
2828
use uucore::parser::parse_size::{ParseSizeError, parse_size_u64};
2929
use uucore::parser::shortcut_value_parser::ShortcutValueParser;
30+
use uucore::time::{FormatSystemTimeFallback, format_system_time};
3031
use uucore::{format_usage, show, show_error, show_warning};
3132
#[cfg(windows)]
3233
use windows_sys::Win32::Foundation::HANDLE;
@@ -528,7 +529,12 @@ impl StatPrinter {
528529

529530
if let Some(md_time) = &self.time {
530531
if let Some(time) = metadata_get_time(&stat.metadata, *md_time) {
531-
uucore::time::format_system_time(&mut stdout(), time, &self.time_format, true)?;
532+
format_system_time(
533+
&mut stdout(),
534+
time,
535+
&self.time_format,
536+
FormatSystemTimeFallback::IntegerError,
537+
)?;
532538
print!("\t");
533539
} else {
534540
print!("???\t");

src/uu/ls/src/ls.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ use uucore::libc::{dev_t, major, minor};
6060
use uucore::line_ending::LineEnding;
6161
use uucore::locale::{get_message, get_message_with_args};
6262
use uucore::quoting_style::{QuotingStyle, locale_aware_escape_dir_name, locale_aware_escape_name};
63+
use uucore::time::{FormatSystemTimeFallback, format_system_time};
6364
use uucore::{
6465
display::Quotable,
6566
error::{UError, UResult, set_exit_code},
@@ -2968,7 +2969,7 @@ fn display_date(
29682969
_ => &config.time_format_recent,
29692970
};
29702971

2971-
uucore::time::format_system_time(out, time, fmt, false)
2972+
format_system_time(out, time, fmt, FormatSystemTimeFallback::Integer)
29722973
}
29732974

29742975
#[allow(dead_code)]

src/uu/stat/src/stat.rs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ use std::{env, fs};
2828
use std::collections::HashMap;
2929
use thiserror::Error;
3030
use uucore::locale::{get_message, get_message_with_args};
31-
use uucore::time::{format_system_time, system_time_to_sec};
31+
use uucore::time::{FormatSystemTimeFallback, format_system_time, system_time_to_sec};
3232

3333
#[derive(Debug, Error)]
3434
enum StatError {
@@ -1288,7 +1288,14 @@ const PRETTY_DATETIME_FORMAT: &str = "%Y-%m-%d %H:%M:%S.%N %z";
12881288
fn pretty_time(meta: &Metadata, md_time_field: MetadataTimeField) -> String {
12891289
if let Some(time) = metadata_get_time(meta, md_time_field) {
12901290
let mut tmp = Vec::new();
1291-
if format_system_time(&mut tmp, time, PRETTY_DATETIME_FORMAT, false).is_ok() {
1291+
if format_system_time(
1292+
&mut tmp,
1293+
time,
1294+
PRETTY_DATETIME_FORMAT,
1295+
FormatSystemTimeFallback::Float,
1296+
)
1297+
.is_ok()
1298+
{
12921299
return String::from_utf8(tmp).unwrap();
12931300
}
12941301
}

src/uucore/src/lib/features/time.rs

Lines changed: 87 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -36,12 +36,19 @@ pub fn system_time_to_sec(time: SystemTime) -> (i64, u32) {
3636
}
3737
}
3838

39+
/// Sets how `format_system_time` behaves if the time cannot be converted.
40+
pub enum FormatSystemTimeFallback {
41+
Integer, // Just print seconds since epoch (`ls`)
42+
IntegerError, // The above, and print an error (`du``)
43+
Float, // Just print seconds+nanoseconds since epoch (`stat`)
44+
}
45+
3946
/// Format a `SystemTime` according to given fmt, and append to vector out.
4047
pub fn format_system_time<W: Write>(
4148
out: &mut W,
4249
time: SystemTime,
4350
fmt: &str,
44-
show_error: bool,
51+
mode: FormatSystemTimeFallback,
4552
) -> UResult<()> {
4653
let zoned: Result<Zoned, _> = time.try_into();
4754
match zoned {
@@ -53,20 +60,30 @@ pub fn format_system_time<W: Write>(
5360
// but it still far enough in the future/past to be unlikely to matter:
5461
// jiff: Year between -9999 to 9999 (UTC) [-377705023201..=253402207200]
5562
// GNU: Year fits in signed 32 bits (timezone dependent)
56-
let ts: i64 = system_time_to_sec(time).0;
57-
let str = ts.to_string();
58-
if show_error {
59-
show_error!("time '{str}' is out of range");
60-
}
61-
out.write_all(str.as_bytes())?;
63+
let (mut secs, mut nsecs) = system_time_to_sec(time);
64+
match mode {
65+
FormatSystemTimeFallback::Integer => out.write_all(secs.to_string().as_bytes())?,
66+
FormatSystemTimeFallback::IntegerError => {
67+
let str = secs.to_string();
68+
show_error!("time '{str}' is out of range");
69+
out.write_all(str.as_bytes())?;
70+
}
71+
FormatSystemTimeFallback::Float => {
72+
if secs < 0 && nsecs != 0 {
73+
secs -= 1;
74+
nsecs = 1_000_000_000 - nsecs;
75+
}
76+
out.write_fmt(format_args!("{secs}.{nsecs:09}"))?;
77+
}
78+
};
6279
Ok(())
6380
}
6481
}
6582
}
6683

6784
#[cfg(test)]
6885
mod tests {
69-
use crate::time::format_system_time;
86+
use crate::time::{FormatSystemTimeFallback, format_system_time};
7087
use std::time::{Duration, UNIX_EPOCH};
7188

7289
// Test epoch SystemTime get printed correctly at UTC0, with 2 simple formats.
@@ -76,12 +93,23 @@ mod tests {
7693

7794
let time = UNIX_EPOCH;
7895
let mut out = Vec::new();
79-
format_system_time(&mut out, time, "%Y-%m-%d %H:%M", false).expect("Formatting error.");
96+
format_system_time(
97+
&mut out,
98+
time,
99+
"%Y-%m-%d %H:%M",
100+
FormatSystemTimeFallback::Integer,
101+
)
102+
.expect("Formatting error.");
80103
assert_eq!(String::from_utf8(out).unwrap(), "1970-01-01 00:00");
81104

82105
let mut out = Vec::new();
83-
format_system_time(&mut out, time, "%Y-%m-%d %H:%M:%S.%N %z", false)
84-
.expect("Formatting error.");
106+
format_system_time(
107+
&mut out,
108+
time,
109+
"%Y-%m-%d %H:%M:%S.%N %z",
110+
FormatSystemTimeFallback::Integer,
111+
)
112+
.expect("Formatting error.");
85113
assert_eq!(
86114
String::from_utf8(out).unwrap(),
87115
"1970-01-01 00:00:00.000000000 +0000"
@@ -93,12 +121,58 @@ mod tests {
93121
fn test_large_system_time() {
94122
let time = UNIX_EPOCH + Duration::from_secs(67_768_036_191_763_200);
95123
let mut out = Vec::new();
96-
format_system_time(&mut out, time, "%Y-%m-%d %H:%M", false).expect("Formatting error.");
124+
format_system_time(
125+
&mut out,
126+
time,
127+
"%Y-%m-%d %H:%M",
128+
FormatSystemTimeFallback::Integer,
129+
)
130+
.expect("Formatting error.");
97131
assert_eq!(String::from_utf8(out).unwrap(), "67768036191763200");
98132

99133
let time = UNIX_EPOCH - Duration::from_secs(67_768_040_922_076_800);
100134
let mut out = Vec::new();
101-
format_system_time(&mut out, time, "%Y-%m-%d %H:%M", false).expect("Formatting error.");
135+
format_system_time(
136+
&mut out,
137+
time,
138+
"%Y-%m-%d %H:%M",
139+
FormatSystemTimeFallback::Integer,
140+
)
141+
.expect("Formatting error.");
102142
assert_eq!(String::from_utf8(out).unwrap(), "-67768040922076800");
103143
}
144+
145+
// Test that very large (positive or negative) lead to just the timestamp being printed.
146+
#[test]
147+
fn test_large_system_time_float() {
148+
let time =
149+
UNIX_EPOCH + Duration::from_secs(67_768_036_191_763_000) + Duration::from_nanos(123);
150+
let mut out = Vec::new();
151+
format_system_time(
152+
&mut out,
153+
time,
154+
"%Y-%m-%d %H:%M",
155+
FormatSystemTimeFallback::Float,
156+
)
157+
.expect("Formatting error.");
158+
assert_eq!(
159+
String::from_utf8(out).unwrap(),
160+
"67768036191763000.000000123"
161+
);
162+
163+
let time =
164+
UNIX_EPOCH - Duration::from_secs(67_768_040_922_076_000) + Duration::from_nanos(123);
165+
let mut out = Vec::new();
166+
format_system_time(
167+
&mut out,
168+
time,
169+
"%Y-%m-%d %H:%M",
170+
FormatSystemTimeFallback::Float,
171+
)
172+
.expect("Formatting error.");
173+
assert_eq!(
174+
String::from_utf8(out).unwrap(),
175+
"-67768040922076000.000000123"
176+
);
177+
}
104178
}

0 commit comments

Comments
 (0)