Skip to content

Commit c541adf

Browse files
Felle33drebbe-intrepid
authored andcommitted
ls, date: refactor common code for formatting a datetime (uutils#7194)
* refactoring ls and date * Refactored and integrated ls and date and added tests to the new feature * Style refactoring
1 parent 47de52a commit c541adf

File tree

9 files changed

+80
-57
lines changed

9 files changed

+80
-57
lines changed

Cargo.lock

Lines changed: 3 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/uu/date/Cargo.toml

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,8 @@ path = "src/date.rs"
2020
[dependencies]
2121
chrono = { workspace = true }
2222
clap = { workspace = true }
23-
uucore = { workspace = true }
23+
uucore = { workspace = true, features = ["custom-tz-fmt"] }
2424
parse_datetime = { workspace = true }
25-
chrono-tz = { workspace = true }
26-
iana-time-zone = { workspace = true }
2725

2826
[target.'cfg(unix)'.dependencies]
2927
libc = { workspace = true }

src/uu/date/src/date.rs

Lines changed: 4 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,16 @@
66
// spell-checker:ignore (chrono) Datelike Timelike ; (format) DATEFILE MMDDhhmm ; (vars) datetime datetimes
77

88
use chrono::format::{Item, StrftimeItems};
9-
use chrono::{DateTime, FixedOffset, Local, Offset, TimeDelta, TimeZone, Utc};
9+
use chrono::{DateTime, FixedOffset, Local, Offset, TimeDelta, Utc};
1010
#[cfg(windows)]
1111
use chrono::{Datelike, Timelike};
12-
use chrono_tz::{OffsetName, Tz};
1312
use clap::{crate_version, Arg, ArgAction, Command};
14-
use iana_time_zone::get_timezone;
1513
#[cfg(all(unix, not(target_os = "macos"), not(target_os = "redox")))]
1614
use libc::{clock_settime, timespec, CLOCK_REALTIME};
1715
use std::fs::File;
1816
use std::io::{BufRead, BufReader};
1917
use std::path::PathBuf;
18+
use uucore::custom_tz_fmt::custom_time_format;
2019
use uucore::display::Quotable;
2120
use uucore::error::FromIo;
2221
use uucore::error::{UResult, USimpleError};
@@ -274,21 +273,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
274273
for date in dates {
275274
match date {
276275
Ok(date) => {
277-
// TODO - Revisit when chrono 0.5 is released. https://github.com/chronotope/chrono/issues/970
278-
let tz = match std::env::var("TZ") {
279-
// TODO Support other time zones...
280-
Ok(s) if s == "UTC0" || s.is_empty() => Tz::Etc__UTC,
281-
_ => match get_timezone() {
282-
Ok(tz_str) => tz_str.parse().unwrap(),
283-
Err(_) => Tz::Etc__UTC,
284-
},
285-
};
286-
let offset = tz.offset_from_utc_date(&Utc::now().date_naive());
287-
let tz_abbreviation = offset.abbreviation();
288-
// GNU `date` uses `%N` for nano seconds, however crate::chrono uses `%f`
289-
let format_string = &format_string
290-
.replace("%N", "%f")
291-
.replace("%Z", tz_abbreviation.unwrap_or("UTC"));
276+
let format_string = custom_time_format(format_string);
292277
// Refuse to pass this string to chrono as it is crashing in this crate
293278
if format_string.contains("%#z") {
294279
return Err(USimpleError::new(
@@ -298,7 +283,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
298283
}
299284
// Hack to work around panic in chrono,
300285
// TODO - remove when a fix for https://github.com/chronotope/chrono/issues/623 is released
301-
let format_items = StrftimeItems::new(format_string);
286+
let format_items = StrftimeItems::new(format_string.as_str());
302287
if format_items.clone().any(|i| i == Item::Error) {
303288
return Err(USimpleError::new(
304289
1,

src/uu/ls/Cargo.toml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,18 +19,17 @@ path = "src/ls.rs"
1919
[dependencies]
2020
ansi-width = { workspace = true }
2121
chrono = { workspace = true }
22-
chrono-tz = { workspace = true }
2322
clap = { workspace = true, features = ["env"] }
2423
glob = { workspace = true }
2524
hostname = { workspace = true }
26-
iana-time-zone = { workspace = true }
2725
lscolors = { workspace = true }
2826
number_prefix = { workspace = true }
2927
once_cell = { workspace = true }
3028
selinux = { workspace = true, optional = true }
3129
terminal_size = { workspace = true }
3230
uucore = { workspace = true, features = [
3331
"colors",
32+
"custom-tz-fmt",
3433
"entries",
3534
"format",
3635
"fs",

src/uu/ls/src/ls.rs

Lines changed: 5 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -27,14 +27,12 @@ use std::{
2727
use std::{collections::HashSet, io::IsTerminal};
2828

2929
use ansi_width::ansi_width;
30-
use chrono::{DateTime, Local, TimeDelta, TimeZone, Utc};
31-
use chrono_tz::{OffsetName, Tz};
30+
use chrono::{DateTime, Local, TimeDelta};
3231
use clap::{
3332
builder::{NonEmptyStringValueParser, PossibleValue, ValueParser},
3433
crate_version, Arg, ArgAction, Command,
3534
};
3635
use glob::{MatchOptions, Pattern};
37-
use iana_time_zone::get_timezone;
3836
use lscolors::LsColors;
3937
use term_grid::{Direction, Filling, Grid, GridOptions};
4038

@@ -60,6 +58,7 @@ use uucore::libc::{S_IXGRP, S_IXOTH, S_IXUSR};
6058
use uucore::line_ending::LineEnding;
6159
use uucore::quoting_style::{self, escape_name, QuotingStyle};
6260
use uucore::{
61+
custom_tz_fmt,
6362
display::Quotable,
6463
error::{set_exit_code, UError, UResult},
6564
format_usage,
@@ -345,31 +344,6 @@ fn is_recent(time: DateTime<Local>) -> bool {
345344
time + TimeDelta::try_seconds(31_556_952 / 2).unwrap() > Local::now()
346345
}
347346

348-
/// Get the alphabetic abbreviation of the current timezone.
349-
///
350-
/// For example, "UTC" or "CET" or "PDT".
351-
fn timezone_abbrev() -> String {
352-
let tz = match std::env::var("TZ") {
353-
// TODO Support other time zones...
354-
Ok(s) if s == "UTC0" || s.is_empty() => Tz::Etc__UTC,
355-
_ => match get_timezone() {
356-
Ok(tz_str) => tz_str.parse().unwrap(),
357-
Err(_) => Tz::Etc__UTC,
358-
},
359-
};
360-
let offset = tz.offset_from_utc_date(&Utc::now().date_naive());
361-
offset.abbreviation().unwrap_or("UTC").to_string()
362-
}
363-
364-
/// Format the given time according to a custom format string.
365-
fn custom_time_format(fmt: &str, time: DateTime<Local>) -> String {
366-
// TODO Refactor the common code from `ls` and `date` for rendering dates.
367-
// TODO - Revisit when chrono 0.5 is released. https://github.com/chronotope/chrono/issues/970
368-
// GNU `date` uses `%N` for nano seconds, however the `chrono` crate uses `%f`.
369-
let fmt = fmt.replace("%N", "%f").replace("%Z", &timezone_abbrev());
370-
time.format(&fmt).to_string()
371-
}
372-
373347
impl TimeStyle {
374348
/// Format the given time according to this time format style.
375349
fn format(&self, time: DateTime<Local>) -> String {
@@ -386,7 +360,9 @@ impl TimeStyle {
386360
//So it's not yet implemented
387361
(Self::Locale, true) => time.format("%b %e %H:%M").to_string(),
388362
(Self::Locale, false) => time.format("%b %e %Y").to_string(),
389-
(Self::Format(e), _) => custom_time_format(e, time),
363+
(Self::Format(fmt), _) => time
364+
.format(custom_tz_fmt::custom_time_format(fmt).as_str())
365+
.to_string(),
390366
}
391367
}
392368
}

src/uucore/Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,16 @@ edition = "2021"
1818
path = "src/lib/lib.rs"
1919

2020
[dependencies]
21+
chrono = { workspace = true }
22+
chrono-tz = { workspace = true }
2123
clap = { workspace = true }
2224
uucore_procs = { workspace = true }
2325
number_prefix = { workspace = true }
2426
dns-lookup = { workspace = true, optional = true }
2527
dunce = { version = "1.0.4", optional = true }
2628
wild = "2.2.1"
2729
glob = { workspace = true }
30+
iana-time-zone = { workspace = true }
2831
lazy_static = "1.4.0"
2932
# * optional
3033
itertools = { workspace = true, optional = true }
@@ -114,4 +117,5 @@ utf8 = []
114117
utmpx = ["time", "time/macros", "libc", "dns-lookup"]
115118
version-cmp = []
116119
wide = []
120+
custom-tz-fmt = []
117121
tty = []

src/uucore/src/lib/features.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ pub mod buf_copy;
1212
pub mod checksum;
1313
#[cfg(feature = "colors")]
1414
pub mod colors;
15+
#[cfg(feature = "custom-tz-fmt")]
16+
pub mod custom_tz_fmt;
1517
#[cfg(feature = "encoding")]
1618
pub mod encoding;
1719
#[cfg(feature = "format")]
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
// This file is part of the uutils coreutils package.
2+
//
3+
// For the full copyright and license information, please view the LICENSE
4+
// file that was distributed with this source code.
5+
6+
use chrono::{TimeZone, Utc};
7+
use chrono_tz::{OffsetName, Tz};
8+
use iana_time_zone::get_timezone;
9+
10+
/// Get the alphabetic abbreviation of the current timezone.
11+
///
12+
/// For example, "UTC" or "CET" or "PDT"
13+
fn timezone_abbreviation() -> String {
14+
let tz = match std::env::var("TZ") {
15+
// TODO Support other time zones...
16+
Ok(s) if s == "UTC0" || s.is_empty() => Tz::Etc__UTC,
17+
_ => match get_timezone() {
18+
Ok(tz_str) => tz_str.parse().unwrap(),
19+
Err(_) => Tz::Etc__UTC,
20+
},
21+
};
22+
23+
let offset = tz.offset_from_utc_date(&Utc::now().date_naive());
24+
offset.abbreviation().unwrap_or("UTC").to_string()
25+
}
26+
27+
/// Adapt the given string to be accepted by the chrono library crate.
28+
///
29+
/// # Arguments
30+
///
31+
/// fmt: the format of the string
32+
///
33+
/// # Return
34+
///
35+
/// A string that can be used as parameter of the chrono functions that use formats
36+
pub fn custom_time_format(fmt: &str) -> String {
37+
// TODO - Revisit when chrono 0.5 is released. https://github.com/chronotope/chrono/issues/970
38+
// GNU `date` uses `%N` for nano seconds, however the `chrono` crate uses `%f`.
39+
fmt.replace("%N", "%f")
40+
.replace("%Z", timezone_abbreviation().as_ref())
41+
}
42+
43+
#[cfg(test)]
44+
mod tests {
45+
use super::{custom_time_format, timezone_abbreviation};
46+
47+
#[test]
48+
fn test_custom_time_format() {
49+
assert_eq!(custom_time_format("%Y-%m-%d %H-%M-%S"), "%Y-%m-%d %H-%M-%S");
50+
assert_eq!(custom_time_format("%d-%m-%Y %H-%M-%S"), "%d-%m-%Y %H-%M-%S");
51+
assert_eq!(custom_time_format("%Y-%m-%d %H-%M-%S"), "%Y-%m-%d %H-%M-%S");
52+
assert_eq!(
53+
custom_time_format("%Y-%m-%d %H-%M-%S.%N"),
54+
"%Y-%m-%d %H-%M-%S.%f"
55+
);
56+
assert_eq!(custom_time_format("%Z"), timezone_abbreviation());
57+
}
58+
}

src/uucore/src/lib/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ pub use crate::features::buf_copy;
4646
pub use crate::features::checksum;
4747
#[cfg(feature = "colors")]
4848
pub use crate::features::colors;
49+
#[cfg(feature = "custom-tz-fmt")]
50+
pub use crate::features::custom_tz_fmt;
4951
#[cfg(feature = "encoding")]
5052
pub use crate::features::encoding;
5153
#[cfg(feature = "format")]

0 commit comments

Comments
 (0)