]> granicus.if.org Git - jq/commitdiff
Add `localtime` and `strflocaltime` (fix #1349)
authorNicolas Williams <nico@cryptonector.com>
Fri, 24 Feb 2017 04:26:53 +0000 (22:26 -0600)
committerNicolas Williams <nico@cryptonector.com>
Fri, 24 Feb 2017 04:26:53 +0000 (22:26 -0600)
configure.ac
src/builtin.c

index 1a1e51c46da491789c4cfa3f52bcd5af58d34fd5..02c42842246d585a73a34114070282531aff9a5b 100644 (file)
@@ -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>]])
index 380ae449ad485a56d4627477cd2e250ee7a61452..3fa65a4e26483eb6e24049dc7c984d67d5ac5f77 100644 (file)
@@ -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},