Used by the toybox touch test suite (and thus necessary to pass the toybox
tests on a toybox-only system).
---
 tests/date.test   | 10 ++++++++++
 toys/posix/date.c | 50 +++++++++++++++++++++++++++++++++++++++-----------
 2 files changed, 49 insertions(+), 11 deletions(-)
From c998db70bb5a47f2290d3c5c08df398528ea4906 Mon Sep 17 00:00:00 2001
From: Elliott Hughes <e...@google.com>
Date: Sat, 15 Apr 2017 11:13:31 -0700
Subject: [PATCH] Support the %N coreutils/busybox extension to date.

Used by the toybox touch test suite (and thus necessary to pass the toybox
tests on a toybox-only system).
---
 tests/date.test   | 10 ++++++++++
 toys/posix/date.c | 50 +++++++++++++++++++++++++++++++++++++++-----------
 2 files changed, 49 insertions(+), 11 deletions(-)

diff --git a/tests/date.test b/tests/date.test
index d59d7fc..f222a0f 100644
--- a/tests/date.test
+++ b/tests/date.test
@@ -21,3 +21,13 @@ testing "-d 111014312015.30" "TZ=UTC date -d 111014312015.30 2>&1" "Sun Nov 10 1
 # Accidentally given a Unix time, we should trivially reject that.
 testing "Unix time missing @" "TZ=UTC date 1438053157 2>/dev/null || echo no" \
   "no\n" "" ""
+
+# Test the %N extension to srtftime(3) format strings.
+testing "%N" "touch -d 2012-01-23T12:34:56.123456789 f && date -r f +%Y%m%d-%H%M%S.%N" "20120123-123456.123456789\n" "" ""
+testing "%1N" "touch -d 2012-01-23T12:34:56.123456789 f && date -r f +%Y%m%d-%H%M%S.%1N" "20120123-123456.1\n" "" ""
+testing "%2N" "touch -d 2012-01-23T12:34:56.123456789 f && date -r f +%Y%m%d-%H%M%S.%2N" "20120123-123456.12\n" "" ""
+testing "%8N" "touch -d 2012-01-23T12:34:56.123456789 f && date -r f +%Y%m%d-%H%M%S.%8N" "20120123-123456.12345678\n" "" ""
+testing "%9N" "touch -d 2012-01-23T12:34:56.123456789 f && date -r f +%Y%m%d-%H%M%S.%9N" "20120123-123456.123456789\n" "" ""
+testing "%10N" "touch -d 2012-01-23T12:34:56.123456789 f && date -r f +%Y%m%d-%H%M%S.%10N" "20120123-123456.0123456789\n" "" ""
+testing "%20N" "touch -d 2012-01-23T12:34:56.123456789 f && date -r f +%Y%m%d-%H%M%S.%20N" "20120123-123456.00000000000123456789\n" "" ""
+rm -f f
diff --git a/toys/posix/date.c b/toys/posix/date.c
index e77ff3a..c095f5d 100644
--- a/toys/posix/date.c
+++ b/toys/posix/date.c
@@ -26,7 +26,7 @@ config DATE
     -r	Use modification time of FILE instead of current date
     -u	Use UTC instead of current timezone
 
-    +FORMAT specifies display format string using these escapes:
+    +FORMAT specifies display format string using strftime(3) syntax:
 
     %% literal %             %n newline              %t tab
     %S seconds (00-60)       %M minute (00-59)       %m month (01-12)
@@ -41,6 +41,8 @@ config DATE
 
     %D = "%m/%d/%y"    %r = "%I : %M : %S %p"   %T = "%H:%M:%S"   %h = "%b"
     %x locale date     %X locale time           %c locale date/time
+
+    As an extension, %N nanoseconds is also supported.
 */
 
 #define FOR_date
@@ -123,17 +125,48 @@ static int parse_default(char *str, struct tm *tm)
   return *str;
 }
 
-void check_range(int a, int low, int high)
+static void check_range(int a, int low, int high)
 {
   if (a<low) error_exit("%d<%d", a, low);
   if (a>high) error_exit("%d>%d", a, high);
 }
 
+static void puts_time(char *fmt, struct tm *tm, long ns)
+{
+  char *s;
+
+  // Find any %Ns and format them manually.
+  fmt = xstrdup(fmt);
+  for (s = fmt; s; s = strchr(s, '%')) {
+    int width, prec, i;
+    char *e = ++s, *new_fmt;
+
+    e += strspn(s, "0123456789");
+    if (*e++ != 'N') continue;
+    width = prec = xstrtol(s, NULL, 10);
+    if (width == 0) width = prec = 9;
+    else if (width < 9) for (i = width; i < 9; ++i) ns /= 10;
+
+    new_fmt = xmprintf("%.*s%*.*ld%s", (int)(s-1-fmt), fmt, width, prec, ns, e);
+    free(fmt);
+    fmt = new_fmt;
+  }
+
+  // Let strftime handle all the standard stuff.
+  if (!strftime(toybuf, sizeof(toybuf), fmt, tm))
+    perror_exit("bad format '%s'", fmt);
+
+  puts(toybuf);
+  free(fmt);
+}
+
 void date_main(void)
 {
   char *setdate = *toys.optargs, *format_string = "%a %b %e %H:%M:%S %Z %Y";
+  struct timespec ts;
   struct tm tm;
 
+  memset(&ts, 0, sizeof(struct timespec));
   memset(&tm, 0, sizeof(struct tm));
 
   if (TT.showdate) {
@@ -143,16 +176,14 @@ void date_main(void)
       if (!s || *s) goto bad_showdate;
     } else if (parse_default(TT.showdate, &tm)) goto bad_showdate;
   } else {
-    time_t now;
-
     if (TT.file) {
       struct stat st;
 
       xstat(TT.file, &st);
-      now = st.st_mtim.tv_sec;
-    } else now = time(0);
+      ts = st.st_mtim;
+    } else clock_gettime(CLOCK_REALTIME, &ts);
 
-    ((toys.optflags & FLAG_u) ? gmtime_r : localtime_r)(&now, &tm);
+    ((toys.optflags & FLAG_u) ? gmtime_r : localtime_r)(&ts.tv_sec, &tm);
   }
 
   // Fall through if no arguments
@@ -194,10 +225,7 @@ void date_main(void)
     if (settimeofday(&tv, NULL) < 0) perror_msg("cannot set date");
   }
 
-  if (!strftime(toybuf, sizeof(toybuf), format_string, &tm))
-    perror_exit("bad format '%s'", format_string);
-  puts(toybuf);
-
+  puts_time(format_string, &tm, ts.tv_nsec);
   return;
 
 bad_showdate:
-- 
2.12.2.762.g0e3151a226-goog

_______________________________________________
Toybox mailing list
Toybox@lists.landley.net
http://lists.landley.net/listinfo.cgi/toybox-landley.net

Reply via email to