Further WIP on parser
This commit is contained in:
parent
02d47dbdf2
commit
09fd37b4f5
|
@ -71,6 +71,21 @@ static const struct monthcount _days_in_month_leap[] = {
|
|||
|
||||
|
||||
|
||||
static int _days_in_month(int year, int month)
|
||||
{
|
||||
const struct monthcount* mc;
|
||||
|
||||
if(month < 1 || month > 12) {
|
||||
errno = EDOM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
mc = iso8601_isleap(year) ? _days_in_month_leap : _days_in_month_common;
|
||||
return mc[month - 1].days;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void _to_year(int* year, int* days_left, const struct iso8601_date* date)
|
||||
{
|
||||
div_t qr;
|
||||
|
@ -278,7 +293,7 @@ int iso8601_from_cal(struct iso8601_date* date, int year, int month, int day)
|
|||
|
||||
// check for domain errors
|
||||
mc = iso8601_isleap(year) ? _days_in_month_leap : _days_in_month_common;
|
||||
if(month < 1 || month > 12 || day < 0 || day > mc[month - 1].days) {
|
||||
if(month < 1 || month > 12 || day < 1 || day > mc[month - 1].days) {
|
||||
errno = EDOM;
|
||||
return -1;
|
||||
}
|
||||
|
@ -318,14 +333,22 @@ int iso8601_from_ord(struct iso8601_date* date, int year, int oday)
|
|||
|
||||
int iso8601_from_week(struct iso8601_date* date, int isoyear, int week, int wday)
|
||||
{
|
||||
int day1off;
|
||||
int day1off, maxwk;
|
||||
|
||||
// compute year part
|
||||
_from_year(date, isoyear);
|
||||
|
||||
// 400-year cycle; ensure we're between 0-400 years
|
||||
isoyear %= 400;
|
||||
if(isoyear < 0) isoyear += 400;
|
||||
|
||||
// domain check
|
||||
maxwk = (((isoyear % 7) == 52) || ((isoyear % 28) == 24)) ? 53 : 52;
|
||||
if(wday < 1 || wday > 7 || week < 1 || week > maxwk) {
|
||||
errno = EDOM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Algorithm notes:
|
||||
* We now compute the offset between the start day of the ISO year and the start day of the
|
||||
* real year. Year 0000 starts on a Saturday, meaning the ISO year 0000 starts on 0000-003
|
||||
|
@ -346,6 +369,60 @@ int iso8601_from_week(struct iso8601_date* date, int isoyear, int week, int wday
|
|||
|
||||
|
||||
|
||||
void iso8601_to_clocktime(int* hour, int* min, int* sec, const struct iso8601_date* date)
|
||||
{
|
||||
div_t qr;
|
||||
|
||||
// two special cases: leap second and midnight
|
||||
switch(date->sec) {
|
||||
case 86400:
|
||||
*hour = 23;
|
||||
*min = 59;
|
||||
*sec = 60;
|
||||
return;
|
||||
|
||||
case 86401:
|
||||
*hour = 24;
|
||||
*min = 0;
|
||||
*sec = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
// normal case
|
||||
qr = div(date->sec, 3600);
|
||||
*hour = qr.quot;
|
||||
qr = div(qr.rem, 60);
|
||||
*min = qr.quot;
|
||||
*sec = qr.rem;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int iso8601_from_clocktime(struct iso8601_date* date, int hour, int min, int sec)
|
||||
{
|
||||
// two special cases: leap second and midnight
|
||||
if(hour == 23 && min == 59 && sec == 60) {
|
||||
date->sec = 86400;
|
||||
return 0;
|
||||
}
|
||||
if(hour == 24 && !min && !sec) {
|
||||
date->sec = 86401;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// domain check
|
||||
if(hour < 0 || hour > 23 || min < 0 || min > 59 || sec < 0 || sec > 59) {
|
||||
errno = EDOM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// normal calculation
|
||||
date->sec = hour * 3600 + min * 60 + sec;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* options for text editors
|
||||
kate: replace-trailing-space-save true; space-indent true; tab-width 4;
|
||||
vim: expandtab:ts=4:sw=4
|
||||
|
|
|
@ -24,6 +24,8 @@ void iso8601_to_ord(int* year, int* oday, const struct iso8601_date* date);
|
|||
int iso8601_from_ord(struct iso8601_date* date, int year, int oday);
|
||||
void iso8601_to_week(int* year, int* week, int* wday, const struct iso8601_date* date);
|
||||
int iso8601_from_week(struct iso8601_date* date, int year, int week, int wday);
|
||||
void iso8601_to_clocktime(int* hour, int* min, int* sec, const struct iso8601_date* date);
|
||||
int iso8601_from_clocktime(struct iso8601_date* date, int hour, int min, int sec);
|
||||
|
||||
/* print.c */
|
||||
void iso8601_print(char* str, int amt, const struct iso8601_date* date,
|
||||
|
|
|
@ -35,7 +35,8 @@ 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 y = 0, m = 0, d = 0, w = 0, wd = 0, 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;
|
||||
|
||||
if(earliest) memset(earliest, 0, sizeof(struct iso8601_date));
|
||||
if(latest) memset(latest, 0, sizeof(struct iso8601_date));
|
||||
|
@ -520,7 +521,114 @@ done:
|
|||
if(neg) y *= -1;
|
||||
if(tz_neg) tz_sec *= -1;
|
||||
|
||||
// TODO
|
||||
if(m != -1) {
|
||||
if(d == -1) {
|
||||
if(earliest && iso8601_from_cal(earliest, y, m, 1)) return -1;
|
||||
if(latest && iso8601_from_cal(latest, y, m, _days_in_month(y, m))) return -1;
|
||||
if(details) details->date_prec = iso8601_prec_month;
|
||||
|
||||
} else {
|
||||
if(earliest && iso8601_from_cal(earliest, y, m, d)) return -1;
|
||||
if(latest && iso8601_from_cal(latest, y, m, d)) return -1;
|
||||
if(details) details->date_prec = iso8601_prec_day;
|
||||
|
||||
}
|
||||
|
||||
} else if(d != -1) {
|
||||
if(earliest && iso8601_from_ord(earliest, y, d)) return -1;
|
||||
if(latest && iso8601_from_ord(latest, y, d)) return -1;
|
||||
if(details) details->date_prec = iso8601_prec_ord;
|
||||
|
||||
} else if(w != -1) {
|
||||
if(wd == -1) {
|
||||
if(earliest && iso8601_from_week(earliest, y, w, 1)) return -1;
|
||||
if(latest && iso8601_from_week(latest, y, w, 7)) return -1;
|
||||
if(details) details->date_prec = iso8601_prec_week;
|
||||
|
||||
} else {
|
||||
if(earliest && iso8601_from_week(earliest, y, w, wd)) return -1;
|
||||
if(latest && iso8601_from_week(latest, y, w, wd)) return -1;
|
||||
if(details) details->date_prec = iso8601_prec_wday;
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
if(earliest && iso8601_from_cal(earliest, y, 1, 1)) return -1;
|
||||
if(latest && iso8601_from_cal(latest, y, 12, 31)) return -1;
|
||||
if(details) details->date_prec = iso8601_prec_year;
|
||||
|
||||
}
|
||||
|
||||
if(nsec_dig != -1) while(nsec_dig++ < 9) nsec *= 10;
|
||||
|
||||
if(hour == -1) {
|
||||
if(earliest && iso8601_from_clocktime(earliest, 0, 0, 0)) return -1;
|
||||
if(latest && iso8601_from_clocktime(latest, 24, 0, 0)) return -1;
|
||||
if(details) details->time_prec = iso8601_prec_none;
|
||||
|
||||
} else if(sec != -1) {
|
||||
if(earliest && iso8601_from_clocktime(earliest, hour, min, sec)) return -1;
|
||||
if(latest && iso8601_from_clocktime(latest, hour, min, sec)) return -1;
|
||||
|
||||
if(nsec_dig == -1) {
|
||||
if(latest) latest->nsec = 999999999;
|
||||
if(details) details->time_prec = iso8601_prec_sec;
|
||||
|
||||
} else {
|
||||
if(earliest) earliest->nsec = nsec;
|
||||
if(latest) latest->nsec = nsec;
|
||||
if(details) details->time_prec = iso8601_prec_secfrac;
|
||||
|
||||
}
|
||||
|
||||
} else if(min != -1) {
|
||||
if(nsec_dig == -1) {
|
||||
if(earliest && iso8601_from_clocktime(earliest, hour, min, 0)) return -1;
|
||||
if(latest && iso8601_from_clocktime(latest, hour, min, 59)) return -1;
|
||||
if(latest) latest->nsec = 999999999;
|
||||
if(details) details->time_prec = iso8601_prec_min;
|
||||
|
||||
} else {
|
||||
frac = nsec * 60.0 / 1e9;
|
||||
sec = (int)frac;
|
||||
nsec = (frac - sec) * 1e9;
|
||||
if(earliest && iso8601_from_clocktime(earliest, hour, min, sec)) return -1;
|
||||
if(earliest) earliest->nsec = nsec;
|
||||
if(latest && iso8601_from_clocktime(latest, hour, min, sec)) return -1;
|
||||
if(latest) latest->nsec = nsec;
|
||||
if(details) details->time_prec = iso8601_prec_minfrac;
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
if(nsec_dig == -1) {
|
||||
if(earliest && iso8601_from_clocktime(earliest, hour, 0, 0)) return -1;
|
||||
if(latest && iso8601_from_clocktime(latest, hour, 59, 59)) return -1;
|
||||
if(latest) latest->nsec = 999999999;
|
||||
if(details) details->time_prec = iso8601_prec_hour;
|
||||
|
||||
} else {
|
||||
frac = nsec * 60.0 / 1e9;
|
||||
min = (int)frac;
|
||||
frac -= min;
|
||||
frac *= 60;
|
||||
sec = (int)frac;
|
||||
nsec = (frac - sec) * 1e9;
|
||||
if(earliest && iso8601_from_clocktime(earliest, hour, min, sec)) return -1;
|
||||
if(earliest) earliest->nsec = nsec;
|
||||
if(latest && iso8601_from_clocktime(latest, hour, min, sec)) return -1;
|
||||
if(latest) latest->nsec = nsec;
|
||||
if(details) details->time_prec = iso8601_prec_hourfrac;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if(details) details->tz_sec = tz_sec;
|
||||
if(earliest) iso8601_add_seconds(earliest, -tz_sec);
|
||||
if(latest) iso8601_add_seconds(latest, -tz_sec);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -114,17 +114,17 @@ void iso8601_print(char* str, int amt, const struct iso8601_date* date,
|
|||
|
||||
case iso8601_prec_hourfrac:
|
||||
frac = y + m / 60.0 + (d + date->nsec / 1e9) / 3600.0;
|
||||
ret = snprintf(str, amt, "T%#09.6f", frac);
|
||||
ret = snprintf(str, amt, "T%#012.9f", frac);
|
||||
break;
|
||||
|
||||
case iso8601_prec_minfrac:
|
||||
frac = m + (d + date->nsec / 1e9) / 60.0;
|
||||
ret = snprintf(str, amt, extended ? "T%02d:%#09.6f" : "T%02d%#09.6f", y, frac);
|
||||
ret = snprintf(str, amt, extended ? "T%02d:%#012.9f" : "T%02d%#012.9f", y, frac);
|
||||
break;
|
||||
|
||||
case iso8601_prec_secfrac:
|
||||
frac = d + date->nsec / 1e9;
|
||||
ret = snprintf(str, amt, extended ? "T%02d:%02d:%#09.6f" : "T%02d%02d%#09.6f", y, m, frac);
|
||||
ret = snprintf(str, amt, extended ? "T%02d:%02d:%#012.9f" : "T%02d%02d%#012.9f", y, m, frac);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -15,25 +15,39 @@
|
|||
int do_date(const char* str)
|
||||
{
|
||||
struct iso8601_date earliest, latest;
|
||||
struct iso8601_details details;
|
||||
char buf[100], buf2[100];
|
||||
struct iso8601_details details, fulldetails;
|
||||
char buf[100], buf2[100], buf3[100], buf4[100];
|
||||
|
||||
if(iso8601_parse(str, &earliest, &latest, &details)) {
|
||||
perror("iso8601_parse");
|
||||
return 1;
|
||||
}
|
||||
|
||||
memset(&fulldetails, 0, sizeof(fulldetails));
|
||||
switch((fulldetails.date_prec = details.date_prec)) {
|
||||
case iso8601_prec_month:
|
||||
case iso8601_prec_year:
|
||||
fulldetails.date_prec = iso8601_prec_day;
|
||||
break;
|
||||
case iso8601_prec_week:
|
||||
fulldetails.date_prec = iso8601_prec_wday;
|
||||
break;
|
||||
}
|
||||
fulldetails.time_prec = iso8601_prec_secfrac;
|
||||
|
||||
iso8601_print(buf, sizeof(buf), &earliest, &details);
|
||||
iso8601_print(buf2, sizeof(buf2), &latest, &details);
|
||||
iso8601_print(buf2, sizeof(buf2), &earliest, &fulldetails);
|
||||
iso8601_print(buf3, sizeof(buf3), &latest, &details);
|
||||
iso8601_print(buf4, sizeof(buf4), &latest, &fulldetails);
|
||||
|
||||
printf("Results for ``%s'':\n"
|
||||
" Earliest: day=%d, sec=%05d, nsec=%09d; %s\n"
|
||||
" Latest : day=%d, sec=%05d, nsec=%09d; %s\n"
|
||||
" Earliest: day=%d, sec=%05d, nsec=%09d; %-20s %s\n"
|
||||
" Latest : day=%d, sec=%05d, nsec=%09d; %-20s %s\n"
|
||||
" Details : date_prec=%d, time_prec=%d, extended=%d, tz_sec=%d\n"
|
||||
"\n",
|
||||
str,
|
||||
earliest.day, earliest.sec, earliest.nsec, buf,
|
||||
latest.day, latest.sec, latest.nsec, buf2,
|
||||
earliest.day, earliest.sec, earliest.nsec, buf, buf2,
|
||||
latest.day, latest.sec, latest.nsec, buf3, buf4,
|
||||
details.date_prec, details.time_prec, details.extended, details.tz_sec);
|
||||
|
||||
return 0;
|
||||
|
|
Loading…
Reference in New Issue