pr: Set date format depending on environment.

Based on GNU manual.
This commit is contained in:
Nicolas Boichat
2025-07-31 15:45:31 +08:00
parent 149529a494
commit 4878e65ea7
2 changed files with 68 additions and 7 deletions
+16 -3
View File
@@ -20,7 +20,7 @@ use uucore::display::Quotable;
use uucore::error::UResult;
use uucore::format_usage;
use uucore::translate;
use uucore::time::{FormatSystemTimeFallback, format_system_time};
use uucore::time::{FormatSystemTimeFallback, format, format_system_time};
const TAB: char = '\t';
const LINES_PER_PAGE: usize = 66;
@@ -33,7 +33,6 @@ const DEFAULT_COLUMN_WIDTH: usize = 72;
const DEFAULT_COLUMN_WIDTH_WITH_S_OPTION: usize = 512;
const DEFAULT_COLUMN_SEPARATOR: &char = &TAB;
const FF: u8 = 0x0C_u8;
const DATE_TIME_FORMAT: &str = "%b %d %H:%M %Y";
mod options {
pub const HEADER: &str = "header";
@@ -402,6 +401,20 @@ fn parse_usize(matches: &ArgMatches, opt: &str) -> Option<Result<usize, PrError>
.map(from_parse_error_to_pr_error)
}
fn get_date_format() -> String {
// Replicate behavior from GNU manual.
if std::env::var("POSIXLY_CORRECT").is_ok()
// TODO: This needs to be moved to uucore and handled by icu?
&& (std::env::var("LC_TIME").unwrap_or_default() == "POSIX"
|| std::env::var("LC_ALL").unwrap_or_default() == "POSIX")
{
"%b %e %H:%M %Y"
} else {
format::LONG_ISO
}
.to_string()
}
#[allow(clippy::cognitive_complexity)]
fn build_options(
matches: &ArgMatches,
@@ -501,7 +514,7 @@ fn build_options(
format_system_time(
&mut v,
time,
DATE_TIME_FORMAT,
&get_date_format(),
FormatSystemTimeFallback::Integer,
)
.ok()
+52 -4
View File
@@ -9,9 +9,9 @@ use std::fs::metadata;
use uutests::new_ucmd;
use uutests::util::UCommand;
const DATE_TIME_FORMAT: &str = "%b %d %H:%M %Y";
const DATE_TIME_FORMAT_DEFAULT: &str = "%Y-%m-%d %H:%M";
fn file_last_modified_time(ucmd: &UCommand, path: &str) -> String {
fn file_last_modified_time_format(ucmd: &UCommand, path: &str, format: &str) -> String {
let tmp_dir_path = ucmd.get_full_fixture_path(path);
let file_metadata = metadata(tmp_dir_path);
file_metadata
@@ -19,19 +19,23 @@ fn file_last_modified_time(ucmd: &UCommand, path: &str) -> String {
i.modified()
.map(|x| {
let date_time: DateTime<Utc> = x.into();
date_time.format(DATE_TIME_FORMAT).to_string()
date_time.format(format).to_string()
})
.unwrap_or_default()
})
.unwrap_or_default()
}
fn file_last_modified_time(ucmd: &UCommand, path: &str) -> String {
file_last_modified_time_format(ucmd, path, DATE_TIME_FORMAT_DEFAULT)
}
fn all_minutes(from: DateTime<Utc>, to: DateTime<Utc>) -> Vec<String> {
let to = to + Duration::try_minutes(1).unwrap();
let mut vec = vec![];
let mut current = from;
while current < to {
vec.push(current.format(DATE_TIME_FORMAT).to_string());
vec.push(current.format(DATE_TIME_FORMAT_DEFAULT).to_string());
current += Duration::try_minutes(1).unwrap();
}
vec
@@ -398,6 +402,50 @@ fn test_with_offset_space_option() {
.stdout_is_templated_fixture(expected_test_file_path, &[("{last_modified_time}", &value)]);
}
#[test]
fn test_with_date_format() {
const POSIXLY_FORMAT: &str = "%b %e %H:%M %Y";
// POSIXLY_CORRECT + LC_ALL/TIME=POSIX uses "%b %e %H:%M %Y" date format
let test_file_path = "test_one_page.log";
let expected_test_file_path = "test_one_page.log.expected";
let mut scenario = new_ucmd!();
let value = file_last_modified_time_format(&scenario, test_file_path, POSIXLY_FORMAT);
scenario
.env("POSIXLY_CORRECT", "1")
.env("LC_ALL", "POSIX")
.args(&[test_file_path])
.succeeds()
.stdout_is_templated_fixture(expected_test_file_path, &[("{last_modified_time}", &value)]);
let mut scenario = new_ucmd!();
let value = file_last_modified_time_format(&scenario, test_file_path, POSIXLY_FORMAT);
scenario
.env("POSIXLY_CORRECT", "1")
.env("LC_TIME", "POSIX")
.args(&[test_file_path])
.succeeds()
.stdout_is_templated_fixture(expected_test_file_path, &[("{last_modified_time}", &value)]);
// But not if POSIXLY_CORRECT/LC_ALL is something else.
let mut scenario = new_ucmd!();
let value = file_last_modified_time_format(&scenario, test_file_path, DATE_TIME_FORMAT_DEFAULT);
scenario
.env("LC_TIME", "POSIX")
.args(&[test_file_path])
.succeeds()
.stdout_is_templated_fixture(expected_test_file_path, &[("{last_modified_time}", &value)]);
let mut scenario = new_ucmd!();
let value = file_last_modified_time_format(&scenario, test_file_path, DATE_TIME_FORMAT_DEFAULT);
scenario
.env("POSIXLY_CORRECT", "1")
.env("LC_TIME", "C")
.args(&[test_file_path])
.succeeds()
.stdout_is_templated_fixture(expected_test_file_path, &[("{last_modified_time}", &value)]);
}
#[test]
fn test_with_pr_core_utils_tests() {
let test_cases = vec![