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;
|
||||
const struct monthcount* mc;
|
||||
int ndays = date->day;
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
*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'.
|
||||
mc = iso8601_isleap(*year) ? _days_in_month_leap : _days_in_month_common;
|
||||
*month = 1;
|
||||
|
@ -124,23 +136,29 @@ 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)
|
||||
{
|
||||
int ndays;
|
||||
|
||||
// perform year calcutation
|
||||
_to_year(year, &ndays, date);
|
||||
|
||||
// now we simply have number of days elapsed since day 001 in `year'.
|
||||
*oday = ndays + 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _from_year(struct iso8601_date* date, int year)
|
||||
{
|
||||
div_t qr;
|
||||
const struct monthcount* mc;
|
||||
|
||||
// check for range / domain errors
|
||||
// check for range errors
|
||||
if(year < -5879609 || year > 5879609) {
|
||||
errno = ERANGE;
|
||||
return -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;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Each 400 years have 97 leap days, giving 365*400+97 = 146097 days in 400 years
|
||||
qr = div(year, 400);
|
||||
date->day = qr.quot * 146097;
|
||||
|
@ -156,6 +174,24 @@ int iso8601_from_cal(struct iso8601_date* date, int year, int month, int day)
|
|||
date->day += 365 * year;
|
||||
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
|
||||
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
|
||||
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:
|
||||
iso8601_to_cal(&y, &m, &d, &dttz);
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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 {
|
||||
|
@ -152,6 +167,8 @@ const struct test tests[] = {
|
|||
{ "Local day", do_details_local_day },
|
||||
{ "Local month", do_details_local_month },
|
||||
{ "Local year", do_details_local_year },
|
||||
{ "Ordinal date", do_details_ordinal_date },
|
||||
{ "Ordinal full", do_details_ordinal },
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue