From 5fbc499886e93f681f05b7219c7f844d17eaeb1d Mon Sep 17 00:00:00 2001
From: Lars Henriksen <LarsHenriksen@get2net.dk>
Date: Sun, 23 Jun 2019 21:42:24 +0200
Subject: Fix monthly and yearly recurrence algorithms

The calculation of the year of the most recent occurrence for year dates before
the start date (disregarding the year) is incorrect for frequencies greater than
one. The most recent occurrence (for a date as mentioned) is either too far or
too close in the past. In most cases it does no harm because the most recent
ocurrence is in the past and does not span the date (i.e. there is no occurrence
on the day). But the following appointment shows the presence of the bug:

12/31/2019 @ 12:00 -> 01/01/2020 @ 12:00 {2Y} |new year

The occurence on 1 Jan 2020 is missing, because the most recent occurrence is
too far in the past (31 Dec 2018 instead of 31 Dec 2019). An occurrence appears
on 1 Jan 2021, because the most recent occurence is too close in the past (31
Dec 2020 instead of 31 Dec 2019).

A similar miscalculation affects the monthly rule as proved by

3/31/2019 @ 12:00 -> 4/1/2019 @ 11:00 {2M} |change of month

Signed-off-by: Lars Henriksen <LarsHenriksen@get2net.dk>
Signed-off-by: Lukas Fleischer <lfleischer@calcurse.org>
---
 src/recur.c | 11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)

(limited to 'src')

diff --git a/src/recur.c b/src/recur.c
index fc1d538..1fd01ad 100644
--- a/src/recur.c
+++ b/src/recur.c
@@ -798,17 +798,18 @@ recur_item_find_occurrence(time_t item_start, long item_dur,
 		break;
 	case RECUR_MONTHLY:
 		diff = diff_months(lt_item_day, lt_day) % rpt_freq;
-		if (lt_day.tm_mday < lt_item_day.tm_mday)
-			diff++;
+		if (!diff && lt_day.tm_mday < lt_item_day.tm_mday)
+			diff += rpt_freq;
 		lt_item_day.tm_mon = lt_day.tm_mon - diff;
 		lt_item_day.tm_year = lt_day.tm_year;
 		break;
 	case RECUR_YEARLY:
 		diff = diff_years(lt_item_day, lt_day) % rpt_freq;
-		if (lt_day.tm_mon < lt_item_day.tm_mon ||
+		if (!diff &&
+		    (lt_day.tm_mon < lt_item_day.tm_mon ||
 		    (lt_day.tm_mon == lt_item_day.tm_mon &&
-		     lt_day.tm_mday < lt_item_day.tm_mday))
-			diff++;
+		     lt_day.tm_mday < lt_item_day.tm_mday)))
+			diff += rpt_freq;
 		lt_item_day.tm_year = lt_day.tm_year - diff;
 		break;
 	default:
-- 
cgit v1.2.3-70-g09d2