Add ISO 8601-specific strptime

Implement `strptime` for systems lacking it, but only supporting the
ISO 8601 format string.
This commit is contained in:
Jason Hood authored and Nico Williams committed 2019-02-16 20:41:41 -06:00
1 parent 87594f81d6
commit 0fc8200ab4
1 file changed
+25 -9
+25 -9
View File
@@ -1308,7 +1308,25 @@ static void set_tm_yday(struct tm *tm) {
tm->tm_yday = yday;
}
#ifdef HAVE_STRPTIME
#ifndef HAVE_STRPTIME
static char *strptime(const char *s, const char *format, struct tm *tm) {
if (strcmp(format, "%Y-%m-%dT%H:%M:%SZ"))
return NULL;
int count, end;
count = sscanf(s, "%d-%d-%dT%d:%d:%d%n",
&tm->tm_year, &tm->tm_mon, &tm->tm_mday,
&tm->tm_hour, &tm->tm_min, &tm->tm_sec,
&end );
if (count == 6 && s[end] == 'Z') {
tm->tm_year -= 1900;
tm->tm_mon--;
return (char*)s + end + 1;
}
return NULL;
}
#endif
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) {
return ret_error2(a, b, jv_string("strptime/1 requires string inputs and arguments"));
@@ -1320,8 +1338,13 @@ static jv f_strptime(jq_state *jq, jv a, jv b) {
tm.tm_yday = 367; // sentinel
const char *input = jv_string_value(a);
const char *fmt = jv_string_value(b);
const char *end = strptime(input, fmt, &tm);
#ifndef HAVE_STRPTIME
if (strcmp(fmt, "%Y-%m-%dT%H:%M:%SZ")) {
return ret_error2(a, b, jv_string("strptime/1 only supports ISO 8601 on this platform"));
}
#endif
const char *end = strptime(input, fmt, &tm);
if (end == NULL || (*end != '\0' && !isspace(*end))) {
return ret_error2(a, b, jv_string_fmt("date \"%s\" does not match format \"%s\"", input, fmt));
}
@@ -1358,13 +1381,6 @@ static jv f_strptime(jq_state *jq, jv a, jv b) {
jv_free(a); // must come after `*end` because `end` is a pointer into `a`'s string
return r;
}
#else
static jv f_strptime(jq_state *jq, jv a, jv b) {
jv_free(a);
jv_free(b);
return jv_invalid_with_msg(jv_string("strptime/1 not implemented on this platform"));
}
#endif
#define TO_TM_FIELD(t, j, i) \
do { \