* src/stat.c (epoch_time): New function. (print_stat): Use it for %[WXYZ]. * NEWS: Document this. * tests/touch/60-seconds: Adjust test to match. ---
It bugs me that %x has more information than %X in 'stat --format', especially, since we don't support any format modifiers for getting at the additional information. We're already incompatible with BSD stat(1) format modifiers, and there is no standard for stat(1), so I wasn't too worried about changing the meaning of existing modifiers rather than burning new letters just for the nanosecond portions. And now that POSIX 2008 requires nanonsecond resolution in stat(2), you could argue that we should always be displaying it. NEWS | 3 +++ src/stat.c | 32 +++++++++++++++++--------------- tests/touch/60-seconds | 2 +- 3 files changed, 21 insertions(+), 16 deletions(-) diff --git a/NEWS b/NEWS index 0c7cc38..690f693 100644 --- a/NEWS +++ b/NEWS @@ -40,6 +40,9 @@ GNU coreutils NEWS -*- outline -*- for a file. It also accepts the %w and %W format directives for outputting the birth time of a file, if one is available. + stat now outputs the full timestamp resolution for the %X, %Y, and + %Z format directives. + ** Changes in behavior df now consistently prints the device name for a bind mounted file, diff --git a/src/stat.c b/src/stat.c index c465e77..fb9b2c2 100644 --- a/src/stat.c +++ b/src/stat.c @@ -461,6 +461,19 @@ human_time (struct timespec t) return str; } +static char * ATTRIBUTE_WARN_UNUSED_RESULT +epoch_time (struct timespec t) +{ + static char str[INT_STRLEN_BOUND (time_t) + sizeof ".NNNNNNNNN"]; + if (TYPE_SIGNED (time_t)) + sprintf (str, "%" PRIdMAX ".%09lu", (intmax_t) t.tv_sec, + (unsigned long) t.tv_nsec); + else + sprintf (str, "%" PRIuMAX ".%09lu", (uintmax_t) t.tv_sec, + (unsigned long) t.tv_nsec); + return str; +} + static void out_string (char *pformat, size_t prefix_len, char const *arg) { @@ -802,38 +815,27 @@ print_stat (char *pformat, size_t prefix_len, char m, struct timespec t = get_stat_birthtime (statbuf); if (t.tv_nsec < 0) out_string (pformat, prefix_len, "-"); - else if (TYPE_SIGNED (time_t)) - out_int (pformat, prefix_len, t.tv_sec); else - out_uint (pformat, prefix_len, t.tv_sec); + out_string (pformat, prefix_len, epoch_time (t)); } break; case 'x': out_string (pformat, prefix_len, human_time (get_stat_atime (statbuf))); break; case 'X': - if (TYPE_SIGNED (time_t)) - out_int (pformat, prefix_len, statbuf->st_atime); - else - out_uint (pformat, prefix_len, statbuf->st_atime); + out_string (pformat, prefix_len, epoch_time (get_stat_atime (statbuf))); break; case 'y': out_string (pformat, prefix_len, human_time (get_stat_mtime (statbuf))); break; case 'Y': - if (TYPE_SIGNED (time_t)) - out_int (pformat, prefix_len, statbuf->st_mtime); - else - out_uint (pformat, prefix_len, statbuf->st_mtime); + out_string (pformat, prefix_len, epoch_time (get_stat_mtime (statbuf))); break; case 'z': out_string (pformat, prefix_len, human_time (get_stat_ctime (statbuf))); break; case 'Z': - if (TYPE_SIGNED (time_t)) - out_int (pformat, prefix_len, statbuf->st_ctime); - else - out_uint (pformat, prefix_len, statbuf->st_ctime); + out_string (pformat, prefix_len, epoch_time (get_stat_ctime (statbuf))); break; case 'C': fail |= out_file_context (filename, pformat, prefix_len); diff --git a/tests/touch/60-seconds b/tests/touch/60-seconds index f858a30..f98f0c5 100755 --- a/tests/touch/60-seconds +++ b/tests/touch/60-seconds @@ -23,7 +23,7 @@ fi . $srcdir/test-lib.sh -echo 60 > exp || framework_failure +echo 60.000000000 > exp || framework_failure # Before coreutils-7.7, this would fail, complaining of -- 1.7.2.3