mirror of
https://github.com/uutils/coreutils.git
synced 2026-06-10 15:48:22 -07:00
date: add support for the 'J' military timezone
This commit is contained in:
+22
-2
@@ -205,15 +205,35 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||
// Iterate over all dates - whether it's a single date or a file.
|
||||
let dates: Box<dyn Iterator<Item = _>> = match settings.date_source {
|
||||
DateSource::Human(ref input) => {
|
||||
// GNU compatibility (Military timezone 'J'):
|
||||
// 'J' is reserved for local time in military timezones.
|
||||
// GNU date accepts it and treats it as midnight today (00:00:00).
|
||||
let is_military_j = input.eq_ignore_ascii_case("j");
|
||||
|
||||
// GNU compatibility (Pure numbers in date strings):
|
||||
// - Manual: https://www.gnu.org/software/coreutils/manual/html_node/Pure-numbers-in-date-strings.html
|
||||
// - Semantics: a pure decimal number denotes today’s time-of-day (HH or HHMM).
|
||||
// - Semantics: a pure decimal number denotes today's time-of-day (HH or HHMM).
|
||||
// Examples: "0"/"00" => 00:00 today; "7"/"07" => 07:00 today; "0700" => 07:00 today.
|
||||
// For all other forms, fall back to the general parser.
|
||||
let is_pure_digits =
|
||||
!input.is_empty() && input.len() <= 4 && input.chars().all(|c| c.is_ascii_digit());
|
||||
|
||||
let date = if is_pure_digits {
|
||||
let date = if is_military_j {
|
||||
// Treat 'J' as midnight today (00:00:00) in local time
|
||||
let date_part =
|
||||
strtime::format("%F", &now).unwrap_or_else(|_| String::from("1970-01-01"));
|
||||
let offset = if settings.utc {
|
||||
String::from("+00:00")
|
||||
} else {
|
||||
strtime::format("%:z", &now).unwrap_or_default()
|
||||
};
|
||||
let composed = if offset.is_empty() {
|
||||
format!("{date_part} 00:00")
|
||||
} else {
|
||||
format!("{date_part} 00:00 {offset}")
|
||||
};
|
||||
parse_date(composed)
|
||||
} else if is_pure_digits {
|
||||
// Derive HH and MM from the input
|
||||
let (hh_opt, mm_opt) = if input.len() <= 2 {
|
||||
(input.parse::<u32>().ok(), Some(0u32))
|
||||
|
||||
@@ -946,17 +946,30 @@ fn test_date_tz_abbreviation_unknown() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore = "we reject 'J', GNU treats as midnight"]
|
||||
fn test_date_fuzz_military_timezone_j() {
|
||||
// J is reserved for local time in military timezones
|
||||
// GNU date treats it as midnight, we reject it
|
||||
fn test_date_military_timezone_j_variations() {
|
||||
// Test multiple variations of 'J' input (case insensitive, with whitespace)
|
||||
// All should produce midnight (00:00:00)
|
||||
let test_cases = vec!["J", "j", " J ", " j ", "\tJ\t"];
|
||||
|
||||
for input in test_cases {
|
||||
new_ucmd!()
|
||||
.env("TZ", "UTC")
|
||||
.arg("-d")
|
||||
.arg(input)
|
||||
.arg("+%T")
|
||||
.succeeds()
|
||||
.stdout_is("00:00:00\n");
|
||||
}
|
||||
|
||||
// Test with -u flag to verify UTC behavior
|
||||
new_ucmd!()
|
||||
.env("TZ", "UTC+1")
|
||||
.arg("-u")
|
||||
.arg("-d")
|
||||
.arg("J")
|
||||
.arg("+%F %T %Z")
|
||||
.arg("+%T %Z")
|
||||
.succeeds()
|
||||
.stdout_contains("00:00:00");
|
||||
.stdout_contains("00:00:00")
|
||||
.stdout_contains("UTC");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user