Add support for ordinal date formats.

This commit is contained in:
Laurence Withers 2006-10-14 23:08:09 +01:00
parent d1fd6453b8
commit 19d55ad54c
3 changed files with 71 additions and 12 deletions

View File

@ -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;

View File

@ -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:

View File

@ -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 }
};