mirror of
https://github.com/uutils/coreutils.git
synced 2026-06-10 15:48:22 -07:00
date: use PosixCustom formatting for GNU-compatible output (#10245)
This commit is contained in:
+15
-13
@@ -8,7 +8,7 @@
|
||||
mod locale;
|
||||
|
||||
use clap::{Arg, ArgAction, Command};
|
||||
use jiff::fmt::strtime;
|
||||
use jiff::fmt::strtime::{self, BrokenDownTime, Config, PosixCustom};
|
||||
use jiff::tz::{TimeZone, TimeZoneDatabase};
|
||||
use jiff::{Timestamp, Zoned};
|
||||
use std::collections::HashMap;
|
||||
@@ -431,21 +431,23 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||
let mut stdout = BufWriter::new(std::io::stdout().lock());
|
||||
|
||||
// Format all the dates
|
||||
let config = Config::new().custom(PosixCustom::new()).lenient(true);
|
||||
for date in dates {
|
||||
match date {
|
||||
// TODO: Switch to lenient formatting.
|
||||
Ok(date) => match strtime::format(format_string, &date) {
|
||||
Ok(s) => writeln!(stdout, "{s}").map_err(|e| {
|
||||
USimpleError::new(1, translate!("date-error-write", "error" => e))
|
||||
})?,
|
||||
Err(e) => {
|
||||
let _ = stdout.flush();
|
||||
return Err(USimpleError::new(
|
||||
1,
|
||||
translate!("date-error-invalid-format", "format" => format_string, "error" => e),
|
||||
));
|
||||
Ok(date) => {
|
||||
match BrokenDownTime::from(&date).to_string_with_config(&config, format_string) {
|
||||
Ok(s) => writeln!(stdout, "{s}").map_err(|e| {
|
||||
USimpleError::new(1, translate!("date-error-write", "error" => e))
|
||||
})?,
|
||||
Err(e) => {
|
||||
let _ = stdout.flush();
|
||||
return Err(USimpleError::new(
|
||||
1,
|
||||
translate!("date-error-invalid-format", "format" => format_string, "error" => e),
|
||||
));
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
Err((input, _err)) => {
|
||||
let _ = stdout.flush();
|
||||
show!(USimpleError::new(
|
||||
|
||||
@@ -480,9 +480,8 @@ fn test_date_set_valid_4() {
|
||||
|
||||
#[test]
|
||||
fn test_invalid_format_string() {
|
||||
let result = new_ucmd!().arg("+%!").fails();
|
||||
result.no_stdout();
|
||||
assert!(result.stderr_str().starts_with("date: invalid format "));
|
||||
// With lenient mode, invalid format sequences are output literally (like GNU date)
|
||||
new_ucmd!().arg("+%!").succeeds().stdout_is("%!\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -1446,3 +1445,27 @@ fn test_date_locale_fr_french() {
|
||||
"Output should include timezone information, got: {stdout}"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_date_posix_format_specifiers() {
|
||||
let cases = [
|
||||
// %r: 12-hour time with zero-padded hour (08:17:48 AM, not 8:17:48 AM)
|
||||
("%r", "08:17:48 AM"),
|
||||
// %x: locale date in MM/DD/YY format
|
||||
("%x", "01/19/97"),
|
||||
// %X: locale time in HH:MM:SS format
|
||||
("%X", "08:17:48"),
|
||||
// %:8z: invalid format (width between : and z) should output literally (lenient mode)
|
||||
("%:8z", "%:8z"),
|
||||
];
|
||||
|
||||
for (format, expected) in cases {
|
||||
new_ucmd!()
|
||||
.env("TZ", "UTC")
|
||||
.arg("-d")
|
||||
.arg("1997-01-19 08:17:48")
|
||||
.arg(format!("+{format}"))
|
||||
.succeeds()
|
||||
.stdout_is(format!("{expected}\n"));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user