Skip to content

stat: fix precision when rendering mtime (%Y) #7115

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jan 12, 2025

Conversation

jfinkels
Copy link
Collaborator

Support precision when rendering the time of last data modification with stat. For example, after this commit

$ stat --printf='%.1Y\n' f
1668645806.7

Previously, the precision in the format specification was ignored. This is implemented with a custom renderer because GNU stat seems to truncate the number as opposed to rounding the number as would happen when using format! with a specified number of digits of precision.

Fixes #3233

Support precision when rendering the time of last data modification
with `stat`. For example, after this commit

    $ stat --printf='%.1Y\n' f
    1668645806.7

Previously, the precision in the format specification was
ignored. This is implemented with a custom renderer because GNU `stat`
seems to truncate the number as opposed to rounding the number as
would happen when using `format!` with a specified number of digits of
precision.

Fixes uutils#3233
@sylvestre
Copy link
Contributor

Sweet, i was working on it but your implementation is better than mine :)

Could you please add this test? It covers more cases

#[cfg(feature = "touch")]
#[test]
fn test_timestamp_format() {
    let ts = TestScenario::new(util_name!());

    // Create a file with a specific timestamp for testing
    ts.ccmd("touch")
        .args(&["-d", "1970-01-01 18:43:33.023456789", "k"])
        .succeeds()
        .no_stderr();

    let test_cases = vec![
        // Basic timestamp formats
        ("%Y", "67413"),
        ("%.Y", "67413.023456789"),
        ("%.1Y", "67413.0"),
        ("%.3Y", "67413.023"),
        ("%.6Y", "67413.023456"),
        ("%.9Y", "67413.023456789"),
        // Width and padding tests
        ("%13.6Y", " 67413.023456"),
        ("%013.6Y", "067413.023456"),
        ("%-13.6Y", "67413.023456 "),
        // Longer width/precision combinations
        ("%18.10Y", " 67413.0234567890"),
        ("%I18.10Y", " 67413.0234567890"),
        ("%018.10Y", "0067413.0234567890"),
        ("%-18.10Y", "67413.0234567890 "),
    ];

    for (format_str, expected) in test_cases {
        let result = ts
            .ucmd()
            .args(&["-c", format_str, "k"])
            .succeeds()
            .stdout_move_str();

        assert_eq!(
            result.trim(),
            expected,
            "Format '{}' failed.\nExpected: '{}'\nGot: '{}'",
            format_str,
            expected,
            result.trim()
        );
    }
}

@jfinkels
Copy link
Collaborator Author

jfinkels commented Jan 11, 2025 via email

@jfinkels
Copy link
Collaborator Author

In order to pass the new test cases, I needed to update the code a bit. There is now a Precision enum that distinguishes between NotSpecified (as in %Y), NoNumber (as in %.Y), and Number(usize) (as in %.3Y). I also made some slight adjustments to the proposed tests: (1) the number of spaces was off by one in the padding test cases, and (2) the result.trim() was trimming the spaces.

There is still a few aspects of the code that are not quite right, but I think they can be fixed in separate pull requests. First, there is some numerical inaccuracy between getting the Metadata::mtime_nsec() and the formatting code, so what should be .7639 is actually .7640. Second, the handling of %.Y does not quite match the documentation, which specifies 9 digits of precision.

@sylvestre
Copy link
Contributor

Yeah, it is surprisingly complex :)

Copy link

GNU testsuite comparison:

GNU test failed: tests/misc/stdbuf. tests/misc/stdbuf is passing on 'main'. Maybe you have to rebase?
Skip an intermittent issue tests/tail/inotify-dir-recreate (fails in this run but passes in the 'main' branch)
Congrats! The gnu test tests/chmod/symlinks is no longer failing!

@sylvestre sylvestre merged commit 988cc4e into uutils:main Jan 12, 2025
64 of 65 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

stat: --printf option does not support precision in certain format strings
2 participants