Add support for ordinal date formats.
This commit is contained in:
parent
d1fd6453b8
commit
19d55ad54c
|
@ -69,10 +69,9 @@ static const struct monthcount _days_in_month_leap[] = {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void iso8601_to_cal(int* year, int* month, int* day, const struct iso8601_date* date)
|
static void _to_year(int* year, int* days_left, const struct iso8601_date* date)
|
||||||
{
|
{
|
||||||
div_t qr;
|
div_t qr;
|
||||||
const struct monthcount* mc;
|
|
||||||
int ndays = date->day;
|
int ndays = date->day;
|
||||||
|
|
||||||
// Each 400 years have 97 leap days, giving 365*400+97 = 146097 days in 400 years
|
// Each 400 years have 97 leap days, giving 365*400+97 = 146097 days in 400 years
|
||||||
|
@ -111,6 +110,19 @@ void iso8601_to_cal(int* year, int* month, int* day, const struct iso8601_date*
|
||||||
ndays = qr.rem;
|
ndays = qr.rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
*days_left = ndays;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void iso8601_to_cal(int* year, int* month, int* day, const struct iso8601_date* date)
|
||||||
|
{
|
||||||
|
const struct monthcount* mc;
|
||||||
|
int ndays;
|
||||||
|
|
||||||
|
// perform year calulation
|
||||||
|
_to_year(year, &ndays, date);
|
||||||
|
|
||||||
// now we simply have number of days elapsed since day 001 in `year'.
|
// now we simply have number of days elapsed since day 001 in `year'.
|
||||||
mc = iso8601_isleap(*year) ? _days_in_month_leap : _days_in_month_common;
|
mc = iso8601_isleap(*year) ? _days_in_month_leap : _days_in_month_common;
|
||||||
*month = 1;
|
*month = 1;
|
||||||
|
@ -124,20 +136,26 @@ void iso8601_to_cal(int* year, int* month, int* day, const struct iso8601_date*
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int iso8601_from_cal(struct iso8601_date* date, int year, int month, int day)
|
void iso8601_to_ord(int* year, int* oday, const struct iso8601_date* date)
|
||||||
{
|
{
|
||||||
div_t qr;
|
int ndays;
|
||||||
const struct monthcount* mc;
|
|
||||||
|
|
||||||
// check for range / domain errors
|
// perform year calcutation
|
||||||
if(year < -5879609 || year > 5879609) {
|
_to_year(year, &ndays, date);
|
||||||
errno = ERANGE;
|
|
||||||
return -1;
|
// now we simply have number of days elapsed since day 001 in `year'.
|
||||||
|
*oday = ndays + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
mc = iso8601_isleap(year) ? _days_in_month_leap : _days_in_month_common;
|
|
||||||
if(month < 1 || month > 12 || day < 0 || day > mc[month - 1].days) {
|
|
||||||
errno = EDOM;
|
int _from_year(struct iso8601_date* date, int year)
|
||||||
|
{
|
||||||
|
div_t qr;
|
||||||
|
|
||||||
|
// check for range errors
|
||||||
|
if(year < -5879609 || year > 5879609) {
|
||||||
|
errno = ERANGE;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -156,6 +174,24 @@ int iso8601_from_cal(struct iso8601_date* date, int year, int month, int day)
|
||||||
date->day += 365 * year;
|
date->day += 365 * year;
|
||||||
date->day += (year + 3) / 4; // there is one leap year for every four years
|
date->day += (year + 3) / 4; // there is one leap year for every four years
|
||||||
date->day -= (year - 1) / 100; // but one less for every century over 0
|
date->day -= (year - 1) / 100; // but one less for every century over 0
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int iso8601_from_cal(struct iso8601_date* date, int year, int month, int day)
|
||||||
|
{
|
||||||
|
const struct monthcount* mc;
|
||||||
|
|
||||||
|
// 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) {
|
||||||
|
errno = EDOM;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// perform year calculation
|
||||||
|
if(_from_year(date, year)) return -1;
|
||||||
|
|
||||||
// now get number of days elapsed up to start of month
|
// now get number of days elapsed up to start of month
|
||||||
date->day += mc[month - 1].elapsed;
|
date->day += mc[month - 1].elapsed;
|
||||||
|
|
|
@ -49,7 +49,13 @@ void iso8601_print(char* str, int amt, const struct iso8601_date* date,
|
||||||
case iso8601_prec_day:
|
case iso8601_prec_day:
|
||||||
iso8601_to_cal(&y, &m, &d, &dttz);
|
iso8601_to_cal(&y, &m, &d, &dttz);
|
||||||
if(y < 0) ret = snprintf(str, amt, "%05d-%02d-%02d", y, m, d);
|
if(y < 0) ret = snprintf(str, amt, "%05d-%02d-%02d", y, m, d);
|
||||||
ret = snprintf(str, amt, extended ? "%04d-%02d-%02d" : "%04d%02d%02d", y, m, d);
|
else ret = snprintf(str, amt, extended ? "%04d-%02d-%02d" : "%04d%02d%02d", y, m, d);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case iso8601_prec_ord:
|
||||||
|
iso8601_to_ord(&y, &d, &dttz);
|
||||||
|
if(y < 0) ret = snprintf(str, amt, "%05d-%03d", y, d);
|
||||||
|
else ret = snprintf(str, amt, extended ? "%04d-%03d" : "%04d%03d", y, d);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -127,6 +127,21 @@ void do_details_utc_year(struct iso8601_details* dt_out, const struct iso8601_de
|
||||||
dt_out->date_prec = iso8601_prec_year;
|
dt_out->date_prec = iso8601_prec_year;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void do_details_ordinal_date(struct iso8601_details* dt_out, const struct iso8601_details* dt_in)
|
||||||
|
{
|
||||||
|
memcpy(dt_out, dt_in, sizeof(struct iso8601_details));
|
||||||
|
dt_out->tz_sec = 0;
|
||||||
|
dt_out->date_prec = iso8601_prec_ord;
|
||||||
|
dt_out->time_prec = iso8601_prec_none;
|
||||||
|
}
|
||||||
|
|
||||||
|
void do_details_ordinal(struct iso8601_details* dt_out, const struct iso8601_details* dt_in)
|
||||||
|
{
|
||||||
|
memcpy(dt_out, dt_in, sizeof(struct iso8601_details));
|
||||||
|
dt_out->tz_sec = 0;
|
||||||
|
dt_out->date_prec = iso8601_prec_ord;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
struct test {
|
struct test {
|
||||||
|
@ -152,6 +167,8 @@ const struct test tests[] = {
|
||||||
{ "Local day", do_details_local_day },
|
{ "Local day", do_details_local_day },
|
||||||
{ "Local month", do_details_local_month },
|
{ "Local month", do_details_local_month },
|
||||||
{ "Local year", do_details_local_year },
|
{ "Local year", do_details_local_year },
|
||||||
|
{ "Ordinal date", do_details_ordinal_date },
|
||||||
|
{ "Ordinal full", do_details_ordinal },
|
||||||
{ 0, 0 }
|
{ 0, 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue