Improve parser's dealing of midnight etc.
This commit is contained in:
parent
6a55a63695
commit
994a28d35b
|
@ -34,7 +34,7 @@ int iso8601_parse(const char* str, struct iso8601_date* earliest, struct iso8601
|
||||||
|
|
||||||
div_t qr;
|
div_t qr;
|
||||||
char ch;
|
char ch;
|
||||||
int num = 0, neg = 0, dig = 0, tz_neg = 0, nsec = -1, nsec_dig = -1;
|
int num = 0, neg = 0, dig = 0, tz_neg = 0, nsec = -1, nsec_dig = -1, leap_sec_req = 0;
|
||||||
int y = 0, m = -1, d = -1, w = -1, wd = -1, hour = -1, min = -1, sec = -1, tz_sec = 0;
|
int y = 0, m = -1, d = -1, w = -1, wd = -1, hour = -1, min = -1, sec = -1, tz_sec = 0;
|
||||||
double frac;
|
double frac;
|
||||||
|
|
||||||
|
@ -47,14 +47,12 @@ int iso8601_parse(const char* str, struct iso8601_date* earliest, struct iso8601
|
||||||
num *= 10; \
|
num *= 10; \
|
||||||
num += ch - '0'; \
|
num += ch - '0'; \
|
||||||
if(num > 1000000000) { \
|
if(num > 1000000000) { \
|
||||||
errno = EDOM; \
|
|
||||||
return -1; \
|
return -1; \
|
||||||
} \
|
} \
|
||||||
}while(0)
|
}while(0)
|
||||||
|
|
||||||
#define ERROR_IF(x) do { \
|
#define ERROR_IF(x) do { \
|
||||||
if(x) { \
|
if(x) { \
|
||||||
errno = EILSEQ; \
|
|
||||||
return -1; \
|
return -1; \
|
||||||
} \
|
} \
|
||||||
}while(0)
|
}while(0)
|
||||||
|
@ -77,7 +75,6 @@ int iso8601_parse(const char* str, struct iso8601_date* earliest, struct iso8601
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
errno = EILSEQ;
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -127,7 +124,6 @@ int iso8601_parse(const char* str, struct iso8601_date* earliest, struct iso8601
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
errno = EILSEQ;
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if(!ch) goto done;
|
if(!ch) goto done;
|
||||||
|
@ -162,7 +158,6 @@ int iso8601_parse(const char* str, struct iso8601_date* earliest, struct iso8601
|
||||||
|
|
||||||
case 'W':
|
case 'W':
|
||||||
if(dig) {
|
if(dig) {
|
||||||
errno = EILSEQ;
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
state = state_week_extended;
|
state = state_week_extended;
|
||||||
|
@ -173,7 +168,6 @@ int iso8601_parse(const char* str, struct iso8601_date* earliest, struct iso8601
|
||||||
case 2: m = num; goto done;
|
case 2: m = num; goto done;
|
||||||
case 3: d = num; goto done;
|
case 3: d = num; goto done;
|
||||||
}
|
}
|
||||||
errno = EILSEQ;
|
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
case 'T':
|
case 'T':
|
||||||
|
@ -185,7 +179,6 @@ int iso8601_parse(const char* str, struct iso8601_date* earliest, struct iso8601
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
errno = EILSEQ;
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -208,7 +201,6 @@ int iso8601_parse(const char* str, struct iso8601_date* earliest, struct iso8601
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
errno = EILSEQ;
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -232,7 +224,6 @@ int iso8601_parse(const char* str, struct iso8601_date* earliest, struct iso8601
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
errno = EILSEQ;
|
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
case 'T':
|
case 'T':
|
||||||
|
@ -247,7 +238,6 @@ int iso8601_parse(const char* str, struct iso8601_date* earliest, struct iso8601
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
errno = EILSEQ;
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -311,7 +301,6 @@ int iso8601_parse(const char* str, struct iso8601_date* earliest, struct iso8601
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
errno = EILSEQ;
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -324,7 +313,7 @@ int iso8601_parse(const char* str, struct iso8601_date* earliest, struct iso8601
|
||||||
case 'Z': state = state_tz_utc; break;
|
case 'Z': state = state_tz_utc; break;
|
||||||
case '+': state = state_tz_basic; break;
|
case '+': state = state_tz_basic; break;
|
||||||
case '-': tz_neg = 1; state = state_tz_basic; break;
|
case '-': tz_neg = 1; state = state_tz_basic; break;
|
||||||
default: errno = EILSEQ; return -1;
|
default: return -1;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -346,7 +335,7 @@ int iso8601_parse(const char* str, struct iso8601_date* earliest, struct iso8601
|
||||||
case 'Z': state = state_tz_utc; break;
|
case 'Z': state = state_tz_utc; break;
|
||||||
case '+': state = state_tz_hour; break;
|
case '+': state = state_tz_hour; break;
|
||||||
case '-': tz_neg = 1; state = state_tz_hour; break;
|
case '-': tz_neg = 1; state = state_tz_hour; break;
|
||||||
default: errno = EILSEQ; return -1;
|
default: return -1;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -368,7 +357,7 @@ int iso8601_parse(const char* str, struct iso8601_date* earliest, struct iso8601
|
||||||
case 'Z': state = state_tz_utc; break;
|
case 'Z': state = state_tz_utc; break;
|
||||||
case '+': state = state_tz_hour; break;
|
case '+': state = state_tz_hour; break;
|
||||||
case '-': tz_neg = 1; state = state_tz_hour; break;
|
case '-': tz_neg = 1; state = state_tz_hour; break;
|
||||||
default: errno = EILSEQ; return -1;
|
default: return -1;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -389,7 +378,7 @@ int iso8601_parse(const char* str, struct iso8601_date* earliest, struct iso8601
|
||||||
case 'Z': state = state_tz_utc; break;
|
case 'Z': state = state_tz_utc; break;
|
||||||
case '+': state = state_tz_hour; break;
|
case '+': state = state_tz_hour; break;
|
||||||
case '-': tz_neg = 1; state = state_tz_hour; break;
|
case '-': tz_neg = 1; state = state_tz_hour; break;
|
||||||
default: errno = EILSEQ; return -1;
|
default: return -1;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -450,13 +439,11 @@ int iso8601_parse(const char* str, struct iso8601_date* earliest, struct iso8601
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
errno = EILSEQ;
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
errno = EILSEQ;
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -479,7 +466,7 @@ int iso8601_parse(const char* str, struct iso8601_date* earliest, struct iso8601
|
||||||
switch(ch) {
|
switch(ch) {
|
||||||
case ':': state = state_tz_min; break;
|
case ':': state = state_tz_min; break;
|
||||||
case 0: goto done;
|
case 0: goto done;
|
||||||
default: errno = EILSEQ; return -1;
|
default: return -1;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -497,7 +484,7 @@ int iso8601_parse(const char* str, struct iso8601_date* earliest, struct iso8601
|
||||||
switch(ch) {
|
switch(ch) {
|
||||||
case ':': state = state_tz_sec; break;
|
case ':': state = state_tz_sec; break;
|
||||||
case 0: goto done;
|
case 0: goto done;
|
||||||
default: errno = EILSEQ; return -1;
|
default: return -1;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -515,9 +502,6 @@ int iso8601_parse(const char* str, struct iso8601_date* earliest, struct iso8601
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#undef ERROR_IF
|
|
||||||
#undef INCNUM
|
|
||||||
|
|
||||||
done:
|
done:
|
||||||
if(neg) y *= -1;
|
if(neg) y *= -1;
|
||||||
if(tz_neg) tz_sec *= -1;
|
if(tz_neg) tz_sec *= -1;
|
||||||
|
@ -568,6 +552,11 @@ done:
|
||||||
if(details) details->time_prec = iso8601_prec_none;
|
if(details) details->time_prec = iso8601_prec_none;
|
||||||
|
|
||||||
} else if(sec != -1) {
|
} else if(sec != -1) {
|
||||||
|
if(sec == 60) {
|
||||||
|
leap_sec_req++;
|
||||||
|
sec = 59;
|
||||||
|
}
|
||||||
|
|
||||||
if(earliest && iso8601_from_clocktime(earliest, hour, min, sec)) return -1;
|
if(earliest && iso8601_from_clocktime(earliest, hour, min, sec)) return -1;
|
||||||
if(latest && iso8601_from_clocktime(latest, hour, min, sec)) return -1;
|
if(latest && iso8601_from_clocktime(latest, hour, min, sec)) return -1;
|
||||||
|
|
||||||
|
@ -625,28 +614,25 @@ done:
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// correct for timezone offset (note trickery to end up at 23:59:60 iff a leap second was
|
||||||
|
// requested)
|
||||||
if(details) details->tz_sec = tz_sec;
|
if(details) details->tz_sec = tz_sec;
|
||||||
if(tz_sec && earliest) iso8601_add_seconds(earliest, -tz_sec);
|
if(tz_sec && earliest) iso8601_add_seconds(earliest, - leap_sec_req - tz_sec);
|
||||||
if(tz_sec && latest) iso8601_add_seconds(latest, -tz_sec);
|
if(tz_sec && latest) iso8601_add_seconds(latest, - leap_sec_req - tz_sec);
|
||||||
|
|
||||||
return 0;
|
// check that, if a leap second was requested, it was a valid leap second
|
||||||
|
if(leap_sec_req) {
|
||||||
|
ERROR_IF(earliest && earliest->sec != 86400);
|
||||||
|
ERROR_IF(latest && latest->sec != 86400);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// we can't have e.g. 240000.5
|
||||||
|
ERROR_IF(earliest && earliest->sec == 86401 && earliest->nsec);
|
||||||
int iso8601_valid(const struct iso8601_date* date)
|
ERROR_IF(latest && latest->sec == 86401 && latest->nsec);
|
||||||
{
|
|
||||||
if(date->nsec < 0 || date->nsec > 1000000000) return 0;
|
|
||||||
|
|
||||||
switch(date->sec) {
|
|
||||||
case 0 ... 86399:
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
case 86401: /* 24:00:00 */
|
|
||||||
return !date->nsec;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
#undef ERROR_IF
|
||||||
|
#undef INCNUM
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue