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;
|
||||
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;
|
||||
double frac;
|
||||
|
||||
|
@ -47,14 +47,12 @@ int iso8601_parse(const char* str, struct iso8601_date* earliest, struct iso8601
|
|||
num *= 10; \
|
||||
num += ch - '0'; \
|
||||
if(num > 1000000000) { \
|
||||
errno = EDOM; \
|
||||
return -1; \
|
||||
} \
|
||||
}while(0)
|
||||
|
||||
#define ERROR_IF(x) do { \
|
||||
if(x) { \
|
||||
errno = EILSEQ; \
|
||||
return -1; \
|
||||
} \
|
||||
}while(0)
|
||||
|
@ -77,7 +75,6 @@ int iso8601_parse(const char* str, struct iso8601_date* earliest, struct iso8601
|
|||
break;
|
||||
|
||||
default:
|
||||
errno = EILSEQ;
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
|
@ -127,7 +124,6 @@ int iso8601_parse(const char* str, struct iso8601_date* earliest, struct iso8601
|
|||
break;
|
||||
|
||||
default:
|
||||
errno = EILSEQ;
|
||||
return -1;
|
||||
}
|
||||
if(!ch) goto done;
|
||||
|
@ -162,7 +158,6 @@ int iso8601_parse(const char* str, struct iso8601_date* earliest, struct iso8601
|
|||
|
||||
case 'W':
|
||||
if(dig) {
|
||||
errno = EILSEQ;
|
||||
return -1;
|
||||
}
|
||||
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 3: d = num; goto done;
|
||||
}
|
||||
errno = EILSEQ;
|
||||
return -1;
|
||||
|
||||
case 'T':
|
||||
|
@ -185,7 +179,6 @@ int iso8601_parse(const char* str, struct iso8601_date* earliest, struct iso8601
|
|||
break;
|
||||
|
||||
default:
|
||||
errno = EILSEQ;
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
|
@ -208,7 +201,6 @@ int iso8601_parse(const char* str, struct iso8601_date* earliest, struct iso8601
|
|||
break;
|
||||
|
||||
default:
|
||||
errno = EILSEQ;
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
|
@ -232,7 +224,6 @@ int iso8601_parse(const char* str, struct iso8601_date* earliest, struct iso8601
|
|||
goto done;
|
||||
}
|
||||
|
||||
errno = EILSEQ;
|
||||
return -1;
|
||||
|
||||
case 'T':
|
||||
|
@ -247,7 +238,6 @@ int iso8601_parse(const char* str, struct iso8601_date* earliest, struct iso8601
|
|||
break;
|
||||
|
||||
default:
|
||||
errno = EILSEQ;
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
|
@ -311,7 +301,6 @@ int iso8601_parse(const char* str, struct iso8601_date* earliest, struct iso8601
|
|||
break;
|
||||
|
||||
default:
|
||||
errno = EILSEQ;
|
||||
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 '+': state = state_tz_basic; break;
|
||||
case '-': tz_neg = 1; state = state_tz_basic; break;
|
||||
default: errno = EILSEQ; return -1;
|
||||
default: return -1;
|
||||
}
|
||||
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 '+': state = state_tz_hour; break;
|
||||
case '-': tz_neg = 1; state = state_tz_hour; break;
|
||||
default: errno = EILSEQ; return -1;
|
||||
default: return -1;
|
||||
}
|
||||
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 '+': state = state_tz_hour; break;
|
||||
case '-': tz_neg = 1; state = state_tz_hour; break;
|
||||
default: errno = EILSEQ; return -1;
|
||||
default: return -1;
|
||||
}
|
||||
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 '+': state = state_tz_hour; break;
|
||||
case '-': tz_neg = 1; state = state_tz_hour; break;
|
||||
default: errno = EILSEQ; return -1;
|
||||
default: return -1;
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -450,13 +439,11 @@ int iso8601_parse(const char* str, struct iso8601_date* earliest, struct iso8601
|
|||
break;
|
||||
|
||||
default:
|
||||
errno = EILSEQ;
|
||||
return -1;
|
||||
}
|
||||
goto done;
|
||||
|
||||
default:
|
||||
errno = EILSEQ;
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
|
@ -479,7 +466,7 @@ int iso8601_parse(const char* str, struct iso8601_date* earliest, struct iso8601
|
|||
switch(ch) {
|
||||
case ':': state = state_tz_min; break;
|
||||
case 0: goto done;
|
||||
default: errno = EILSEQ; return -1;
|
||||
default: return -1;
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -497,7 +484,7 @@ int iso8601_parse(const char* str, struct iso8601_date* earliest, struct iso8601
|
|||
switch(ch) {
|
||||
case ':': state = state_tz_sec; break;
|
||||
case 0: goto done;
|
||||
default: errno = EILSEQ; return -1;
|
||||
default: return -1;
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -515,9 +502,6 @@ int iso8601_parse(const char* str, struct iso8601_date* earliest, struct iso8601
|
|||
}
|
||||
}
|
||||
|
||||
#undef ERROR_IF
|
||||
#undef INCNUM
|
||||
|
||||
done:
|
||||
if(neg) y *= -1;
|
||||
if(tz_neg) tz_sec *= -1;
|
||||
|
@ -568,6 +552,11 @@ done:
|
|||
if(details) details->time_prec = iso8601_prec_none;
|
||||
|
||||
} else if(sec != -1) {
|
||||
if(sec == 60) {
|
||||
leap_sec_req++;
|
||||
sec = 59;
|
||||
}
|
||||
|
||||
if(earliest && iso8601_from_clocktime(earliest, 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(tz_sec && earliest) iso8601_add_seconds(earliest, -tz_sec);
|
||||
if(tz_sec && latest) iso8601_add_seconds(latest, -tz_sec);
|
||||
if(tz_sec && earliest) iso8601_add_seconds(earliest, - leap_sec_req - tz_sec);
|
||||
if(tz_sec && latest) iso8601_add_seconds(latest, - leap_sec_req - tz_sec);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int iso8601_valid(const struct iso8601_date* date)
|
||||
{
|
||||
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;
|
||||
// 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);
|
||||
ERROR_IF(latest && latest->sec == 86401 && latest->nsec);
|
||||
|
||||
return 0;
|
||||
#undef ERROR_IF
|
||||
#undef INCNUM
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue