Add from-week-date conversion functions
This commit is contained in:
parent
fdd856381d
commit
582b960e0b
|
@ -16,6 +16,8 @@
|
||||||
* of the next day).
|
* of the next day).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#define DAYS_IN_400_YEARS (146097)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int iso8601_isleap(int year)
|
int iso8601_isleap(int year)
|
||||||
|
@ -74,14 +76,14 @@ static void _to_year(int* year, int* days_left, const struct iso8601_date* date)
|
||||||
div_t qr;
|
div_t qr;
|
||||||
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 = DAYS_IN_400_YEARS days in 400 years
|
||||||
qr = div(ndays, 146097);
|
qr = div(ndays, DAYS_IN_400_YEARS);
|
||||||
*year = qr.quot * 400;
|
*year = qr.quot * 400;
|
||||||
ndays = qr.rem;
|
ndays = qr.rem;
|
||||||
|
|
||||||
// ensure that we always end up with between 0 and 146096 days remaining
|
// ensure that we always end up with between 0 and 146096 days remaining
|
||||||
if(ndays < 0) {
|
if(ndays < 0) {
|
||||||
ndays += 146097;
|
ndays += DAYS_IN_400_YEARS;
|
||||||
*year -= 400;
|
*year -= 400;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -250,14 +252,14 @@ int _from_year(struct iso8601_date* date, int year)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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 = DAYS_IN_400_YEARS days in 400 years
|
||||||
qr = div(year, 400);
|
qr = div(year, 400);
|
||||||
date->day = qr.quot * 146097;
|
date->day = qr.quot * DAYS_IN_400_YEARS;
|
||||||
year = qr.rem;
|
year = qr.rem;
|
||||||
|
|
||||||
// ensure we have between 0 and 399 years
|
// ensure we have between 0 and 399 years
|
||||||
if(year < 0) {
|
if(year < 0) {
|
||||||
date->day -= 146097;
|
date->day -= DAYS_IN_400_YEARS;
|
||||||
year += 400;
|
year += 400;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -316,6 +318,28 @@ 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 iso8601_from_week(struct iso8601_date* date, int isoyear, int week, int wday)
|
||||||
{
|
{
|
||||||
|
int day1off;
|
||||||
|
|
||||||
|
_from_year(date, isoyear);
|
||||||
|
|
||||||
|
// 400-year cycle; ensure we're between 0-400 years
|
||||||
|
isoyear %= 400;
|
||||||
|
if(isoyear < 0) isoyear += 400;
|
||||||
|
|
||||||
|
/* 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
|
||||||
|
* (offset of +2 days). Each year reduces the offset by one day, and each leap year reduces it
|
||||||
|
* by a further day; the offset wraps from -3 to +3.
|
||||||
|
*/
|
||||||
|
day1off = 2 - isoyear; // reduce offset by 1 for each year
|
||||||
|
day1off += (isoyear - 1) / 100; // cancel out 1 leap year for each century past the first
|
||||||
|
day1off -= (isoyear + 3) / 4; // 1 leap year every 4 years
|
||||||
|
day1off %= 7;
|
||||||
|
if(day1off < -3) day1off += 7;
|
||||||
|
|
||||||
|
// now simply add in the day offset and days/weeks elapsed
|
||||||
|
date->day += day1off + (week - 1) * 7 + wday - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -128,7 +128,7 @@ int try_weeks(void)
|
||||||
// starting position
|
// starting position
|
||||||
int weekcount = 52, weekday = 5, isoyear = -1;
|
int weekcount = 52, weekday = 5, isoyear = -1;
|
||||||
int y, wk, wd, ret = 0;
|
int y, wk, wd, ret = 0;
|
||||||
struct iso8601_date dt;
|
struct iso8601_date dt, dt2;
|
||||||
|
|
||||||
for(dt.day = 0; dt.day < MAX_YEAR_COUNT * 366; ++dt.day) {
|
for(dt.day = 0; dt.day < MAX_YEAR_COUNT * 366; ++dt.day) {
|
||||||
iso8601_to_week(&y, &wk, &wd, &dt);
|
iso8601_to_week(&y, &wk, &wd, &dt);
|
||||||
|
@ -141,9 +141,17 @@ int try_weeks(void)
|
||||||
++isoyear;
|
++isoyear;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(wk != weekcount || y != isoyear) goto discont;
|
|
||||||
|
|
||||||
|
if(wk != weekcount || y != isoyear) goto discont;
|
||||||
weekday = wd;
|
weekday = wd;
|
||||||
|
|
||||||
|
iso8601_from_week(&dt2, isoyear, weekcount, weekday);
|
||||||
|
if(dt2.day != dt.day) {
|
||||||
|
printf("[weekmismatch ] %04d-W%02d-%d: should be %d, got %d\n",
|
||||||
|
isoyear, weekcount, weekday, dt.day, dt2.day);
|
||||||
|
if(++ret > 20) return ret;
|
||||||
|
}
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
discont:
|
discont:
|
||||||
|
|
Loading…
Reference in New Issue