summary refs log tree commit diff
path: root/Src/Modules/datetime.c
diff options
context:
space:
mode:
Diffstat (limited to 'Src/Modules/datetime.c')
-rw-r--r--Src/Modules/datetime.c64
1 files changed, 46 insertions, 18 deletions
diff --git a/Src/Modules/datetime.c b/Src/Modules/datetime.c
index be378b347..18c7fb58e 100644
--- a/Src/Modules/datetime.c
+++ b/Src/Modules/datetime.c
@@ -100,8 +100,8 @@ output_strftime(char *nam, char **argv, Options ops, UNUSED(int func))
 {
     int bufsize, x, len;
     char *endptr = NULL, *scalar = NULL, *buffer;
-    time_t secs;
-    struct tm *t;
+    struct tm *tm;
+    struct timespec ts;
 
     if (OPT_ISSET(ops,'s')) {
 	scalar = OPT_ARG(ops, 's');
@@ -110,30 +110,58 @@ output_strftime(char *nam, char **argv, Options ops, UNUSED(int func))
 	    return 1;
 	}
     }
-    if (OPT_ISSET(ops, 'r'))
+    if (OPT_ISSET(ops, 'r')) {
+	if (!argv[1]) {
+	    zwarnnam(nam, "timestring expected");
+	    return 1;
+	}
 	return reverse_strftime(nam, argv, scalar, OPT_ISSET(ops, 'q'));
-
-    errno = 0;
-    secs = (time_t)strtoul(argv[1], &endptr, 10);
-    if (errno != 0) {
-	zwarnnam(nam, "%s: %e", argv[1], errno);
-	return 1;
-    } else if (*endptr != '\0') {
-	zwarnnam(nam, "%s: invalid decimal number", argv[1]);
-	return 1;
     }
 
-    t = localtime(&secs);
-    if (!t) {
-	zwarnnam(nam, "%s: unable to convert to time", argv[1]);
-	return 1;
+    if (!argv[1]) {
+	zgettime(&ts);
+	tm = localtime(&ts.tv_sec);
+    } else {
+	errno = 0;
+
+	ts.tv_sec = (time_t)strtoul(argv[1], &endptr, 10);
+	if (errno != 0) {
+	    zwarnnam(nam, "%s: %e", argv[1], errno);
+	    return 1;
+	} else if (*argv[1] == '\0' || *endptr != '\0') {
+	    zwarnnam(nam, "%s: invalid decimal number", argv[1]);
+	    return 1;
+	}
+
+	tm = localtime(&ts.tv_sec);
+	if (!tm) {
+	    zwarnnam(nam, "%s: unable to convert to time", argv[1]);
+	    return 1;
+	}
+
+	ts.tv_nsec = 0L;
+	if (argv[2]) {
+	    ts.tv_nsec = (long)zstrtol(argv[2], &endptr, 10);
+	    if (errno != 0) {
+		zwarnnam(nam, "%s: %e", argv[2], errno);
+		return 1;
+	    } else if (*argv[2] == '\0' || *endptr != '\0') {
+		zwarnnam(nam, "%s: invalid decimal number", argv[2]);
+		return 1;
+	    } else if (ts.tv_nsec < 0) {
+		zwarnnam(nam, "%s: invalid nanosecond value", argv[2]);
+		return 1;
+	    }
+	}
     }
+
     bufsize = strlen(argv[0]) * 8;
     buffer = zalloc(bufsize);
 
     len = 0;
     for (x=0; x < 4; x++) {
-        if ((len = ztrftime(buffer, bufsize, argv[0], t, 0L)) >= 0 || x==3)
+        if ((len = ztrftime(buffer, bufsize, argv[0], tm, ts.tv_nsec)) >= 0 ||
+	    x==3)
 	    break;
 	buffer = zrealloc(buffer, bufsize *= 2);
     }
@@ -207,7 +235,7 @@ getcurrenttime(UNUSED(Param pm))
 }
 
 static struct builtin bintab[] = {
-    BUILTIN("strftime",    0, bin_strftime,    2,   2, 0, "qrs:", NULL),
+    BUILTIN("strftime",    0, bin_strftime,    1,   3, 0, "qrs:", NULL),
 };
 
 static const struct gsu_integer epochseconds_gsu =