|
3 | 3 | // For the full copyright and license information, please view the LICENSE |
4 | 4 | // file that was distributed with this source code. |
5 | 5 |
|
6 | | -// spell-checker:ignore strtime ; (format) DATEFILE MMDDhhmm ; (vars) datetime datetimes getres AWST ACST AEST |
| 6 | +// spell-checker:ignore strtime ; (format) DATEFILE MMDDhhmm ; (vars) datetime datetimes getres AWST ACST AEST foobarbaz |
7 | 7 |
|
8 | 8 | mod locale; |
9 | 9 |
|
10 | 10 | use clap::{Arg, ArgAction, Command}; |
11 | 11 | use jiff::fmt::strtime; |
12 | 12 | use jiff::tz::{TimeZone, TimeZoneDatabase}; |
13 | 13 | use jiff::{Timestamp, Zoned}; |
| 14 | +use std::borrow::Cow; |
14 | 15 | use std::collections::HashMap; |
15 | 16 | use std::fs::File; |
16 | 17 | use std::io::{BufRead, BufReader, BufWriter, Write}; |
@@ -130,6 +131,39 @@ enum DayDelta { |
130 | 131 | Next, |
131 | 132 | } |
132 | 133 |
|
| 134 | +/// Strip parenthesized comments from a date string. |
| 135 | +/// |
| 136 | +/// GNU date treats text enclosed in parentheses as comments. |
| 137 | +/// This function removes all `(...)` sequences from the input. |
| 138 | +/// If a `(` has no matching `)`, everything from `(` to end is removed. |
| 139 | +/// |
| 140 | +/// Examples: |
| 141 | +/// - "2026(comment)-01-05" -> "2026-01-05" |
| 142 | +/// - "1(ignore comment to eol" -> "1" |
| 143 | +/// - "(" -> "" |
| 144 | +/// - "foo(a)bar(b)baz" -> "foobarbaz" |
| 145 | +fn strip_parenthesized_comments(input: &str) -> Cow<'_, str> { |
| 146 | + let Some(first_paren) = input.find('(') else { |
| 147 | + return Cow::Borrowed(input); |
| 148 | + }; |
| 149 | + |
| 150 | + let mut result = String::with_capacity(input.len()); |
| 151 | + result.push_str(&input[..first_paren]); |
| 152 | + |
| 153 | + let mut chars = input[first_paren..].chars(); |
| 154 | + while let Some(c) = chars.next() { |
| 155 | + if c == '(' { |
| 156 | + if !chars.by_ref().any(|ch| ch == ')') { |
| 157 | + break; |
| 158 | + } |
| 159 | + } else { |
| 160 | + result.push(c); |
| 161 | + } |
| 162 | + } |
| 163 | + |
| 164 | + Cow::Owned(result) |
| 165 | +} |
| 166 | + |
133 | 167 | /// Parse military timezone with optional hour offset. |
134 | 168 | /// Pattern: single letter (a-z except j) optionally followed by 1-2 digits. |
135 | 169 | /// Returns Some(total_hours_in_utc) or None if pattern doesn't match. |
@@ -286,7 +320,10 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { |
286 | 320 | // Iterate over all dates - whether it's a single date or a file. |
287 | 321 | let dates: Box<dyn Iterator<Item = _>> = match settings.date_source { |
288 | 322 | DateSource::Human(ref input) => { |
| 323 | + // GNU compatibility (Comments in parentheses) |
| 324 | + let input = strip_parenthesized_comments(input); |
289 | 325 | let input = input.trim(); |
| 326 | + |
290 | 327 | // GNU compatibility (Empty string): |
291 | 328 | // An empty string (or whitespace-only) should be treated as midnight today. |
292 | 329 | let is_empty_or_whitespace = input.is_empty(); |
@@ -885,4 +922,25 @@ mod tests { |
885 | 922 | assert_eq!(parse_military_timezone_with_offset("m999"), None); // Too long |
886 | 923 | assert_eq!(parse_military_timezone_with_offset("9m"), None); // Starts with digit |
887 | 924 | } |
| 925 | + |
| 926 | + #[test] |
| 927 | + fn test_strip_parenthesized_comments() { |
| 928 | + assert_eq!(strip_parenthesized_comments("hello"), "hello"); |
| 929 | + assert_eq!(strip_parenthesized_comments("2026-01-05"), "2026-01-05"); |
| 930 | + assert_eq!(strip_parenthesized_comments("("), ""); |
| 931 | + assert_eq!(strip_parenthesized_comments("1(comment"), "1"); |
| 932 | + assert_eq!( |
| 933 | + strip_parenthesized_comments("2026-01-05(this is a comment"), |
| 934 | + "2026-01-05" |
| 935 | + ); |
| 936 | + assert_eq!( |
| 937 | + strip_parenthesized_comments("2026(comment)-01-05"), |
| 938 | + "2026-01-05" |
| 939 | + ); |
| 940 | + assert_eq!(strip_parenthesized_comments("a(b)c"), "ac"); |
| 941 | + assert_eq!(strip_parenthesized_comments("()"), ""); |
| 942 | + assert_eq!(strip_parenthesized_comments("a(b)c(d)e"), "ace"); |
| 943 | + assert_eq!(strip_parenthesized_comments("(a)(b)"), ""); |
| 944 | + assert_eq!(strip_parenthesized_comments("a(b)c(d"), "ac"); |
| 945 | + } |
888 | 946 | } |
0 commit comments