summaryrefslogtreecommitdiffstats
path: root/builtin.c
diff options
context:
space:
mode:
authorNicolas Williams <nico@cryptonector.com>2015-03-31 10:03:35 -0500
committerNicolas Williams <nico@cryptonector.com>2015-03-31 10:03:35 -0500
commitddad9618dca03c93a029a4ec7ee7bcd9e69717fa (patch)
tree5528ee8e6d53aeb937107029714d47020c38f9b3 /builtin.c
parent24005287f4ed1ffe486060b3156d5dfe6a3847da (diff)
Test fix for mktime
Diffstat (limited to 'builtin.c')
-rw-r--r--builtin.c63
1 files changed, 39 insertions, 24 deletions
diff --git a/builtin.c b/builtin.c
index cef1d540..7ef3cfa4 100644
--- a/builtin.c
+++ b/builtin.c
@@ -936,6 +936,38 @@ static jv tm2jv(struct tm *tm) {
jv_number(tm->tm_yday));
}
+/*
+ * mktime() has side-effects and anyways, returns time in the local
+ * timezone, not UTC. We want timegm(), which isn't standard.
+ *
+ * To make things worse, mktime() tells you what the timezone
+ * adjustment is, but you have to #define _BSD_SOURCE to get this
+ * field of struct tm on some systems.
+ *
+ * This is all to blame on POSIX, of course.
+ *
+ * Our wrapper tries to use timegm() if available, or mktime() and
+ * correct for its side-effects if possible.
+ *
+ * Returns (time_t)-2 if mktime()'s side-effects cannot be corrected.
+ */
+static time_t my_mktime(struct tm *tm) {
+#ifdef HAVE_TIMEGM
+ return timegm(tm);
+#else /* HAVE_TIMEGM */
+ time_t t = mktime(&tm);
+ if (t == (time_t)-1)
+ return t;
+#ifdef HAVE_TM_TM_GMT_OFF
+ return t + tm.tm_gmtoff;
+#elif defined(HAVE_TM_TM_GMT_OFF)
+ return t + tm.__tm_gmtoff;
+#else
+ return (time_t)-2; /* Not supported */
+#endif
+#endif /* !HAVE_TIMEGM */
+}
+
#ifdef HAVE_STRPTIME
static jv f_strptime(jq_state *jq, jv a, jv b) {
if (jv_get_kind(a) != JV_KIND_STRING || jv_get_kind(b) != JV_KIND_STRING)
@@ -955,6 +987,8 @@ static jv f_strptime(jq_state *jq, jv a, jv b) {
}
jv_free(a);
jv_free(b);
+ if (tm.tm_wday == 0 && tm.tm_yday == 0 && my_mktime(&tm) == (time_t)-2)
+ return jv_invalid_with_msg(jv_string("strptime/1 not supported on this platform"));
jv r = tm2jv(&tm);
if (*end != '\0')
r = jv_array_append(r, jv_string(end));
@@ -996,35 +1030,16 @@ static jv f_mktime(jq_state *jq, jv a) {
if (jv_get_kind(a) != JV_KIND_ARRAY)
return jv_invalid_with_msg(jv_string("mktime requires array inputs"));
if (jv_array_length(jv_copy(a)) < 6)
- return jv_invalid_with_msg(jv_string("mktime requires parsed datetime inputs")); \
+ return jv_invalid_with_msg(jv_string("mktime requires parsed datetime inputs"));
struct tm tm;
if (!jv2tm(a, &tm))
- return jv_invalid_with_msg(jv_string("mktime requires parsed datetime inputs")); \
- /*
- * mktime() has side-effects and anyways, returns time in the local
- * timezone, not UTC. We want timegm(), which isn't standard.
- *
- * To make things worse, mktime() tells you what the timezone
- * adjustment is, but you have to #define _BSD_SOURCE to get this
- * field of struct tm on some systems.
- *
- * This is all to blame on POSIX, of course.
- */
-#ifdef HAVE_TIMEGM
- time_t t = timegm(&tm);
+ return jv_invalid_with_msg(jv_string("mktime requires parsed datetime inputs"));
+ time_t t = my_mktime(&tm);
if (t == (time_t)-1)
return jv_invalid_with_msg(jv_string("invalid gmtime representation"));
+ if (t == (time_t)-2)
+ return jv_invalid_with_msg(jv_string("mktime not supported on this platform"));
return jv_number(t);
-#else /* HAVE_TIMEGM */
- time_t t = mktime(&tm);
- if (t == (time_t)-1)
- return jv_invalid_with_msg(jv_string("invalid gmtime representation"));
-#ifdef HAVE_TM_TM_GMT_OFF
- return jv_number(t + tm.tm_gmtoff);
-#elif defined(HAVE_TM_TM_GMT_OFF)
- return jv_number(t + tm.__tm_gmtoff);
-#endif
-#endif /* HAVE_TIMEGM */
}
#ifdef HAVE_GMTIME_R