Zsh Mailing List Archive
Messages sorted by:
Reverse Date,
Date,
Thread,
Author
Re: zsh/stat: output atime/mtime/ctime with nanoseconds
- X-seq: zsh-workers 43075
- From: dana <dana@xxxxxxx>
- To: Oliver Kiddle <okiddle@xxxxxxxxxxx>
- Subject: Re: zsh/stat: output atime/mtime/ctime with nanoseconds
- Date: Wed, 20 Jun 2018 00:12:31 -0500
- Cc: zsh-workers@xxxxxxx
- Dkim-signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=dana-is.20150623.gappssmtp.com; s=20150623; h=mime-version:subject:from:in-reply-to:date:cc :content-transfer-encoding:message-id:references:to; bh=ZhkQCCNLimcOpGozjpNnkNmVjJyRgaAKoMX/X8tsE/8=; b=cn9R+WApTHcc1iBeKM36K1za9m16Ml+4fI6IZJhxQwQN9OjsZQGEyip29OMNh0GtSv LFxPzk8w3WsIJfhnrwY22lte+xLYW88ToX6y3Ct+yq6qDoIalX0Oc0lXPDn5FboeVxAl CIDrXQUIlYDig9PelJEZg4P5BJStzVuPhzIPYcyKAoCCVSU3HSZOtczzTqf4u7XDkVpG ykejEI4JLre5N9bgQOnRcf5uZhlOBECGURBr22uDXzr5ILiPvZSoXvcN2+GZKSSMq5nf 5PV92Lv+CQFkMzOaE106L0aENmgCrk+NljYbQ43hWYYarsY5iiBw4FkD79Xyo+Bdvv67 BUfQ==
- In-reply-to: <16617.1529435823@thecus>
- List-help: <mailto:zsh-workers-help@zsh.org>
- List-id: Zsh Workers List <zsh-workers.zsh.org>
- List-post: <mailto:zsh-workers@zsh.org>
- List-unsubscribe: <mailto:zsh-workers-unsubscribe@zsh.org>
- Mailing-list: contact zsh-workers-help@xxxxxxx; run by ezmlm
- References: <20180619141851.GA16101@zira.vinc17.org> <16617.1529435823@thecus>
On 19 Jun 2018, at 14:17, Oliver Kiddle <okiddle@xxxxxxxxxxx> wrote:
>Checking back, it seems the patch in workers/24059 was never applied.
How is this? Building on the earlier patch, it:
* Adds a zgettime() function to conveniently get nanosecond-precision clock
time, or at least something approximating it (Peter had independently added ns
precision to zsh/datetime between then and now, so i figured it was best to
centralize that functionality)
* Updates ztrftime() to support %9. and %N
* Updates prompt expansion to format times with nanoseconds
* Updates zsh/datetime to use zgettime()
* Updates zsh/stat to format times with nanoseconds
* Updates documentation and tests
I'm not sure about the error-handling / fall-back stuff in zgettime(). Is an
error message necessary? I put one in because pws had one, but he wasn't falling
back to gettimeofday() like i am. Also the ret++/ret-- stuff may be a bit
strange; i couldn't think of anything cleaner.
One remaining (not new) issue is the fact that the strftime built-in doesn't
support sub-second times. That might not be feasible for `strftime -r`, but the
regular one could accept an optional third operand maybe?
dana
diff --git a/configure.ac b/configure.ac
index 7644ebe52..53c30c2cf 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1113,6 +1113,14 @@ zsh_TYPE_EXISTS([
#endif
], struct timezone)
+dnl Check for struct timespec since POSIX only gained it in 2008
+zsh_TYPE_EXISTS([
+#define _GNU_SOURCE 1
+#ifdef HAVE_SYS_TIME_H
+# include <sys/time.h>
+#endif
+], struct timespec)
+
dnl Check for utmp structures, for watch
zsh_TYPE_EXISTS([
#ifdef HAVE_SYS_TYPES_H
diff --git a/Src/zsh_system.h b/Src/zsh_system.h
index 5339b496f..8289ee97c 100644
--- a/Src/zsh_system.h
+++ b/Src/zsh_system.h
@@ -250,6 +250,14 @@ struct timezone {
};
#endif
+/* Used to provide compatibility with clock_gettime() */
+#if !defined(HAVE_STRUCT_TIMESPEC) && !defined(ZSH_OOT_MODULE)
+struct timespec {
+ time_t tv_sec;
+ long tv_nsec;
+};
+#endif
+
/* There's more than one non-standard way to get at this data */
#if !defined(HAVE_STRUCT_DIRENT_D_INO) && defined(HAVE_STRUCT_DIRENT_D_STAT)
# define d_ino d_stat.st_ino
diff --git a/Src/compat.c b/Src/compat.c
index a130d9264..7b5c4411c 100644
--- a/Src/compat.c
+++ b/Src/compat.c
@@ -94,6 +94,39 @@ gettimeofday(struct timeval *tv, struct timezone *tz)
#endif
+/* Provide clock time with nanoseconds */
+
+/**/
+mod_export int
+zgettime(struct timespec *ts)
+{
+ int ret = -1;
+
+#ifdef HAVE_CLOCK_GETTIME
+ struct timespec dts;
+ if (clock_gettime(CLOCK_REALTIME, &dts) < 0) {
+ zwarn("unable to retrieve time: %e", errno);
+ ret--;
+ } else {
+ ret++;
+ ts->tv_sec = (time_t) dts.tv_sec;
+ ts->tv_nsec = (long) dts.tv_nsec;
+ }
+#endif
+
+ if (ret) {
+ struct timeval dtv;
+ struct timezone dtz;
+ gettimeofday(&dtv, &dtz);
+ ret++;
+ ts->tv_sec = (time_t) dtv.tv_sec;
+ ts->tv_nsec = (long) dtv.tv_usec * 1000;
+ }
+
+ return ret;
+}
+
+
/* compute the difference between two calendar times */
/**/
diff --git a/Src/utils.c b/Src/utils.c
index b41851700..ee2ad207f 100644
--- a/Src/utils.c
+++ b/Src/utils.c
@@ -3224,7 +3224,7 @@ ztrftimebuf(int *bufsizeptr, int decr)
/**/
mod_export int
-ztrftime(char *buf, int bufsize, char *fmt, struct tm *tm, long usec)
+ztrftime(char *buf, int bufsize, char *fmt, struct tm *tm, long nsec)
{
int hr12;
#ifdef HAVE_STRFTIME
@@ -3299,15 +3299,15 @@ morefmt:
case '.':
if (ztrftimebuf(&bufsize, digs))
return -1;
- if (digs > 6)
- digs = 6;
- if (digs < 6) {
+ if (digs > 9)
+ digs = 9;
+ if (digs < 9) {
int trunc;
- for (trunc = 5 - digs; trunc; trunc--)
- usec /= 10;
- usec = (usec + 5) / 10;
+ for (trunc = 8 - digs; trunc; trunc--)
+ nsec /= 10;
+ nsec = (nsec + 8) / 10;
}
- sprintf(buf, "%0*ld", digs, usec);
+ sprintf(buf, "%0*ld", digs, nsec);
buf += digs;
break;
case '\0':
@@ -3369,6 +3369,12 @@ morefmt:
*buf++ = '0' + tm->tm_min / 10;
*buf++ = '0' + tm->tm_min % 10;
break;
+ case 'N':
+ if (ztrftimebuf(&bufsize, 9))
+ return -1;
+ sprintf(buf, "%09ld", nsec);
+ buf += 9;
+ break;
case 'S':
if (tm->tm_sec > 9 || !strip)
*buf++ = '0' + tm->tm_sec / 10;
diff --git a/Src/prompt.c b/Src/prompt.c
index 95da52559..959ed8e3d 100644
--- a/Src/prompt.c
+++ b/Src/prompt.c
@@ -273,8 +273,7 @@ putpromptchar(int doprint, int endchar, unsigned int *txtchangep)
char *ss, *hostnam;
int t0, arg, test, sep, j, numjobs, len;
struct tm *tm;
- struct timezone dummy_tz;
- struct timeval tv;
+ struct timespec ts;
time_t timet;
Nameddir nd;
@@ -664,8 +663,8 @@ putpromptchar(int doprint, int endchar, unsigned int *txtchangep)
tmfmt = "%l:%M%p";
break;
}
- gettimeofday(&tv, &dummy_tz);
- tm = localtime(&tv.tv_sec);
+ zgettime(&ts);
+ tm = localtime(&ts.tv_sec);
/*
* Hack because strftime won't say how
* much space it actually needs. Try to add it
@@ -675,7 +674,7 @@ putpromptchar(int doprint, int endchar, unsigned int *txtchangep)
*/
for(j = 0, t0 = strlen(tmfmt)*8; j < 3; j++, t0*=2) {
addbufspc(t0);
- if ((len = ztrftime(bv->bp, t0, tmfmt, tm, tv.tv_usec))
+ if ((len = ztrftime(bv->bp, t0, tmfmt, tm, ts.tv_nsec))
>= 0)
break;
}
diff --git a/Src/Modules/datetime.c b/Src/Modules/datetime.c
index 6e9047bc5..be378b347 100644
--- a/Src/Modules/datetime.c
+++ b/Src/Modules/datetime.c
@@ -180,66 +180,30 @@ getcurrentsecs(UNUSED(Param pm))
}
static double
-getcurrentrealtime(Param pm)
+getcurrentrealtime(UNUSED(Param pm))
{
-#ifdef HAVE_CLOCK_GETTIME
struct timespec now;
-
- if (clock_gettime(CLOCK_REALTIME, &now) < 0) {
- zwarn("%s: unable to retrieve time: %e", pm->node.nam, errno);
- return (double)0.0;
- }
-
+ zgettime(&now);
return (double)now.tv_sec + (double)now.tv_nsec * 1e-9;
-#else
- struct timeval now;
- struct timezone dummy_tz;
-
- (void)pm;
- gettimeofday(&now, &dummy_tz);
-
- return (double)now.tv_sec + (double)now.tv_usec * 1e-6;
-#endif
}
static char **
-getcurrenttime(Param pm)
+getcurrenttime(UNUSED(Param pm))
{
char **arr;
char buf[DIGBUFSIZE];
-
-#ifdef HAVE_CLOCK_GETTIME
struct timespec now;
- if (clock_gettime(CLOCK_REALTIME, &now) < 0) {
- zwarn("%s: unable to retrieve time: %e", pm->node.nam, errno);
- return NULL;
- }
-
- arr = (char **)zhalloc(3 * sizeof(*arr));
- sprintf(buf, "%ld", (long)now.tv_sec);
- arr[0] = dupstring(buf);
- sprintf(buf, "%ld", now.tv_nsec);
- arr[1] = dupstring(buf);
- arr[2] = NULL;
-
- return arr;
-#else
- struct timeval now;
- struct timezone dummy_tz;
-
- (void)pm;
- gettimeofday(&now, &dummy_tz);
+ zgettime(&now);
arr = (char **)zhalloc(3 * sizeof(*arr));
sprintf(buf, "%ld", (long)now.tv_sec);
arr[0] = dupstring(buf);
- sprintf(buf, "%ld", (long)now.tv_usec * 1000);
+ sprintf(buf, "%ld", (long)now.tv_nsec);
arr[1] = dupstring(buf);
arr[2] = NULL;
return arr;
-#endif
}
static struct builtin bintab[] = {
diff --git a/Src/Modules/stat.c b/Src/Modules/stat.c
index 66baa1292..50a6a9bb2 100644
--- a/Src/Modules/stat.c
+++ b/Src/Modules/stat.c
@@ -188,7 +188,7 @@ static char *timefmt;
/**/
static void
-stattimeprint(time_t tim, char *outbuf, int flags)
+stattimeprint(time_t tim, long nsecs, char *outbuf, int flags)
{
if (flags & STF_RAW) {
sprintf(outbuf, "%ld", (unsigned long)tim);
@@ -199,7 +199,7 @@ stattimeprint(time_t tim, char *outbuf, int flags)
char *oend = outbuf + strlen(outbuf);
/* Where the heck does "40" come from? */
int len = ztrftime(oend, 40, timefmt, (flags & STF_GMT) ? gmtime(&tim) :
- localtime(&tim), 0L);
+ localtime(&tim), nsecs);
if (len > 0)
metafy(oend, len, META_NOALLOC);
if (flags & STF_RAW)
@@ -291,15 +291,27 @@ statprint(struct stat *sbuf, char *outbuf, char *fname, int iwhich, int flags)
break;
case ST_ATIM:
- stattimeprint(sbuf->st_atime, optr, flags);
+#ifdef GET_ST_ATIME_NSEC
+ stattimeprint(sbuf->st_atime, GET_ST_ATIME_NSEC(*sbuf), optr, flags);
+#else
+ stattimeprint(sbuf->st_atime, 0L, optr, flags);
+#endif
break;
case ST_MTIM:
- stattimeprint(sbuf->st_mtime, optr, flags);
+#ifdef GET_ST_MTIME_NSEC
+ stattimeprint(sbuf->st_mtime, GET_ST_MTIME_NSEC(*sbuf), optr, flags);
+#else
+ stattimeprint(sbuf->st_mtime, 0L, optr, flags);
+#endif
break;
case ST_CTIM:
- stattimeprint(sbuf->st_ctime, optr, flags);
+#ifdef GET_ST_CTIME_NSEC
+ stattimeprint(sbuf->st_ctime, GET_ST_CTIME_NSEC(*sbuf), optr, flags);
+#else
+ stattimeprint(sbuf->st_ctime, 0L, optr, flags);
+#endif
break;
case ST_BLKSIZE:
diff --git a/Test/D01prompt.ztst b/Test/D01prompt.ztst
index 11f18dc71..56b7c294a 100644
--- a/Test/D01prompt.ztst
+++ b/Test/D01prompt.ztst
@@ -108,6 +108,14 @@
if (( $date2[7,8] != $date3[1,2] )); then
print "Years do not agree in $date2, $date3"
fi
+ # These are somewhat questionable, but...
+ ns=( ${="$(print -P '%D{%9.} %D{%N}')"} )
+ if [[ $ns[1] != [0-9](#c9) ]] || [[ $ns[2] != [0-9](#c9) ]]; then
+ print "Nanosecond lengths/formats are not as expected in $ns[1], $ns[2]"
+ fi
+ if (( ($ns2[2] - $ns[1]) > 5000000 )); then
+ print "Nanoseconds differ too much in $ns[1], $ns[2]"
+ fi
0:Dates produced by prompt escapes
mkdir foo
diff --git a/Doc/Zsh/prompt.yo b/Doc/Zsh/prompt.yo
index 3c8f2a094..909012c8e 100644
--- a/Doc/Zsh/prompt.yo
+++ b/Doc/Zsh/prompt.yo
@@ -198,11 +198,15 @@ endsitem()
In addition, if the system supports the POSIX tt(gettimeofday) system
call, tt(%.) provides decimal fractions of a second since the epoch with
leading zeroes. By default three decimal places are provided, but a
-number of digits up to 6 may be given following the tt(%); hence tt(%6.)
-outputs microseconds. A typical example of this is the format
-`tt(%D{%H:%M:%S.%.})'.
+number of digits up to 9 may be given following the tt(%); hence tt(%6.)
+outputs microseconds, and tt(%9.) outputs nanoseconds. (The latter
+requires a nanosecond-precision tt(clock_gettime); systems lacking this
+will return a value multiplied by the appropriate power of 10.) A typical
+example of this is the format `tt(%D{%H:%M:%S.%.})'.
-The GNU extension that a `tt(-)' between the tt(%) and the
+The GNU extension tt(%N) is handled as a synonym for tt(%9.).
+
+Additionally, the GNU extension that a `tt(-)' between the tt(%) and the
format character causes a leading zero or space to be stripped
is handled directly by the shell for the format characters tt(d), tt(f),
tt(H), tt(k), tt(l), tt(m), tt(M), tt(S) and tt(y); any other format
diff --git a/Doc/Zsh/mod_stat.yo b/Doc/Zsh/mod_stat.yo
index 96349061e..9caed1e45 100644
--- a/Doc/Zsh/mod_stat.yo
+++ b/Doc/Zsh/mod_stat.yo
@@ -114,7 +114,11 @@ named files; no list of file names is allowed in this case.
)
item(tt(-F) var(fmt))(
Supplies a tt(strftime) (see manref(strftime)(3)) string for the
-formatting of the time elements. The tt(-s) option is implied.
+formatting of the time elements. The format string supports all of the
+zsh extensions described in
+ifzman(the section EXPANSION OF PROMPT SEQUENCES in zmanref(zshmisc))\
+ifnzman(noderef(Prompt Expansion)).
+The tt(-s) option is implied.
)
item(tt(-g))(
Show the time elements in the GMT time zone. The
Messages sorted by:
Reverse Date,
Date,
Thread,
Author