From 2ae30b223ecf79f92bf81af934c40dd645be274c Mon Sep 17 00:00:00 2001
From: Lars Henriksen <LarsHenriksen@get2net.dk>
Date: Wed, 14 Aug 2019 23:32:45 +0200
Subject: Set time-of-day consistently to midnight for until day

A day begins on midnight (inclusive) and ends on midnight (exclusive). A
day as a whole is represented by the initial midnight, i.e. time-of-day
is 00:00.

On load of recurrent appointments (but not events) time-of-day for the
until day is set to 23:59. For a newly created recurrent appointment the
setting depends on the input method: time-of-day is set to 00:00 if
until day is given as a date (day, month and year), but to time-of-day
for the start day if given as an offset (+dd).

The resulting behaviour is only visible in interactive use of calcurse
as proved by the following scenario.

1) Create an appointment with start time 12:00, end time 11:59 (multi
   day).

2) Turn it into a recurrent appointment of type daily, frequency 3,
   until day +3.

The appointment is correctly displayed with two 2-day occurrences three
days apart.

3) Edit the appointment and select Repetition. Accept existing type,
   frequency and end day (now as a date).

The second day of the second occurrence disappears.

4) Repeat 3), but set the end day as an offset (+3).

The second day of the second occurrence reappears.

The inconsistencies have been eliminated, and time-of-day for the until
day is now always 00:00.

Also, until day may equal start day, so midnights should be compared.

Signed-off-by: Lars Henriksen <LarsHenriksen@get2net.dk>
Signed-off-by: Lukas Fleischer <lfleischer@calcurse.org>
---
 src/recur.c  |  9 +++++----
 src/ui-day.c | 18 ++++++++++++++----
 2 files changed, 19 insertions(+), 8 deletions(-)

(limited to 'src')

diff --git a/src/recur.c b/src/recur.c
index 1fd01ad..d424bca 100644
--- a/src/recur.c
+++ b/src/recur.c
@@ -433,8 +433,8 @@ struct recur_apoint *recur_apoint_scan(FILE * f, struct tm start,
 	tend = mktime(&end);
 
 	if (until.tm_year != 0) {
-		until.tm_hour = 23;
-		until.tm_min = 59;
+		until.tm_hour = 0;
+		until.tm_min = 0;
 		until.tm_sec = 0;
 		until.tm_isdst = -1;
 		until.tm_year -= 1900;
@@ -768,7 +768,8 @@ recur_item_find_occurrence(time_t item_start, long item_dur,
 	if (date_cmp_day(day_start, item_start) < 0)
 		return 0;
 
-	if (rpt_until != 0 && day_start >= rpt_until + item_dur)
+	if (rpt_until != 0 && day_start >= rpt_until +
+	    (item_start - update_time_in_date(item_start, 0, 0)) + item_dur)
 		return 0;
 
 	t = day_start;
@@ -834,7 +835,7 @@ recur_item_find_occurrence(time_t item_start, long item_dur,
 	if (LLIST_FIND_FIRST(item_exc, &t, exc_inday))
 		return 0;
 
-	if (rpt_until != 0 && t > rpt_until)
+	if (rpt_until != 0 && t >= NEXTDAY(rpt_until))
 		return 0;
 
 	localtime_r(&t, &lt_item_day);
diff --git a/src/ui-day.c b/src/ui-day.c
index 49c47ae..e0e306b 100644
--- a/src/ui-day.c
+++ b/src/ui-day.c
@@ -420,7 +420,11 @@ static void update_rept(struct rpt **rpt, const time_t start, llist_t *exc)
 				keys_wgetch(win[KEY].p);
 				continue;
 			}
-			newuntil = date_sec_change(start, 0, days);
+			/* Until is midnight of the day. */
+			newuntil = date_sec_change(
+					update_time_in_date(start, 0, 0),
+					0, days
+				   );
 		} else {
 			int year, month, day;
 			if (!parse_date(timstr, conf.input_datefmt, &year,
@@ -432,7 +436,8 @@ static void update_rept(struct rpt **rpt, const time_t start, llist_t *exc)
 			struct date d = { day, month, year };
 			newuntil = date2sec(d, 0, 0);
 		}
-		if (newuntil >= start)
+		/* Conmpare days (midnights) - until-day may equal start day. */
+		if (newuntil >= update_time_in_date(start, 0, 0))
 			break;
 
 		mem_free(timstr);
@@ -943,7 +948,11 @@ void ui_day_item_repeat(void)
 				keys_wgetch(win[KEY].p);
 				continue;
 			}
-			until = date_sec_change(p->start, 0, days);
+			/* Until is midnight of the day. */
+			until = date_sec_change(
+					update_time_in_date(p->start, 0, 0),
+					0, days
+				);
 		} else {
 			int year, month, day;
 			if (!parse_date(user_input, conf.input_datefmt,
@@ -955,7 +964,8 @@ void ui_day_item_repeat(void)
 			struct date d = { day, month, year };
 			until = date2sec(d, 0, 0);
 		}
-		if (until >= p->start)
+		/* Compare days (midnights) - until-day may equal start day. */
+		if (until >= get_slctd_day())
 			break;
 
 		datestr = date_sec2date_str(p->start, DATEFMT(conf.input_datefmt));
-- 
cgit v1.2.3-70-g09d2