From 19d55ad54c5aa704fc04f4e9f60245c8f6acbd2a Mon Sep 17 00:00:00 2001 From: Laurence Withers Date: Sat, 14 Oct 2006 23:08:09 +0100 Subject: [PATCH] Add support for ordinal date formats. --- src/libiso8601/calc.c | 58 ++++++++++++++++++++++++++++++++++-------- src/libiso8601/print.c | 8 +++++- src/tests/printer.c | 17 +++++++++++++ 3 files changed, 71 insertions(+), 12 deletions(-) diff --git a/src/libiso8601/calc.c b/src/libiso8601/calc.c index a983f0e..4455bb7 100644 --- a/src/libiso8601/calc.c +++ b/src/libiso8601/calc.c @@ -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; diff --git a/src/libiso8601/print.c b/src/libiso8601/print.c index d306906..5e91723 100644 --- a/src/libiso8601/print.c +++ b/src/libiso8601/print.c @@ -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: diff --git a/src/tests/printer.c b/src/tests/printer.c index f629274..bd5c2b9 100644 --- a/src/tests/printer.c +++ b/src/tests/printer.c @@ -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 } };