I installed the attached series of patches into GNU coreutils. The main user-visible change is to add a new --resolution option to GNU 'date', which queries clock_getres to print the clock resolution. 'date' and similar programs now also support the %-N format, which prints subsecond fractions just wide enough to cover the resolution.
From 6812e6baa7882ed064d274ead8dcd84b556603ce Mon Sep 17 00:00:00 2001
From: Paul Eggert <egg...@cs.ucla.edu>
Date: Fri, 31 Dec 2021 00:45:03 -0800
Subject: [PATCH 1/5] build: port to AIX 7.1

This fixes a porting bug introduced in
2019-08-12T03:29:00Z!br...@clisp.org.
Problem discovered on AIX 7.1.
* src/local.mk (LDADD): Add $(LIB_MBRTOWC), since pretty much
every command uses quotearg or mbrtowc or whatever.
(src_sort_LDADD): Add $(LIBPMULTITHREAD) and
$(LIB_PTHREAD_SIGMASK) instead of $(LIBTHREAD).
---
 NEWS         |  3 +++
 src/local.mk | 11 ++++++++---
 2 files changed, 11 insertions(+), 3 deletions(-)

diff --git a/NEWS b/NEWS
index 72453dc4b..b9d36c724 100644
--- a/NEWS
+++ b/NEWS
@@ -29,6 +29,9 @@ GNU coreutils NEWS                                    -*- outline -*-
   for B when A is a directory, possibly inflooping.
   [bug introduced in coreutils-6.3]
 
+  AIX builds no longer fail because some library functions are not found.
+  [bug introduced in coreutils-8.32]
+
 ** Changes in behavior
 
   timeout --foreground --kill-after=... will now exit with status 137
diff --git a/src/local.mk b/src/local.mk
index 0c8b65d39..d668bfc30 100644
--- a/src/local.mk
+++ b/src/local.mk
@@ -90,7 +90,9 @@ remove_ldadd =
 # must precede $(LIBINTL) in order to ensure we use GNU getopt.
 # But libcoreutils.a must also follow $(LIBINTL), since libintl uses
 # replacement functions defined in libcoreutils.a.
-LDADD = src/libver.a lib/libcoreutils.a $(LIBINTL) lib/libcoreutils.a
+# Similarly for $(LIB_MBRTOWC).
+LDADD = src/libver.a lib/libcoreutils.a $(LIBINTL) $(LIB_MBRTOWC) \
+  lib/libcoreutils.a
 
 # First, list all programs, to make listing per-program libraries easier.
 # See [ below.
@@ -317,8 +319,11 @@ src_uname_LDADD += $(GETHOSTNAME_LIB)
 # for strsignal
 src_kill_LDADD += $(LIBTHREAD)
 
-# for pthread
-src_sort_LDADD += $(LIB_PTHREAD)
+# for pthread-cond, pthread-mutex, pthread-thread
+src_sort_LDADD += $(LIBPMULTITHREAD)
+
+# for pthread_sigmask
+src_sort_LDADD += $(LIB_PTHREAD_SIGMASK)
 
 # Get the release year from lib/version-etc.c.
 RELEASE_YEAR = \
-- 
2.32.0

From 1011b88594a9d6e940d51ce5b9443571d6ebef3b Mon Sep 17 00:00:00 2001
From: Paul Eggert <egg...@cs.ucla.edu>
Date: Fri, 31 Dec 2021 00:45:03 -0800
Subject: [PATCH 2/5] doc: Document , vs . in date --rfc-3339=ns

---
 doc/coreutils.texi | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/doc/coreutils.texi b/doc/coreutils.texi
index f7ce1654b..49d2afbe2 100644
--- a/doc/coreutils.texi
+++ b/doc/coreutils.texi
@@ -16458,7 +16458,8 @@ For compatibility with older versions of @command{date},
 Display the date using a format specified by
 @uref{https://tools.ietf.org/search/rfc3339, Internet
 RFC 3339}.  This is like @option{--iso-8601}, except that a space rather
-than a @samp{T} separates dates from times.
+than a @samp{T} separates dates from times, and a period rather than
+a comma separates seconds from subseconds.
 @dateParseNote
 
 The argument @var{timespec} specifies how much of the time to include.
-- 
2.32.0

From 64b65cf4b8295cb35f4aa7431f91fccadb327ef6 Mon Sep 17 00:00:00 2001
From: Paul Eggert <egg...@cs.ucla.edu>
Date: Fri, 31 Dec 2021 00:45:03 -0800
Subject: [PATCH 3/5] build: update gnulib submodule to latest

---
 gnulib | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/gnulib b/gnulib
index 8220e0f0b..972be3cee 160000
--- a/gnulib
+++ b/gnulib
@@ -1 +1 @@
-Subproject commit 8220e0f0b5f46ff61e1d19f8a1614508fa162abd
+Subproject commit 972be3cee24d6e9b84de7250c5bc7f078ac1a19d
-- 
2.32.0

From 0cd39a246af30d141be2676f1b4c1fd6616dfec5 Mon Sep 17 00:00:00 2001
From: Paul Eggert <egg...@cs.ucla.edu>
Date: Fri, 31 Dec 2021 00:45:03 -0800
Subject: [PATCH 4/5] date: %-N now means suppress extra digits

* NEWS, doc/coreutils.texi: Mention this.
* bootstrap.conf (gnulib_modules): Add gettime-res.
* src/date.c (res_width, adjust_resolution): New functions.
(main): Adjust %-N to be %9N, or whatever, before using it.
---
 NEWS               |  4 ++++
 bootstrap.conf     |  1 +
 doc/coreutils.texi |  6 ++++++
 src/date.c         | 40 ++++++++++++++++++++++++++++++++++++++--
 4 files changed, 49 insertions(+), 2 deletions(-)

diff --git a/NEWS b/NEWS
index b9d36c724..79320820f 100644
--- a/NEWS
+++ b/NEWS
@@ -34,6 +34,10 @@ GNU coreutils NEWS                                    -*- outline -*-
 
 ** Changes in behavior
 
+  date +'%-N' now suppresses excess trailing digits, instead of always
+  padding them with zeros to 9 digits.  It uses clock_getres and
+  clock_gettime to infer the clock resolution.
+
   timeout --foreground --kill-after=... will now exit with status 137
   if the kill signal was sent, which is consistent with the behavior
   when the --foreground option is not specified.  This allows users to
diff --git a/bootstrap.conf b/bootstrap.conf
index c2f74f406..afa2cdcb9 100644
--- a/bootstrap.conf
+++ b/bootstrap.conf
@@ -119,6 +119,7 @@ gnulib_modules="
   getpass-gnu
   gettext-h
   gettime
+  gettime-res
   getugroups
   getusershell
   git-version-gen
diff --git a/doc/coreutils.texi b/doc/coreutils.texi
index 49d2afbe2..aa970da6c 100644
--- a/doc/coreutils.texi
+++ b/doc/coreutils.texi
@@ -16227,6 +16227,12 @@ The following optional flags can appear after the @samp{%}:
 (hyphen) Do not pad the field; useful if the output is intended for
 human consumption.
 This is a GNU extension.
+As a special case, @samp{%-N} outputs only enough trailing digits to
+not lose information, assuming that the timestamp's resolution is the
+same as the current hardware clock.  For example, if the hardware
+clock resolution is 1 microsecond, @samp{%s.%-N} outputs something
+like @samp{1640890100.395710}.
+
 @item _
 (underscore) Pad with spaces; useful if you need a fixed
 number of characters in the output, but zeros are too distracting.
diff --git a/src/date.c b/src/date.c
index 4a7a4e243..b0a53ba6c 100644
--- a/src/date.c
+++ b/src/date.c
@@ -281,6 +281,39 @@ Show the local time for 9AM next Friday on the west coast of the US\n\
   exit (status);
 }
 
+/* Yield the number of decimal digits needed to output a time with the
+   nanosecond resolution RES, without losing information.  */
+
+static int
+res_width (long int res)
+{
+  int i = 9;
+  for (long long int r = 1; (r *= 10) <= res; )
+    i--;
+  return i;
+}
+
+/* Return a newly allocated copy of FORMAT with each "%-N" adjusted to
+   be "%9N", "%6N", or whatever other resolution is appropriate for
+   the current platform.  If no "%-N" appears, return NULL.  */
+
+static char *
+adjust_resolution (char const *format)
+{
+  char *copy = NULL;
+
+  for (char const *f = format; *f; f++)
+    if (f[0] == '%' && f[1] == '-' && f[2] == 'N')
+      {
+        if (!copy)
+          copy = xstrdup (format);
+        copy[f + 1 - format] = '0' + res_width (gettime_res ());
+        f += 2;
+      }
+
+  return copy;
+}
+
 /* Parse each line in INPUT_FILENAME as with --date and display each
    resulting time and date.  If the file cannot be opened, tell why
    then exit.  Issue a diagnostic for any lines that cannot be parsed.
@@ -505,11 +538,13 @@ main (int argc, char **argv)
         }
     }
 
+  char *format_copy = adjust_resolution (format);
+  char const *format_res = format_copy ? format_copy : format;
   char const *tzstring = getenv ("TZ");
   timezone_t tz = tzalloc (tzstring);
 
   if (batch_file != NULL)
-    ok = batch_convert (batch_file, format, tz, tzstring);
+    ok = batch_convert (batch_file, format_res, tz, tzstring);
   else
     {
       bool valid_date = true;
@@ -568,10 +603,11 @@ main (int argc, char **argv)
             }
         }
 
-      ok &= show_date (format, when, tz);
+      ok &= show_date (format_res, when, tz);
     }
 
   IF_LINT (tzfree (tz));
+  IF_LINT (free (format_copy));
 
   return ok ? EXIT_SUCCESS : EXIT_FAILURE;
 }
-- 
2.32.0

From 840ae54cf5e7b1bfa5755f7bb70c1b671ec36190 Mon Sep 17 00:00:00 2001
From: Paul Eggert <egg...@cs.ucla.edu>
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

Reply via email to