summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKen Murchison <murch@fastmail.com>2020-11-05 17:21:14 -0500
committerKen Murchison <murch@fastmail.com>2020-11-05 17:21:14 -0500
commit03c8fc0ea5a8f16d807d7bdfbf7ef5281f46f408 (patch)
tree9209336f424e6dab8f69428ad481acd4b0ca2964
parent3bfbe8b97a904cc7951c0b82d41d2f4e70f01b8b (diff)
downloadlibical-git-03c8fc0ea5a8f16d807d7bdfbf7ef5281f46f408.tar.gz
icalrecur.c: properly handle BYWEEKNO=-1, etc
-rw-r--r--src/libical/icalrecur.c31
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);