Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

PATCH: zsh/datetime $EPOCHREALTIME



I had a need for the current time to better than one second precision in
a shell function, which currently (as far as I can see) the shell
doesn't do.  It does for SECONDS, but that's not useful for comparison
with times used by the rest of the system.

Adding a floating point variable to zsh/datetime seems to be the natural
way to go.  It's called EPOCHREALTIME because it's using CLOCK_REALTIME,
which is a bit of arcane knowledge the shell user doesn't need to know,
and is tautologous since that by definition measures time since the
epoch, but since EPOCHSECONDS is already taken I had to make something
up.  The state of the art (POSIX) appears to be clock_gettime(), rather
than gettimeofday() that's used elsewhere in the shell, but it will
fall back if that's not available; we already assume gettimeofday() is
present so I haven't bothered testing for it.

Linux hides clock_gettime() in a library called librt.  I'm not sure how
standard that is, but it's another reason for the HAVE_... test.

Index: configure.ac
===================================================================
RCS file: /cvsroot/zsh/zsh/configure.ac,v
retrieving revision 1.136
diff -p -u -r1.136 configure.ac
--- configure.ac	14 May 2011 00:07:41 -0000	1.136
+++ configure.ac	10 Aug 2011 11:12:33 -0000
@@ -693,6 +693,8 @@ AC_CHECK_LIB(c, printf, [LIBS="$LIBS -lc
 
 AC_CHECK_LIB(m, pow)
 
+AC_CHECK_LIB(rt, clock_gettime)
+
 dnl Various features of ncurses depend on having the right header
 dnl (the system's own curses.h may well not be good enough).
 dnl So don't search for ncurses unless we found the header.
@@ -1170,7 +1172,7 @@ dnl need to integrate this function
 dnl AC_FUNC_STRFTIME
 
 AC_CHECK_FUNCS(strftime strptime mktime timelocal \
-	       difftime gettimeofday \
+	       difftime gettimeofday clock_gettime \
 	       select poll \
 	       readlink faccessx fchdir ftruncate \
 	       fstat lstat lchown fchown fchmod \
Index: Doc/Zsh/mod_datetime.yo
===================================================================
RCS file: /cvsroot/zsh/zsh/Doc/Zsh/mod_datetime.yo,v
retrieving revision 1.3
diff -p -u -r1.3 mod_datetime.yo
--- Doc/Zsh/mod_datetime.yo	17 Aug 2006 15:28:11 -0000	1.3
+++ Doc/Zsh/mod_datetime.yo	10 Aug 2011 11:12:33 -0000
@@ -30,9 +30,17 @@ in seconds if tt(-r) is given) to var(sc
 )
 enditem()
 
-The tt(zsh/datetime) module makes available one parameter:
+The tt(zsh/datetime) module makes available several parameters:
 
 startitem()
+vindex(EPOCHREALTIME)
+item(tt(EPOCHREALTIME))(
+A floating point value representing the number of seconds since
+the epoch.  The notional accuracy is to nanoseconds if the
+tt(clock_gettime) call is available and to microseconds otherwise,
+but in practice the range of double precision floating point and
+shell scheduling latencies may be significant effects.
+)
 vindex(EPOCHSECONDS)
 item(tt(EPOCHSECONDS))(
 An integer value representing the number of seconds since the
Index: Src/module.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/module.c,v
retrieving revision 1.42
diff -p -u -r1.42 module.c
--- Src/module.c	14 Jun 2010 11:57:08 -0000	1.42
+++ Src/module.c	10 Aug 2011 11:12:33 -0000
@@ -1081,6 +1081,11 @@ addparamdef(Paramdef d)
 	    pm->gsu.i = d->gsu ? (GsuInteger)d->gsu : &varinteger_gsu;
 	    break;
 
+	case PM_FFLOAT:
+	case PM_EFLOAT:
+	    pm->gsu.f = d->gsu;
+	    break;
+
 	case PM_ARRAY:
 	    pm->gsu.a = d->gsu ? (GsuArray)d->gsu : &vararray_gsu;
 	    break;
Index: Src/Modules/datetime.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/Modules/datetime.c,v
retrieving revision 1.22
diff -p -u -r1.22 datetime.c
--- Src/Modules/datetime.c	13 May 2011 18:12:06 -0000	1.22
+++ Src/Modules/datetime.c	10 Aug 2011 11:12:33 -0000
@@ -151,6 +151,28 @@ getcurrentsecs(UNUSED(Param pm))
     return (zlong) time(NULL);
 }
 
+static double
+getcurrentrealtime(UNUSED(Param pm))
+{
+#ifdef HAVE_CLOCK_GETTIME
+    struct timespec now;
+
+    if (clock_gettime(CLOCK_REALTIME, &now) < 0) {
+	zwarn("EPOCHREALTIME: unable to retrieve time: %e", errno);
+	return (double)0.0;
+    }
+
+    return (double)now.tv_sec + (double)now.tv_nsec * 1e-9;
+#else
+    struct timeval now;
+    struct timezone dummy_tz;
+
+    gettimeofday(&now, &dummy_tz);
+
+    return (double)now.tv_sec + (double)now.tv_usec * 1e-6;
+#endif
+}
+
 static struct builtin bintab[] = {
     BUILTIN("strftime",    0, bin_strftime,    2,   2, 0, "qrs:", NULL),
 };
@@ -158,9 +180,14 @@ static struct builtin bintab[] = {
 static const struct gsu_integer epochseconds_gsu =
 { getcurrentsecs, NULL, stdunsetfn };
 
+static const struct gsu_float epochrealtime_gsu =
+{ getcurrentrealtime, NULL, stdunsetfn };
+
 static struct paramdef patab[] = {
     SPECIALPMDEF("EPOCHSECONDS", PM_INTEGER|PM_READONLY,
 		 &epochseconds_gsu, NULL, NULL),
+    SPECIALPMDEF("EPOCHREALTIME", PM_FFLOAT|PM_READONLY,
+		 &epochrealtime_gsu, NULL, NULL)
 };
 
 static struct features module_features = {


Member of the CSR plc group of companies. CSR plc registered in England and Wales, registered number 4187346, registered office Churchill House, Cambridge Business Park, Cowley Road, Cambridge, CB4 0WZ, United Kingdom
More information can be found at www.csr.com. Follow CSR on Twitter at http://twitter.com/CSR_PLC and read our blog at www.csr.com/blog



Messages sorted by: Reverse Date, Date, Thread, Author