diff options
author | Rob Landley <rob@landley.net> | 2017-05-19 12:35:36 -0500 |
---|---|---|
committer | Rob Landley <rob@landley.net> | 2017-05-19 12:35:36 -0500 |
commit | d852ec18900ef635a38f99ed769a636f15af72c6 (patch) | |
tree | 48c34a2717618e39f494a8e7fe11786c71b83144 | |
parent | 57605d2b481a87af4ba444761ece592d441950b1 (diff) | |
download | toybox-d852ec18900ef635a38f99ed769a636f15af72c6.tar.gz |
Implement date %N, loosely inspired by Elliott Hughes's patch.
I didn't implement %37N's ability to insert zeroes, so removed those
two tests. If you really need it, I can add the divide loop back.
-rw-r--r-- | tests/date.test | 11 | ||||
-rw-r--r-- | toys/posix/date.c | 51 |
2 files changed, 50 insertions, 12 deletions
diff --git a/tests/date.test b/tests/date.test index d59d7fcf..be80d451 100644 --- a/tests/date.test +++ b/tests/date.test @@ -21,3 +21,14 @@ 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 "%%N" "touch -d 2012-01-23T12:34:56.123456789 f && date -r f +%Y%m%d-%H%M%S.%%N" "20120123-123456.%N\n" "" "" +testing "trailing %" "touch -d 2012-01-23T12:34:56.123456789 f && date -r f +%Y%m%d-%H%M%S.%" "20120123-123456.%\n" "" "" +testing "just %" "touch -d 2012-01-23T12:34:56.123456789 f && date -r f +%" "%\n" "" "" +rm -f f diff --git a/toys/posix/date.c b/toys/posix/date.c index e77ff3a5..56eb02bd 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) @@ -35,6 +35,7 @@ config DATE %a short weekday name %A weekday name %u day of week (1-7, 1=mon) %b short month name %B month name %Z timezone name %j day of year (001-366) %d day of month (01-31) %e day of month ( 1-31) + %N nanosec (output only) %U Week of year (0-53 start sunday) %W Week of year (0-53 start monday) %V Week of year (1-53 start monday, week < 4 days not part of this year) @@ -123,12 +124,41 @@ 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); } +// Print strftime plus %N escape(s). note: modifies fmt for %N +static void puts_time(char *fmt, struct tm *tm) +{ + char *s, *snap; + long width = width; + + for (s = fmt;;s++) { + + // Find next %N or end + if (*(snap = s) == '%') { + width = isdigit(*++s) ? *(s++)-'0' : 9; + if (*s && *s != 'N') continue; + } else if (*s) continue; + + // Don't modify input string if no %N (default format is constant string). + if (*s) *snap = 0; + if (!strftime(toybuf, sizeof(toybuf)-10, fmt, tm)) + perror_exit("bad format '%s'", fmt); + if (*s) { + snap = toybuf+strlen(toybuf); + sprintf(snap, "%09u", TT.nano); + snap[width] = 0; + } + fputs(toybuf, stdout); + if (!*s || !*(fmt = s+1)) break; + } + xputc('\n'); +} + void date_main(void) { char *setdate = *toys.optargs, *format_string = "%a %b %e %H:%M:%S %Z %Y"; @@ -143,16 +173,16 @@ void date_main(void) if (!s || *s) goto bad_showdate; } else if (parse_default(TT.showdate, &tm)) goto bad_showdate; } else { - time_t now; + struct timespec ts; + struct stat st; 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); + TT.nano = ts.tv_nsec; } // Fall through if no arguments @@ -194,10 +224,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); return; bad_showdate: |