From b2321a7567340ff285cfcde5f9b4c7e60be7374d Mon Sep 17 00:00:00 2001
From: Frederic Culot <calcurse@culot.org>
Date: Mon, 8 Mar 2010 08:44:28 +0000
Subject: Patch to correct the wrong calculation of recurrent items' dates
 after a turn of year (submitted by Lukas Fleischer, thanks!).

---
 src/calendar.c |  5 ++--
 src/calendar.h | 12 +++++++--
 src/recur.c    | 81 +++++++++++++++++++++++++++++++++++++++++++++++++++++-----
 src/vars.h     |  9 ++-----
 4 files changed, 88 insertions(+), 19 deletions(-)

(limited to 'src')

diff --git a/src/calendar.c b/src/calendar.c
index 2c6c781..2be7c62 100755
--- a/src/calendar.c
+++ b/src/calendar.c
@@ -1,9 +1,9 @@
-/*	$calcurse: calendar.c,v 1.31 2010/03/01 18:55:45 culot Exp $	*/
+/*	$calcurse: calendar.c,v 1.32 2010/03/08 08:44:44 culot Exp $	*/
 
 /*
  * Calcurse - text-based organizer
  *
- * Copyright (c) 2004-2009 Frederic Culot <frederic@culot.org>
+ * Copyright (c) 2004-2010 Frederic Culot <frederic@culot.org>
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -64,7 +64,6 @@
 #define	lzero	  318.351648	/* lunar mean long at EPOCH */
 #define	Pzero	  36.340410	/* lunar mean long of perigee at EPOCH */
 #define	Nzero	  318.510107	/* lunar mean long of node at EPOCH */
-#define TM_YEAR_BASE	1900
 
 #define isleap(y) ((((y) % 4) == 0 && ((y) % 100) != 0) || ((y) % 400) == 0)
 
diff --git a/src/calendar.h b/src/calendar.h
index 60499a7..e900bcd 100755
--- a/src/calendar.h
+++ b/src/calendar.h
@@ -1,9 +1,9 @@
-/*	$calcurse: calendar.h,v 1.18 2009/10/28 15:15:43 culot Exp $	*/
+/*	$calcurse: calendar.h,v 1.19 2010/03/08 08:44:44 culot Exp $	*/
 
 /*
  * Calcurse - text-based organizer
  *
- * Copyright (c) 2004-2009 Frederic Culot <frederic@culot.org>
+ * Copyright (c) 2004-2010 Frederic Culot <frederic@culot.org>
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -60,6 +60,14 @@
 #define	CALHEIGHT	12
 #define	CALWIDTH	30
 
+#define DAYINSEC        86400
+#define HOURINSEC       3600
+#define MININSEC        60
+#define YEARINDAYS      365
+#define YEARINMONTHS    12
+#define WEEKINDAYS      7
+#define TM_YEAR_BASE    1900
+
 typedef enum
 {				/* days of week */
   SUNDAY,
diff --git a/src/recur.c b/src/recur.c
index e21bf0c..5d06726 100755
--- a/src/recur.c
+++ b/src/recur.c
@@ -1,9 +1,9 @@
-/*	$calcurse: recur.c,v 1.52 2009/07/19 08:20:01 culot Exp $	*/
+/*	$calcurse: recur.c,v 1.53 2010/03/08 08:44:44 culot Exp $	*/
 
 /*
  * Calcurse - text-based organizer
  *
- * Copyright (c) 2004-2009 Frederic Culot <frederic@culot.org>
+ * Copyright (c) 2004-2010 Frederic Culot <frederic@culot.org>
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -55,6 +55,7 @@ struct recur_event_s             *recur_elist;
 static struct recur_event_s       bkp_cut_recur_event;
 static recur_apoint_llist_node_t  bkp_cut_recur_apoint;
 
+
 static void
 free_exc (struct days_s *exc)
 {
@@ -589,11 +590,78 @@ recur_save_data (FILE *f)
   pthread_mutex_unlock (&(recur_alist_p->mutex));
 }
 
+
+/*
+ * The two following defines together with the diff_days, diff_weeks,
+ * diff_months and diff_years functions were provided by Lukas Fleischer to
+ * correct the wrong calculation of recurrent dates after a turn of year.
+ */
+#define bc(start, end, bs)                                              \
+  (((end) - (start) + ((start) % bs) - ((end) % bs)) / bs               \
+   + ((((start) % bs) == 0) ? 1 : 0))
+
+#define leapcount(start, end)                                           \
+  (bc(start, end, 4) - bc(start, end, 100) + bc(start, end, 400))
+
+
+/* Calculate the difference in days between two dates. */
+static long
+diff_days (struct tm lt_start, struct tm lt_end)
+{
+  long diff;
+
+  if (lt_end.tm_year < lt_start.tm_year)
+    return 0;
+
+  diff = lt_end.tm_yday - lt_start.tm_yday;
+
+  if (lt_end.tm_year > lt_start.tm_year)
+    {
+      diff += (lt_end.tm_year - lt_start.tm_year) * YEARINDAYS;
+      diff += leapcount (lt_start.tm_year + TM_YEAR_BASE,
+                         lt_end.tm_year + TM_YEAR_BASE - 1);
+    }
+
+  return diff;
+}
+
+/* Calculate the difference in weeks between two dates. */
+static long
+diff_weeks (struct tm lt_start, struct tm lt_end)
+{
+  return diff_days (lt_start, lt_end) / WEEKINDAYS;
+}
+
+/* Calculate the difference in months between two dates. */
+static long
+diff_months (struct tm lt_start, struct tm lt_end)
+{
+  long diff;
+
+  if (lt_end.tm_year < lt_start.tm_year)
+    return 0;
+
+  diff = lt_end.tm_mon - lt_start.tm_mon;
+  diff += (lt_end.tm_year - lt_start.tm_year) * YEARINMONTHS;
+
+  return diff;
+}
+
+/* Calculate the difference in years between two dates. */
+static long
+diff_years (struct tm lt_start, struct tm lt_end)
+{
+  return lt_end.tm_year - lt_start.tm_year;
+}
+
 /* 
  * Check if the recurrent item belongs to the selected day,
  * and if yes, return the real start time.
+ *
  * This function was improved thanks to Tony's patch.
  * Thanks also to youshe for reporting daylight saving time related problems.
+ * And finally thanks to Lukas for providing a patch to correct the wrong
+ * calculation of recurrent dates after a turn of years.
  */
 unsigned
 recur_item_inday (long item_start, struct days_s *item_exc, int rpt_type,
@@ -625,7 +693,7 @@ recur_item_inday (long item_start, struct days_s *item_exc, int rpt_type,
   switch (rpt_type)
     {
     case RECUR_DAILY:
-      diff = lt_day.tm_yday - lt_item.tm_yday;
+      diff = diff_days (lt_item, lt_day);
       if (diff % rpt_freq != 0)
 	return (0);
       lt_item.tm_mday = lt_day.tm_mday;
@@ -637,7 +705,7 @@ recur_item_inday (long item_start, struct days_s *item_exc, int rpt_type,
 	return (0);
       else
 	{
-	  diff = ((lt_day.tm_yday - lt_item.tm_yday) / WEEKINDAYS);
+          diff = diff_weeks (lt_item, lt_day);
 	  if (diff % rpt_freq != 0)
 	    return (0);
 	}
@@ -646,15 +714,14 @@ recur_item_inday (long item_start, struct days_s *item_exc, int rpt_type,
       lt_item.tm_year = lt_day.tm_year;
       break;
     case RECUR_MONTHLY:
-      diff = (((lt_day.tm_year - lt_item.tm_year) * 12)
-              + (lt_day.tm_mon - lt_item.tm_mon));
+      diff = diff_months (lt_item, lt_day);
       if (diff % rpt_freq != 0)
 	return (0);
       lt_item.tm_mon = lt_day.tm_mon;
       lt_item.tm_year = lt_day.tm_year;
       break;
     case RECUR_YEARLY:
-      diff = lt_day.tm_year - lt_item.tm_year;
+      diff = diff_years (lt_item, lt_day);
       if (diff % rpt_freq != 0)
 	return (0);
       lt_item.tm_year = lt_day.tm_year;
diff --git a/src/vars.h b/src/vars.h
index 7f45c98..fbb88c1 100755
--- a/src/vars.h
+++ b/src/vars.h
@@ -1,9 +1,9 @@
-/*	$calcurse: vars.h,v 1.37 2009/08/01 13:31:21 culot Exp $	*/
+/*	$calcurse: vars.h,v 1.38 2010/03/08 08:44:44 culot Exp $	*/
 
 /*
  * Calcurse - text-based organizer
  *
- * Copyright (c) 2004-2009 Frederic Culot <frederic@culot.org>
+ * Copyright (c) 2004-2010 Frederic Culot <frederic@culot.org>
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -82,11 +82,6 @@
 #define ATTR_HIGH	5
 #define ATTR_HIGHEST	6
 
-#define DAYINSEC  	86400
-#define HOURINSEC	3600
-#define MININSEC	60
-#define WEEKINDAYS	7
-
 #define STATUSHEIGHT	2
 #define	NOTESIZ		6
 
-- 
cgit v1.2.3-70-g09d2