diff options
author | Nicolas Williams <nico@cryptonector.com> | 2017-02-23 22:26:53 -0600 |
---|---|---|
committer | Nicolas Williams <nico@cryptonector.com> | 2017-02-23 22:26:53 -0600 |
commit | 06f20603f6022b721fa6a001969fbbb1111f113d (patch) | |
tree | 23eed72661434e5f672c093c6e65f625e092a8ad | |
parent | 607a9e3912434b5274bdce453738b63f78b76c57 (diff) |
Add `localtime` and `strflocaltime` (fix #1349)
-rw-r--r-- | configure.ac | 2 | ||||
-rw-r--r-- | src/builtin.c | 67 |
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}, |