From 840ae54cf5e7b1bfa5755f7bb70c1b671ec36190 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Fri, 31 Dec 2021 00:45:03 -0800 Subject: [PATCH 5/5] date: new option --resolution * NEWS, doc/coreutils.texi (Options for date): Mention this. * src/date.c (RESOLUTION_OPTION): New constant. (DEBUG_DATE_PARSING_OPTION): Rename from DEBUG_DATE_PARSING. All uses changed. (long_options, usage, main): Support --resolution. --- NEWS | 2 ++ doc/coreutils.texi | 13 +++++++++++++ src/date.c | 40 +++++++++++++++++++++++++++++----------- 3 files changed, 44 insertions(+), 11 deletions(-) diff --git a/NEWS b/NEWS index 79320820f..7ce6a698f 100644 --- a/NEWS +++ b/NEWS @@ -50,6 +50,8 @@ GNU coreutils NEWS -*- outline -*- not already exist, and cp is preserving mode and timestamps (e.g., 'cp -p', 'cp -a'). + The new 'date' option --resolution outputs the timestamp resolution. + sort --debug now diagnoses issues with --field-separator characters that conflict with characters possibly used in numbers. diff --git a/doc/coreutils.texi b/doc/coreutils.texi index aa970da6c..4cd3d11b6 100644 --- a/doc/coreutils.texi +++ b/doc/coreutils.texi @@ -16436,6 +16436,19 @@ for the @option{--date} (@option{-d}) and @option{--file} Display the date and time of the last modification of @var{file}, instead of the current date and time. +@item --resolution +@opindex --resolution +Display the timestamp resolution instead of the time. +Current clock timestamps that are output by @command{date} +are integer multiples of the timestamp resolution. +With this option, the format defaults to @samp{%s.%N}. +For example, if the clock resolution is 1 millsecond, +the output is: + +@example +0.001000000 +@end example + @item -R @itemx --rfc-email @opindex -R diff --git a/src/date.c b/src/date.c index b0a53ba6c..b92c8ae5c 100644 --- a/src/date.c +++ b/src/date.c @@ -79,8 +79,9 @@ static char const rfc_email_format[] = "%a, %d %b %Y %H:%M:%S %z"; non-character as a pseudo short option, starting with CHAR_MAX + 1. */ enum { - RFC_3339_OPTION = CHAR_MAX + 1, - DEBUG_DATE_PARSING + DEBUG_DATE_PARSING_OPTION = CHAR_MAX + 1, + RESOLUTION_OPTION, + RFC_3339_OPTION }; static char const short_options[] = "d:f:I::r:Rs:u"; @@ -88,10 +89,11 @@ static char const short_options[] = "d:f:I::r:Rs:u"; static struct option const long_options[] = { {"date", required_argument, NULL, 'd'}, - {"debug", no_argument, NULL, DEBUG_DATE_PARSING}, + {"debug", no_argument, NULL, DEBUG_DATE_PARSING_OPTION}, {"file", required_argument, NULL, 'f'}, {"iso-8601", optional_argument, NULL, 'I'}, {"reference", required_argument, NULL, 'r'}, + {"resolution", no_argument, NULL, RESOLUTION_OPTION}, {"rfc-email", no_argument, NULL, 'R'}, {"rfc-822", no_argument, NULL, 'R'}, {"rfc-2822", no_argument, NULL, 'R'}, @@ -154,6 +156,10 @@ Display the current time in the given FORMAT, or set the system date.\n\ 'hours', 'minutes', 'seconds', or 'ns'\n\ for date and time to the indicated precision.\n\ Example: 2006-08-14T02:34:56-06:00\n\ +"), stdout); + fputs (_("\ + --resolution output the available resolution of timestamps\n\ + Example: 0.000000001\n\ "), stdout); fputs (_("\ -R, --rfc-email output date and time in RFC 5322 format.\n\ @@ -386,11 +392,11 @@ main (int argc, char **argv) struct timespec when; bool set_date = false; char const *format = NULL; + bool get_resolution = false; char *batch_file = NULL; char *reference = NULL; struct stat refstats; bool ok; - int option_specified_date; initialize_main (&argc, &argv); set_program_name (argv[0]); @@ -410,12 +416,15 @@ main (int argc, char **argv) case 'd': datestr = optarg; break; - case DEBUG_DATE_PARSING: + case DEBUG_DATE_PARSING_OPTION: parse_datetime_flags |= PARSE_DATETIME_DEBUG; break; case 'f': batch_file = optarg; break; + case RESOLUTION_OPTION: + get_resolution = true; + break; case RFC_3339_OPTION: { static char const rfc_3339_format[][32] = @@ -479,9 +488,8 @@ main (int argc, char **argv) } } - option_specified_date = ((datestr ? 1 : 0) - + (batch_file ? 1 : 0) - + (reference ? 1 : 0)); + int option_specified_date = (!!datestr + !!batch_file + !!reference + + get_resolution); if (option_specified_date > 1) { @@ -524,9 +532,12 @@ main (int argc, char **argv) if (!format) { - format = DATE_FMT_LANGINFO (); - if (! *format) + if (get_resolution) + format = "%s.%N"; + else { + format = DATE_FMT_LANGINFO (); + /* Do not wrap the following literal format string with _(...). For example, suppose LC_ALL is unset, LC_TIME=POSIX, and LANG="ko_KR". In that case, POSIX says that LC_TIME @@ -534,7 +545,8 @@ main (int argc, char **argv) written by date, which means "date" must generate output using the POSIX locale; but adding _() would cause "date" to use a Korean translation of the format. */ - format = "%a %b %e %H:%M:%S %Z %Y"; + if (! *format) + format = "%a %b %e %H:%M:%S %Z %Y"; } } @@ -579,6 +591,12 @@ main (int argc, char **argv) die (EXIT_FAILURE, errno, "%s", quotef (reference)); when = get_stat_mtime (&refstats); } + else if (get_resolution) + { + long int res = gettime_res (); + when.tv_sec = res / TIMESPEC_HZ; + when.tv_nsec = res % TIMESPEC_HZ; + } else { if (set_datestr) -- 2.32.0