src/recur.c: Support recurrent multi-day appointments

Completely rewrite our inday algorithm in recur_item_inday() and be more
fine-grained. This version can deal with recurrent multi-day
appointments unless they overlap.

In case of overlapping appointments, only the last appointment that
starts before the current day is shown. We will need to rewrite the
whole recur_item_inday() interface in order to fix this - this
relatively trivial patch is only the first step.

Signed-off-by: Lukas Fleischer <calcurse@cryptocrack.de>
This commit is contained in:
Lukas Fleischer 2011-10-06 12:23:48 +02:00
parent 2d89d33668
commit 0d51e61f3d

View File

@ -635,74 +635,79 @@ recur_item_inday (long item_start, long item_dur, llist_t *item_exc,
int rpt_type, int rpt_freq, long rpt_until, long day_start) int rpt_type, int rpt_freq, long rpt_until, long day_start)
{ {
struct date start_date; struct date start_date;
long day_end, diff; long diff, span;
struct tm lt_item, lt_day; struct tm lt_day, lt_item, lt_item_day;
time_t t; time_t t;
day_end = day_start + DAYINSEC; if (day_start < item_start - DAYINSEC + 1)
t = day_start;
lt_day = *localtime (&t);
if (LLIST_FIND_FIRST (item_exc, day_start, exc_inday))
return 0; return 0;
if (rpt_until == 0) /* we have an endless recurrent item */ t = day_start;
rpt_until = day_end; lt_day = *localtime (&t);
if (item_start > day_end || rpt_until < day_start)
return (0);
t = item_start; t = item_start;
lt_item = *localtime (&t); lt_item = *localtime (&t);
lt_item_day = lt_item;
lt_item_day.tm_sec = lt_item_day.tm_min = lt_item_day.tm_hour = 0;
span = (item_start - mktime (&lt_item_day) + item_dur - 1) / DAYINSEC;
switch (rpt_type) switch (rpt_type)
{ {
case RECUR_DAILY: case RECUR_DAILY:
diff = diff_days (lt_item, lt_day); diff = diff_days (lt_item_day, lt_day) % rpt_freq;
if (diff % rpt_freq != 0) lt_item_day.tm_mday = lt_day.tm_mday - diff;
return (0); lt_item_day.tm_mon = lt_day.tm_mon;
lt_item.tm_mday = lt_day.tm_mday; lt_item_day.tm_year = lt_day.tm_year;
lt_item.tm_mon = lt_day.tm_mon;
lt_item.tm_year = lt_day.tm_year;
break; break;
case RECUR_WEEKLY: case RECUR_WEEKLY:
if (lt_item.tm_wday != lt_day.tm_wday) diff = diff_days (lt_item_day, lt_day) % (rpt_freq * WEEKINDAYS);
return (0); lt_item_day.tm_mday = lt_day.tm_mday - diff;
else lt_item_day.tm_mon = lt_day.tm_mon;
{ lt_item_day.tm_year = lt_day.tm_year;
diff = diff_weeks (lt_item, lt_day);
if (diff % rpt_freq != 0)
return (0);
}
lt_item.tm_mday = lt_day.tm_mday;
lt_item.tm_mon = lt_day.tm_mon;
lt_item.tm_year = lt_day.tm_year;
break; break;
case RECUR_MONTHLY: case RECUR_MONTHLY:
diff = diff_months (lt_item, lt_day); diff = diff_months (lt_item_day, lt_day) % rpt_freq;
if (diff % rpt_freq != 0) if (lt_day.tm_mday < lt_item_day.tm_mday)
return (0); diff++;
lt_item.tm_mon = lt_day.tm_mon; lt_item_day.tm_mon = lt_day.tm_mon - diff;
lt_item.tm_year = lt_day.tm_year; lt_item_day.tm_year = lt_day.tm_year;
break; break;
case RECUR_YEARLY: case RECUR_YEARLY:
diff = diff_years (lt_item, lt_day); diff = diff_years (lt_item_day, lt_day) % rpt_freq;
if (diff % rpt_freq != 0) if (lt_day.tm_mon < lt_item_day.tm_mon ||
return (0); (lt_day.tm_mon == lt_item_day.tm_mon &&
lt_item.tm_year = lt_day.tm_year; lt_day.tm_mday < lt_item_day.tm_mday))
diff++;
lt_item_day.tm_year = lt_day.tm_year - diff;
break; break;
default: default:
EXIT (_("unknown item type")); EXIT (_("unknown item type"));
} }
start_date.dd = lt_item.tm_mday;
start_date.mm = lt_item.tm_mon + 1;
start_date.yyyy = lt_item.tm_year + 1900;
item_start = date2sec (start_date, lt_item.tm_hour, lt_item.tm_min);
if (item_start < day_end && item_start >= day_start) lt_item_day.tm_isdst = lt_day.tm_isdst;
return (item_start); t = mktime (&lt_item_day);
if (LLIST_FIND_FIRST (item_exc, t, exc_inday))
return 0;
if (rpt_until != 0 && t > rpt_until)
return 0;
lt_item_day = *localtime (&t);
diff = diff_days (lt_item_day, lt_day);
if (diff <= span)
{
start_date.dd = lt_item_day.tm_mday;
start_date.mm = lt_item_day.tm_mon + 1;
start_date.yyyy = lt_item_day.tm_year + 1900;
return date2sec (start_date, lt_item.tm_hour, lt_item.tm_min);
}
else else
return (0); return 0;
} }
unsigned unsigned