diff options
author | Ken Murchison <murch@fastmail.com> | 2020-11-05 17:21:14 -0500 |
---|---|---|
committer | Ken Murchison <murch@fastmail.com> | 2020-11-05 17:21:14 -0500 |
commit | 03c8fc0ea5a8f16d807d7bdfbf7ef5281f46f408 (patch) | |
tree | 9209336f424e6dab8f69428ad481acd4b0ca2964 | |
parent | 3bfbe8b97a904cc7951c0b82d41d2f4e70f01b8b (diff) | |
download | libical-git-03c8fc0ea5a8f16d807d7bdfbf7ef5281f46f408.tar.gz |
icalrecur.c: properly handle BYWEEKNO=-1, etc
-rw-r--r-- | src/libical/icalrecur.c | 31 |
1 files changed, 19 insertions, 12 deletions
diff --git a/src/libical/icalrecur.c b/src/libical/icalrecur.c index f8f42d71..82793df0 100644 --- a/src/libical/icalrecur.c +++ b/src/libical/icalrecur.c @@ -1052,6 +1052,17 @@ static void setup_defaults(icalrecur_iterator *impl, } } +/** Calculate ISO weeks per year + https://en.wikipedia.org/wiki/ISO_week_date#Weeks_per_year */ +static int weeks_in_year(int year) +{ + /* Long years occur when year starts on Thu or leap year starts on Wed */ + int dow = icaltime_day_of_week(icaltime_from_day_of_year(1, year)); + int is_long = (dow == 5 || (dow == 4 && icaltime_is_leap_year(year))); + + return (52 + is_long); +} + /** Calculate the number of Gregorian months between 2 dates */ static int __greg_month_diff(icaltimetype a, icaltimetype b) { @@ -1692,17 +1703,6 @@ static int get_day_of_week(icalrecur_iterator *impl) return icaltime_day_of_week(impl->last); } -/** Calculate ISO weeks per year - https://en.wikipedia.org/wiki/ISO_week_date#Weeks_per_year */ -static int weeks_in_year(int year) -{ - /* Long years occur when year starts on Thu or leap year starts on Wed */ - int dow = icaltime_day_of_week(icaltime_from_day_of_year(1, year)); - int is_long = (dow == 5 || (dow == 4 && icaltime_is_leap_year(year))); - - return (52 + is_long); -} - /** Calculate ISO week number https://en.wikipedia.org/wiki/ISO_week_date#Calculation */ static int get_week_number(icalrecur_iterator *impl, struct icaltimetype tt) @@ -2421,11 +2421,14 @@ static int expand_by_day(icalrecur_iterator *impl, int year, if (has_by_data(impl, BY_WEEK_NO)) { /* Make sure our day falls in one of the BYWEEKNO */ + int nweeks = weeks_in_year(year); int j; for (j = 0; BYWEEKPTR[j] != ICAL_RECURRENCE_ARRAY_MAX; j++) { int weekno = BYWEEKPTR[j]; + if (weekno < 0) weekno += nweeks + 1; + if (weekno == this_weekno) { valid = 1; break; @@ -2747,7 +2750,7 @@ static int expand_year_days(icalrecur_iterator *impl, int year) } } else if (has_by_data(impl, BY_WEEK_NO)) { - int weekno, start_doy; + int nweeks, weekno, start_doy; /* We only support BYWEEKNO + BYDAY */ if (has_by_data(impl, BY_YEAR_DAY) || @@ -2759,6 +2762,8 @@ static int expand_year_days(icalrecur_iterator *impl, int year) /* BYWEEKNO + BYDAY handled below */ if (!has_by_data(impl, BY_DAY)) { + nweeks = weeks_in_year(year); + /* Calculate location of DTSTART day in weekno 1 */ doy = get_day_of_year(impl, year, impl->dtstart.month, impl->dtstart.day, NULL); @@ -2770,6 +2775,8 @@ static int expand_year_days(icalrecur_iterator *impl, int year) for (i = 0; BYWEEKPTR[i] != ICAL_RECURRENCE_ARRAY_MAX; i++) { weekno = BYWEEKPTR[i]; + if (weekno < 0) weekno += nweeks + 1; + doy = start_doy + 7 * (weekno - 1); daysmask_setbit(impl->days, doy, 1); |