diff options
author | Nicolas Williams <nico@cryptonector.com> | 2015-03-31 10:03:35 -0500 |
---|---|---|
committer | Nicolas Williams <nico@cryptonector.com> | 2015-03-31 10:03:35 -0500 |
commit | ddad9618dca03c93a029a4ec7ee7bcd9e69717fa (patch) | |
tree | 5528ee8e6d53aeb937107029714d47020c38f9b3 /builtin.c | |
parent | 24005287f4ed1ffe486060b3156d5dfe6a3847da (diff) |
Test fix for mktime
Diffstat (limited to 'builtin.c')
-rw-r--r-- | builtin.c | 63 |
1 files changed, 39 insertions, 24 deletions
@@ -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 |