From 9e160fac16e81c42ac368f450b9cc4df29753e00 Mon Sep 17 00:00:00 2001
From: Lukas Fleischer <lfleischer@calcurse.org>
Date: Sun, 27 Mar 2016 12:54:10 +0200
Subject: Do not assume that days always have 86400 seconds

Make that date membership is computed correctly, even if a day has less
than 86400 seconds (e.g. after changing clocks).

Reported-by: Hakan Jerning <jerning@home.se>
Signed-off-by: Lukas Fleischer <lfleischer@calcurse.org>
---
 src/apoint.c               |  3 +--
 src/calcurse.h             |  1 +
 src/event.c                |  2 +-
 src/recur.c                |  4 ++--
 src/utils.c                | 24 ++++++++++++++++++++++++
 test/Makefile.am           |  2 ++
 test/data/apts-regress-001 |  1 +
 test/regress-001.sh        | 15 +++++++++++++++
 8 files changed, 47 insertions(+), 5 deletions(-)
 create mode 100644 test/data/apts-regress-001
 create mode 100755 test/regress-001.sh

diff --git a/src/apoint.c b/src/apoint.c
index cb23ead..409e889 100644
--- a/src/apoint.c
+++ b/src/apoint.c
@@ -119,8 +119,7 @@ struct apoint *apoint_new(char *mesg, char *note, long start, long dur,
 
 unsigned apoint_inday(struct apoint *i, long *start)
 {
-	return (i->start <= *start + DAYINSEC
-		&& i->start + i->dur > *start);
+	return (date_cmp_day(i->start, *start) == 0);
 }
 
 void apoint_sec2str(struct apoint *o, long day, char *start, char *end)
diff --git a/src/calcurse.h b/src/calcurse.h
index d337145..3aab885 100644
--- a/src/calcurse.h
+++ b/src/calcurse.h
@@ -1111,6 +1111,7 @@ int get_item_min(long);
 struct tm date2tm(struct date, unsigned, unsigned);
 time_t date2sec(struct date, unsigned, unsigned);
 time_t utcdate2sec(struct date, unsigned, unsigned);
+int date_cmp_day(time_t, time_t);
 char *date_sec2date_str(long, const char *);
 void date_sec2date_fmt(long, const char *, char *);
 int date_change(struct tm *, int, int);
diff --git a/src/event.c b/src/event.c
index ad26f19..4f6965c 100644
--- a/src/event.c
+++ b/src/event.c
@@ -107,7 +107,7 @@ struct event *event_new(char *mesg, char *note, long day, int id)
 /* Check if the event belongs to the selected day */
 unsigned event_inday(struct event *i, long *start)
 {
-	return (i->day < *start + DAYINSEC && i->day >= *start);
+	return (date_cmp_day(i->day, *start) == 0);
 }
 
 char *event_tostr(struct event *o)
diff --git a/src/recur.c b/src/recur.c
index 186acbe..10a2623 100644
--- a/src/recur.c
+++ b/src/recur.c
@@ -683,7 +683,7 @@ static long diff_years(struct tm lt_start, struct tm lt_end)
 
 static int exc_inday(struct excp *exc, long *day_start)
 {
-	return (exc->st >= *day_start && exc->st < *day_start + DAYINSEC);
+	return (date_cmp_day(exc->st, *day_start) == 0);
 }
 
 /*
@@ -706,7 +706,7 @@ recur_item_find_occurrence(long item_start, long item_dur,
 	struct tm lt_day, lt_item, lt_item_day;
 	time_t t;
 
-	if (day_start < item_start - DAYINSEC + 1)
+	if (date_cmp_day(day_start, item_start) < 0)
 		return 0;
 
 	if (rpt_until != 0 && day_start >= rpt_until + item_dur)
diff --git a/src/utils.c b/src/utils.c
index 4300b59..50f2507 100644
--- a/src/utils.c
+++ b/src/utils.c
@@ -418,6 +418,30 @@ time_t utcdate2sec(struct date day, unsigned hour, unsigned min)
 	return t;
 }
 
+/* Compare two dates (without comparing times). */
+int date_cmp_day(time_t d1, time_t d2)
+{
+	struct tm lt1, lt2;
+
+	localtime_r((time_t *)&d1, &lt1);
+	localtime_r((time_t *)&d2, &lt2);
+
+	if (lt1.tm_year < lt2.tm_year)
+		return -1;
+	if (lt1.tm_year > lt2.tm_year)
+		return 1;
+	if (lt1.tm_mon < lt2.tm_mon)
+		return -1;
+	if (lt1.tm_mon > lt2.tm_mon)
+		return 1;
+	if (lt1.tm_mday < lt2.tm_mday)
+		return -1;
+	if (lt1.tm_mday > lt2.tm_mday)
+		return 1;
+
+	return 0;
+}
+
 /* Return a string containing the date, given a date in seconds. */
 char *date_sec2date_str(long sec, const char *datefmt)
 {
diff --git a/test/Makefile.am b/test/Makefile.am
index efc3d12..f8d6088 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -52,6 +52,7 @@ TESTS = \
 	next-001.sh \
 	search-001.sh \
 	bug-002.sh \
+	regress-001.sh \
 	recur-001.sh \
 	recur-002.sh \
 	recur-003.sh \
@@ -105,6 +106,7 @@ EXTRA_DIST = \
 	data/apts-event-006 \
 	data/apts-filter-001 \
 	data/apts-recur \
+	data/apts-regress-001 \
 	data/conf \
 	data/ical-001.ical \
 	data/ical-002.ical \
diff --git a/test/data/apts-regress-001 b/test/data/apts-regress-001
new file mode 100644
index 0000000..8eaae31
--- /dev/null
+++ b/test/data/apts-regress-001
@@ -0,0 +1 @@
+03/28/2016 [1] Day after clock adjustment
diff --git a/test/regress-001.sh b/test/regress-001.sh
new file mode 100755
index 0000000..3ad6deb
--- /dev/null
+++ b/test/regress-001.sh
@@ -0,0 +1,15 @@
+#!/bin/sh
+
+. "${TEST_INIT:-./test-init.sh}"
+
+if [ "$1" = 'actual' ]; then
+  "$CALCURSE" --read-only -D "$DATA_DIR"/ -c "$DATA_DIR/apts-regress-001" \
+    -Q --filter-type=cal --from=2016-03-27 --days=2
+elif [ "$1" = 'expected' ]; then
+  cat <<EOD
+03/28/16:
+ * Day after clock adjustment
+EOD
+else
+  ./run-test "$0"
+fi
-- 
cgit v1.2.3-70-g09d2