summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNicolas Williams <nico@cryptonector.com>2017-02-23 22:26:53 -0600
committerNicolas Williams <nico@cryptonector.com>2017-02-23 22:26:53 -0600
commit06f20603f6022b721fa6a001969fbbb1111f113d (patch)
tree23eed72661434e5f672c093c6e65f625e092a8ad
parent607a9e3912434b5274bdce453738b63f78b76c57 (diff)
Add `localtime` and `strflocaltime` (fix #1349)
-rw-r--r--configure.ac2
-rw-r--r--src/builtin.c67
2 files changed, 69 insertions, 0 deletions
diff --git a/configure.ac b/configure.ac
index 1a1e51c4..02c42842 100644
--- a/configure.ac
+++ b/configure.ac
@@ -127,6 +127,8 @@ AC_FIND_FUNC([strftime], [c], [#include <time.h>], [0, 0, 0, 0])
AC_FIND_FUNC([timegm], [c], [#include <time.h>], [0])
AC_FIND_FUNC([gmtime_r], [c], [#include <time.h>], [0, 0])
AC_FIND_FUNC([gmtime], [c], [#include <time.h>], [0])
+AC_FIND_FUNC([localtime_r], [c], [#include <time.h>], [0, 0])
+AC_FIND_FUNC([localtime], [c], [#include <time.h>], [0])
AC_FIND_FUNC([gettimeofday], [c], [#include <time.h>], [0, 0])
AC_CHECK_MEMBER([struct tm.tm_gmtoff], [AC_DEFINE([HAVE_TM_TM_GMT_OFF],1,[Define to 1 if the system has the tm_gmt_off field in struct tm])],
[], [[#include <time.h>]])
diff --git a/src/builtin.c b/src/builtin.c
index 380ae449..3fa65a4e 100644
--- a/src/builtin.c
+++ b/src/builtin.c
@@ -1283,6 +1283,43 @@ static jv f_gmtime(jq_state *jq, jv a) {
}
#endif
+#ifdef HAVE_LOCALTIME_R
+static jv f_localtime(jq_state *jq, jv a) {
+ if (jv_get_kind(a) != JV_KIND_NUMBER)
+ return jv_invalid_with_msg(jv_string("localtime() requires numeric inputs"));
+ struct tm tm, *tmp;
+ memset(&tm, 0, sizeof(tm));
+ double fsecs = jv_number_value(a);
+ time_t secs = fsecs;
+ jv_free(a);
+ tmp = localtime_r(&secs, &tm);
+ if (tmp == NULL)
+ return jv_invalid_with_msg(jv_string("errror converting number of seconds since epoch to datetime"));
+ a = tm2jv(tmp);
+ return jv_array_set(a, 5, jv_number(jv_number_value(jv_array_get(jv_copy(a), 5)) + (fsecs - floor(fsecs))));
+}
+#elif defined HAVE_GMTIME
+static jv f_localtime(jq_state *jq, jv a) {
+ if (jv_get_kind(a) != JV_KIND_NUMBER)
+ return jv_invalid_with_msg(jv_string("localtime requires numeric inputs"));
+ struct tm tm, *tmp;
+ memset(&tm, 0, sizeof(tm));
+ double fsecs = jv_number_value(a);
+ time_t secs = fsecs;
+ jv_free(a);
+ tmp = localtime(&secs);
+ if (tmp == NULL)
+ return jv_invalid_with_msg(jv_string("errror converting number of seconds since epoch to datetime"));
+ a = tm2jv(tmp);
+ return jv_array_set(a, 5, jv_number(jv_number_value(jv_array_get(jv_copy(a), 5)) + (fsecs - floor(fsecs))));
+}
+#else
+static jv f_localtime(jq_state *jq, jv a) {
+ jv_free(a);
+ return jv_invalid_with_msg(jv_string("localtime not implemented on this platform"));
+}
+#endif
+
#ifdef HAVE_STRFTIME
static jv f_strftime(jq_state *jq, jv a, jv b) {
if (jv_get_kind(a) == JV_KIND_NUMBER) {
@@ -1311,6 +1348,34 @@ static jv f_strftime(jq_state *jq, jv a) {
}
#endif
+#ifdef HAVE_STRFTIME
+static jv f_strflocaltime(jq_state *jq, jv a, jv b) {
+ if (jv_get_kind(a) == JV_KIND_NUMBER) {
+ a = f_localtime(jq, a);
+ } else if (jv_get_kind(a) != JV_KIND_ARRAY) {
+ return jv_invalid_with_msg(jv_string("strflocaltime/1 requires parsed datetime inputs"));
+ }
+ struct tm tm;
+ if (!jv2tm(a, &tm))
+ return jv_invalid_with_msg(jv_string("strflocaltime/1 requires parsed datetime inputs")); \
+ const char *fmt = jv_string_value(b);
+ size_t alloced = strlen(fmt) + 100;
+ char *buf = alloca(alloced);
+ size_t n = strftime(buf, alloced, fmt, &tm);
+ jv_free(b);
+ /* POSIX doesn't provide errno values for strftime() failures; weird */
+ if (n == 0 || n > alloced)
+ return jv_invalid_with_msg(jv_string("strflocaltime/1: unknown system failure"));
+ return jv_string(buf);
+}
+#else
+static jv f_strflocaltime(jq_state *jq, jv a) {
+ jv_free(a);
+ jv_free(b);
+ return jv_invalid_with_msg(jv_string("strflocaltime/1 not implemented on this platform"));
+}
+#endif
+
#ifdef HAVE_GETTIMEOFDAY
static jv f_now(jq_state *jq, jv a) {
jv_free(a);
@@ -1413,8 +1478,10 @@ static const struct cfunction function_list[] = {
{(cfunction_ptr)f_stderr, "stderr", 1},
{(cfunction_ptr)f_strptime, "strptime", 2},
{(cfunction_ptr)f_strftime, "strftime", 2},
+ {(cfunction_ptr)f_strflocaltime, "strflocaltime", 2},
{(cfunction_ptr)f_mktime, "mktime", 1},
{(cfunction_ptr)f_gmtime, "gmtime", 1},
+ {(cfunction_ptr)f_localtime, "localtime", 1},
{(cfunction_ptr)f_now, "now", 1},
{(cfunction_ptr)f_current_filename, "input_filename", 1},
{(cfunction_ptr)f_current_line, "input_line_number", 1},