diff options
-rw-r--r-- | src/recur.c | 71 |
1 files changed, 36 insertions, 35 deletions
diff --git a/src/recur.c b/src/recur.c index d424bca..7376536 100644 --- a/src/recur.c +++ b/src/recur.c @@ -760,29 +760,35 @@ recur_item_find_occurrence(time_t item_start, long item_dur, time_t rpt_until, time_t day_start, time_t *occurrence) { - struct date start_date; - long diff, span; +/* + * Function-internal duration + * 1) To avoid an item ending on midnight (which belongs to the next day), + * duration is always diminished by 1 second. + * 2) An event has no explicit duration, but lasts for an entire day, which + * in turn depends on DST. + */ +#define ITEM_DUR(d) ((item_dur == -1 ? DAYLEN(d) : item_dur) - 1) + + long diff; struct tm lt_day, lt_item, lt_item_day; - time_t t; + time_t occ, item_day_start; - if (date_cmp_day(day_start, item_start) < 0) - return 0; + item_day_start = update_time_in_date(item_start, 0, 0); - if (rpt_until != 0 && day_start >= rpt_until + - (item_start - update_time_in_date(item_start, 0, 0)) + item_dur) + if (day_start < item_day_start) return 0; - t = day_start; - localtime_r(&t, <_day); - - t = item_start; - localtime_r(&t, <_item); - - lt_item_day = lt_item; - lt_item_day.tm_sec = lt_item_day.tm_min = lt_item_day.tm_hour = 0; + if (rpt_until && day_start >= + rpt_until + (item_start - item_day_start) + ITEM_DUR(rpt_until)) + return 0; - span = (item_start - mktime(<_item_day) + item_dur - 1) / DAYINSEC; + localtime_r(&day_start, <_day); /* selected day */ + localtime_r(&item_start, <_item); /* first occurrence */ + lt_item_day = lt_item; /* recent occurrence */ + /* + * Update to the most recent occurrence before or on the selected day. + */ switch (rpt_type) { case RECUR_DAILY: diff = diff_days(lt_item_day, lt_day) % rpt_freq; @@ -817,8 +823,9 @@ recur_item_find_occurrence(time_t item_start, long item_dur, EXIT(_("unknown item type")); } - lt_item_day.tm_isdst = lt_day.tm_isdst; - t = mktime(<_item_day); + /* Switch to calendar (Unix) time. */ + lt_item_day.tm_isdst = -1; + occ = mktime(<_item_day); /* * Impossible dates must be ignored (according to RFC 5545). Changing @@ -826,34 +833,28 @@ recur_item_find_occurrence(time_t item_start, long item_dur, * non-leap years or 31 November. */ if (rpt_type == RECUR_MONTHLY || rpt_type == RECUR_YEARLY) { - localtime_r(&t, <_item_day); + localtime_r(&occ, <_item_day); if (lt_item_day.tm_mday != lt_item.tm_mday) return 0; } /* Exception day? */ - if (LLIST_FIND_FIRST(item_exc, &t, exc_inday)) + if (LLIST_FIND_FIRST(item_exc, &occ, exc_inday)) return 0; - if (rpt_until != 0 && t >= NEXTDAY(rpt_until)) + /* After until day? */ + if (rpt_until && occ >= NEXTDAY(rpt_until)) return 0; - localtime_r(&t, <_item_day); - diff = diff_days(lt_item_day, lt_day); - - if (diff > span) + /* Does it span the selected day? */ + if (occ + ITEM_DUR(occ) < day_start) return 0; - if (occurrence) { - 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; - - *occurrence = date2sec(start_date, lt_item.tm_hour, - lt_item.tm_min); - } + if (occurrence) + *occurrence = occ; return 1; +#undef ITEM_DUR } unsigned @@ -871,7 +872,7 @@ unsigned recur_event_find_occurrence(struct recur_event *rev, time_t day_start, time_t *occurrence) { - return recur_item_find_occurrence(rev->day, DAYINSEC, &rev->exc, + return recur_item_find_occurrence(rev->day, -1, &rev->exc, rev->rpt->type, rev->rpt->freq, rev->rpt->until, day_start, occurrence); @@ -899,7 +900,7 @@ unsigned recur_apoint_inday(struct recur_apoint *rapt, time_t *day_start) unsigned recur_event_inday(struct recur_event *rev, time_t *day_start) { - return recur_item_inday(rev->day, DAYINSEC, &rev->exc, + return recur_item_inday(rev->day, -1, &rev->exc, rev->rpt->type, rev->rpt->freq, rev->rpt->until, *day_start); } |