about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog6
-rw-r--r--Doc/Zsh/mod_datetime.yo21
-rw-r--r--Src/Modules/datetime.c66
-rw-r--r--configure.ac3
4 files changed, 90 insertions, 6 deletions
diff --git a/ChangeLog b/ChangeLog
index ef0d8f7c7..e80bf8314 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,9 @@
 2006-08-17  Peter Stephenson  <pws@csr.com>
 
+	* 22613: configure.ac, Doc/Zsh/mod_datetime.yo,
+	Src/Modules/datetime.c: add strftime -r to use strptime()
+	if available.
+
 	* 22612: Src/Zle/complist.c: comment the static variables.
 
 2006-08-16  Peter Stephenson  <pws@csr.com>
@@ -19,7 +23,7 @@
 
 2006-08-14  Peter Stephenson  <pws@csr.com>
 
-	* 22608: Doc/Zsh/contrib.yo: improvments on 22606.
+	* 22608: Doc/Zsh/contrib.yo: improvements on 22606.
 
 	* 22606: Doc/Zsh/contrib.yo, Functions/Zle/match-word-context,
 	Functions/Zle/match-words-by-style, Functions/Zle/.distfiles: new
diff --git a/Doc/Zsh/mod_datetime.yo b/Doc/Zsh/mod_datetime.yo
index b006baf89..145d4a181 100644
--- a/Doc/Zsh/mod_datetime.yo
+++ b/Doc/Zsh/mod_datetime.yo
@@ -6,12 +6,27 @@ The tt(zsh/datetime) module makes available one builtin command:
 startitem()
 findex(strftime)
 cindex(date string, printing)
-item(tt(strftime) [ tt(-s) var(scalar) ] var(format) var(epochtime) )(
+xitem(tt(strftime) [ tt(-s) var(scalar) ] var(format) var(epochtime) )
+item(tt(strftime) tt(-r) [ tt(-q) ] [ tt(-s) var(scalar) ] var(format) var(timestring) )(
 Output the date denoted by var(epochtime) in the var(format)
 specified.
 
-If tt(-s) var(scalar) is given, assign the date to var(scalar) instead
-of printing it.
+With the option tt(-r) (reverse), use the format var(format) to parse the
+input string var(timestring) and output the number of seconds since the
+epoch at which the time occurred.  If no timezone is parsed, the current
+timezone is used; other parameters are set to zero if not present.  If
+var(timestring) does not match var(format) the command returns status 1; it
+will additionally print an error message unless the option tt(-q) (quiet)
+is given.  If var(timestring) matches var(format) but not all characters in
+var(timestring) were used, the conversion succeeds; however, a warning is
+issued unless the option tt(-q) is given.  The matching is implemented by
+the system function tt(strptime); see manref(strptime)(3).  This means that
+zsh format extensions are not available, however for reverse lookup they
+are not required.  If the function is not implemented, the command returns
+status 2 and (unless tt(-q) is given) prints a message.
+
+If tt(-s) var(scalar) is given, assign the date string (or epoch time
+in seconds if tt(-r) is given) to var(scalar) instead of printing it.
 )
 enditem()
 
diff --git a/Src/Modules/datetime.c b/Src/Modules/datetime.c
index 8b5ff5d68..add4b303b 100644
--- a/Src/Modules/datetime.c
+++ b/Src/Modules/datetime.c
@@ -31,6 +31,68 @@
 #include "datetime.pro"
 #include <time.h>
 
+#ifndef HAVE_MKTIME
+#ifdef HAVE_TIMELOCAL
+#define	mktime(x)	timelocal(x)
+#define HAVE_MKTIME	1
+#endif
+#endif
+
+static int
+reverse_strftime(char *nam, char **argv, char *scalar, int quiet)
+{
+#if defined(HAVE_STRPTIME) && defined(HAVE_MKTIME)
+    struct tm tm;
+    zlong mytime;
+    char *endp;
+
+    /*
+     * Initialise all parameters to zero; there's no floating point
+     * so memset() will do the trick.  The exception is that tm_isdst
+     * is set to -1 which, if not overridden, will cause mktime()
+     * to use the current timezone.  This is probably the best guess;
+     * it's the one that will cause dates and times output by strftime
+     * without the -r option and without an explicit timezone to be
+     * converted back correctly.
+     */
+    (void)memset(&tm, 0, sizeof(tm));
+    tm.tm_isdst = -1;
+    endp = strptime(argv[1], argv[0], &tm);
+
+    if (!endp) {
+	/* Conversion failed completely. */
+	if (!quiet)
+	    zwarnnam(nam, "format not matched");
+	return 1;
+    }
+
+    mytime = (zlong)mktime(&tm);
+
+    if (scalar)
+	setiparam(scalar, mytime);
+    else {
+	char buf[DIGBUFSIZE];
+	convbase(buf, mytime, 10);
+	printf("%s\n", buf);
+    }
+
+    if (*endp && !quiet) {
+	/*
+	 * Not everything in the input string was converted.
+	 * This is probably benign, since the format has been satisfied,
+	 * but issue a warning unless the quiet flag is set.
+	 */
+	zwarnnam(nam, "warning: input string not completely matched");
+    }
+
+    return 0;
+#else
+    if (!quiet)
+	zwarnnam(nam, "not implemented on this system");
+    return 2;
+#endif
+}
+
 static int
 bin_strftime(char *nam, char **argv, Options ops, UNUSED(int func))
 {
@@ -46,6 +108,8 @@ bin_strftime(char *nam, char **argv, Options ops, UNUSED(int func))
 	    return 1;
 	}
     }
+    if (OPT_ISSET(ops, 'r'))
+	return reverse_strftime(nam, argv, scalar, OPT_ISSET(ops, 'q'));
 
     secs = (time_t)strtoul(argv[1], &endptr, 10);
     if (secs == (time_t)ULONG_MAX) {
@@ -83,7 +147,7 @@ getcurrentsecs()
 }
 
 static struct builtin bintab[] = {
-    BUILTIN("strftime",    0, bin_strftime,    2,   2, 0, "s:", NULL),
+    BUILTIN("strftime",    0, bin_strftime,    2,   2, 0, "qrs:", NULL),
 };
 
 static const struct gsu_integer epochseconds_gsu =
diff --git a/configure.ac b/configure.ac
index 75f4d7687..21e7764e2 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1096,7 +1096,8 @@ dnl ---------------
 dnl need to integrate this function
 dnl AC_FUNC_STRFTIME
 
-AC_CHECK_FUNCS(strftime difftime gettimeofday \
+AC_CHECK_FUNCS(strftime strptime mktime timelocal \
+	       difftime gettimeofday \
 	       select poll \
 	       readlink faccessx fchdir ftruncate \
 	       fstat lstat lchown fchown fchmod \