Extend import of recurrence rules
Support has been implemented for recurrence rule parts BYMONTH, BYMONTHDAY and BYDAY. A new test has been added. Signed-off-by: Lars Henriksen <LarsHenriksen@get2net.dk> Signed-off-by: Lukas Fleischer <lfleischer@calcurse.org>
This commit is contained in:
parent
d2791b046a
commit
382e60ba69
205
src/ical.c
205
src/ical.c
@ -68,6 +68,9 @@ typedef struct {
|
||||
unsigned freq;
|
||||
time_t until;
|
||||
unsigned count;
|
||||
llist_t bymonth;
|
||||
llist_t bywday;
|
||||
llist_t bymonthday;
|
||||
} ical_rpt_t;
|
||||
|
||||
static void ical_export_header(FILE *);
|
||||
@ -377,7 +380,7 @@ static void ical_store_todo(int priority, int completed, char *mesg,
|
||||
* Calcurse limitation: events are one-day (all-day), and all multi-day events
|
||||
* are turned into one-day events; a note has been added by ical_read_event().
|
||||
*/
|
||||
static void
|
||||
static int
|
||||
ical_store_event(char *mesg, char *note, time_t day, time_t end,
|
||||
ical_rpt_t *irpt, llist_t *exc, const char *fmt_ev,
|
||||
const char *fmt_rev)
|
||||
@ -395,12 +398,14 @@ ical_store_event(char *mesg, char *note, time_t day, time_t end,
|
||||
rpt.type = irpt->type;
|
||||
rpt.freq = irpt->freq;
|
||||
rpt.until = irpt->until;
|
||||
LLIST_INIT(&rpt.bymonth);
|
||||
LLIST_INIT(&rpt.bywday);
|
||||
LLIST_INIT(&rpt.bymonthday);
|
||||
rpt.bymonth = irpt->bymonth;
|
||||
rpt.bywday = irpt->bywday;
|
||||
rpt.bymonthday = irpt->bymonthday;
|
||||
rpt.exc = *exc;
|
||||
rev = recur_event_new(mesg, note, day, EVENTID, &rpt);
|
||||
if (!recur_item_find_occurrence(day, -1, &rpt, NULL, day, NULL))
|
||||
return 0;
|
||||
mem_free(irpt);
|
||||
rev = recur_event_new(mesg, note, day, EVENTID, &rpt);
|
||||
if (fmt_rev)
|
||||
print_recur_event(fmt_rev, day, rev);
|
||||
goto cleanup;
|
||||
@ -434,9 +439,10 @@ ical_store_event(char *mesg, char *note, time_t day, time_t end,
|
||||
cleanup:
|
||||
mem_free(mesg);
|
||||
erase_note(¬e);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
static int
|
||||
ical_store_apoint(char *mesg, char *note, time_t start, long dur,
|
||||
ical_rpt_t * irpt, llist_t * exc, int has_alarm,
|
||||
const char *fmt_apt, const char *fmt_rapt)
|
||||
@ -446,6 +452,7 @@ ical_store_apoint(char *mesg, char *note, time_t start, long dur,
|
||||
struct recur_apoint *rapt;
|
||||
time_t day;
|
||||
|
||||
day = update_time_in_date(start, 0, 0);
|
||||
if (has_alarm)
|
||||
state |= APOINT_NOTIFY;
|
||||
if (irpt) {
|
||||
@ -453,10 +460,13 @@ ical_store_apoint(char *mesg, char *note, time_t start, long dur,
|
||||
rpt.type = irpt->type;
|
||||
rpt.freq = irpt->freq;
|
||||
rpt.until = irpt->until;
|
||||
LLIST_INIT(&rpt.bymonth);
|
||||
LLIST_INIT(&rpt.bywday);
|
||||
LLIST_INIT(&rpt.bymonthday);
|
||||
rpt.bymonth = irpt->bymonth;
|
||||
rpt.bywday = irpt->bywday;
|
||||
rpt.bymonthday = irpt->bymonthday;
|
||||
rpt.exc = *exc;
|
||||
if (!recur_item_find_occurrence(start, dur, &rpt, NULL,
|
||||
day, NULL))
|
||||
return 0;
|
||||
/*
|
||||
* In calcurse, "until" is interpreted as a day (DATE) - hours,
|
||||
* minutes and seconds are ignored - whereas in iCal the full
|
||||
@ -485,6 +495,7 @@ ical_store_apoint(char *mesg, char *note, time_t start, long dur,
|
||||
}
|
||||
mem_free(mesg);
|
||||
erase_note(¬e);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -790,9 +801,9 @@ static void ical_count2until(time_t s, long d, ical_rpt_t *i, llist_t *e,
|
||||
rpt.type = i->type;
|
||||
rpt.freq = i->freq;
|
||||
rpt.until = 0;
|
||||
LLIST_INIT(&rpt.bymonth);
|
||||
LLIST_INIT(&rpt.bywday);
|
||||
LLIST_INIT(&rpt.bymonthday);
|
||||
rpt.bymonth = i->bymonth;
|
||||
rpt.bywday = i->bywday;
|
||||
rpt.bymonthday = i->bymonthday;
|
||||
recur_nth_occurrence(s, d, &rpt, e, i->count, &i->until);
|
||||
}
|
||||
|
||||
@ -813,9 +824,108 @@ static char *ical_get_value(char *p)
|
||||
return p + 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Fill in the bymonth linked list from a comma-separated list of
|
||||
* unsigned integers terminated by a space or end of string.
|
||||
*/
|
||||
static int ical_bymonth(llist_t *ll, char *cl)
|
||||
{
|
||||
unsigned mon;
|
||||
int *i, n;
|
||||
|
||||
while (!(*cl == ' ' || *cl == '\0')) {
|
||||
if (!(sscanf(cl, "%u%n", &mon, &n) == 1))
|
||||
return 0;
|
||||
i = mem_malloc(sizeof(int));
|
||||
*i = mon;
|
||||
LLIST_ADD(ll, i);
|
||||
cl += n;
|
||||
cl += (*cl == ',');
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Fill in the bymonthday linked list from a comma-separated list of
|
||||
* (signed) integers terminated by a space or end of string.
|
||||
*/
|
||||
static int ical_bymonthday(llist_t *ll, char *cl)
|
||||
{
|
||||
int mday;
|
||||
int *i, n;
|
||||
|
||||
while (!(*cl == ' ' || *cl == '\0')) {
|
||||
if (!(sscanf(cl, "%d%n", &mday, &n) == 1))
|
||||
return 0;
|
||||
i = mem_malloc(sizeof(int));
|
||||
*i = mday;
|
||||
LLIST_ADD(ll, i);
|
||||
cl += n;
|
||||
cl += (*cl == ',');
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Fill in the bywday linked list from a comma-separated list of (ordered)
|
||||
* weekday names (+1SU, MO, -5SA, 25TU, etc.) terminated by a space or end of
|
||||
* string.
|
||||
*/
|
||||
static int ical_bywday(llist_t *ll, char *cl)
|
||||
{
|
||||
int sign, order, wday, n, *i;
|
||||
char *owd;
|
||||
|
||||
while (!(*cl == ' ' || *cl == '\0')) {
|
||||
/* find list separator */
|
||||
for (owd = cl; !(*cl == ',' || *cl == ' ' || *cl == '\0'); cl++)
|
||||
;
|
||||
cl += (*cl == ',');
|
||||
|
||||
if (!(sscanf(owd, "%d%n", &order, &n) == 1))
|
||||
order = n = 0;
|
||||
sign = (order < 0) ? -1 : 1;
|
||||
order *= sign;
|
||||
owd += n;
|
||||
if (starts_with(owd, "SU"))
|
||||
wday = 0;
|
||||
else if (starts_with(owd, "MO"))
|
||||
wday = 1;
|
||||
else if (starts_with(owd, "TU"))
|
||||
wday = 2;
|
||||
else if (starts_with(owd, "WE"))
|
||||
wday = 3;
|
||||
else if (starts_with(owd, "TH"))
|
||||
wday = 4;
|
||||
else if (starts_with(owd, "FR"))
|
||||
wday = 5;
|
||||
else if (starts_with(owd, "SA"))
|
||||
wday = 6;
|
||||
else
|
||||
return 0;
|
||||
|
||||
wday = sign * (wday + order * WEEKINDAYS);
|
||||
i = mem_malloc(sizeof(int));
|
||||
*i = wday;
|
||||
LLIST_ADD(ll, i);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read a recurrence rule from an iCalendar RRULE string.
|
||||
*
|
||||
* RFC 5545, section 3.8.5.3:
|
||||
*
|
||||
* Property Name: RRULE
|
||||
*
|
||||
* Purpose: This property defines a rule or repeating pattern for
|
||||
* recurring events, to-dos, journal entries, or time zone definitions.
|
||||
*
|
||||
* Value Type: RECUR
|
||||
*
|
||||
* RFC 5545, section 3.3.10:
|
||||
*
|
||||
* Value Name: RECUR
|
||||
*
|
||||
* Purpose: This value type is used to identify properties that contain
|
||||
@ -855,7 +965,8 @@ static char *ical_get_value(char *p)
|
||||
static ical_rpt_t *ical_read_rrule(FILE *log, char *rrulestr,
|
||||
unsigned *noskipped,
|
||||
const int itemline,
|
||||
ical_vevent_e type)
|
||||
ical_vevent_e type,
|
||||
time_t start)
|
||||
{
|
||||
char freqstr[8];
|
||||
ical_rpt_t *rpt;
|
||||
@ -880,6 +991,9 @@ static ical_rpt_t *ical_read_rrule(FILE *log, char *rrulestr,
|
||||
|
||||
rpt = mem_malloc(sizeof(ical_rpt_t));
|
||||
memset(rpt, 0, sizeof(ical_rpt_t));
|
||||
LLIST_INIT(&rpt->bymonth);
|
||||
LLIST_INIT(&rpt->bywday);
|
||||
LLIST_INIT(&rpt->bymonthday);
|
||||
|
||||
/* FREQ rule part */
|
||||
if ((p = strstr(rrulestr, "FREQ="))) {
|
||||
@ -960,6 +1074,42 @@ static ical_rpt_t *ical_read_rrule(FILE *log, char *rrulestr,
|
||||
}
|
||||
}
|
||||
|
||||
/* BYMONTH rule part */
|
||||
if ((p = strstr(rrulestr, "BYMONTH="))) {
|
||||
p = strchr(p, '=') + 1;
|
||||
if (!ical_bymonth(&rpt->bymonth, p)) {
|
||||
ical_log(log, ICAL_VEVENT, itemline,
|
||||
_("invalid bymonth list."));
|
||||
(*noskipped)++;
|
||||
mem_free(rpt);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* BYMONTHDAY rule part */
|
||||
if ((p = strstr(rrulestr, "BYMONTHDAY="))) {
|
||||
p = strchr(p, '=') + 1;
|
||||
if (!ical_bymonthday(&rpt->bymonthday, p)) {
|
||||
ical_log(log, ICAL_VEVENT, itemline,
|
||||
_("invalid bymonthday list."));
|
||||
(*noskipped)++;
|
||||
mem_free(rpt);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* BYDAY rule part */
|
||||
if ((p = strstr(rrulestr, "BYDAY="))) {
|
||||
p = strchr(p, '=') + 1;
|
||||
if (!ical_bywday(&rpt->bywday, p)) {
|
||||
ical_log(log, ICAL_VEVENT, itemline,
|
||||
_("invalid byday list."));
|
||||
(*noskipped)++;
|
||||
mem_free(rpt);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return rpt;
|
||||
}
|
||||
|
||||
@ -1214,21 +1364,38 @@ ical_read_event(FILE * fdi, FILE * log, unsigned *noevents,
|
||||
}
|
||||
vevent.note = generate_note(string_buf(&s));
|
||||
mem_free(s.buf);
|
||||
/*
|
||||
* Necessary to prevent double-free if item
|
||||
* creation fails below.
|
||||
*/
|
||||
vevent.desc = vevent.loc = vevent.comm =
|
||||
vevent.stat = vevent.imp = NULL;
|
||||
}
|
||||
char *msg = _("rrule does not match start day (%s).");
|
||||
switch (vevent_type) {
|
||||
case APPOINTMENT:
|
||||
ical_store_apoint(vevent.mesg, vevent.note,
|
||||
if (!ical_store_apoint(vevent.mesg, vevent.note,
|
||||
vevent.start, vevent.dur,
|
||||
vevent.rpt, &vevent.exc,
|
||||
vevent.has_alarm, fmt_apt,
|
||||
fmt_rapt);
|
||||
vevent.has_alarm,
|
||||
fmt_apt, fmt_rapt)) {
|
||||
char *l = day_ins(&msg, vevent.start);
|
||||
ical_log(log, ICAL_VEVENT, ITEMLINE, l);
|
||||
mem_free(l);
|
||||
goto skip;
|
||||
}
|
||||
(*noapoints)++;
|
||||
break;
|
||||
case EVENT:
|
||||
ical_store_event(vevent.mesg, vevent.note,
|
||||
if (!ical_store_event(vevent.mesg, vevent.note,
|
||||
vevent.start, vevent.end,
|
||||
vevent.rpt, &vevent.exc,
|
||||
fmt_ev, fmt_rev);
|
||||
fmt_ev, fmt_rev)) {
|
||||
char *l = day_ins(&msg, vevent.start);
|
||||
ical_log(log, ICAL_VEVENT, ITEMLINE, l);
|
||||
mem_free(l);
|
||||
goto skip;
|
||||
}
|
||||
(*noevents)++;
|
||||
break;
|
||||
case UNDEFINED:
|
||||
@ -1342,7 +1509,7 @@ ical_read_event(FILE * fdi, FILE * log, unsigned *noevents,
|
||||
}
|
||||
} else if (starts_with_ci(buf, "RRULE")) {
|
||||
vevent.rpt = ical_read_rrule(log, buf, noskipped,
|
||||
ITEMLINE, vevent_type);
|
||||
ITEMLINE, vevent_type, vevent.start);
|
||||
if (!vevent.rpt)
|
||||
goto cleanup;
|
||||
} else if (starts_with_ci(buf, "EXDATE")) {
|
||||
|
@ -1828,7 +1828,7 @@ int recur_next_occurrence(time_t s, long d, struct rpt *r, llist_t *e,
|
||||
}
|
||||
|
||||
/*
|
||||
* Finds the nth occurrence of a recurrence rule (s, d, r, e) (incl. the start)
|
||||
* Finds the nth occurrence (incl. start) of a recurrence rule (s, d, r, e)
|
||||
* and returns it in the provided buffer.
|
||||
*/
|
||||
int recur_nth_occurrence(time_t s, long d, struct rpt *r, llist_t *e, int n,
|
||||
|
@ -434,9 +434,9 @@ time_t tzdate2sec(struct date day, unsigned hour, unsigned min, char *tznew)
|
||||
tzold = getenv("TZ");
|
||||
if (tzold)
|
||||
tzold = mem_strdup(tzold);
|
||||
|
||||
setenv("TZ", tznew, 1);
|
||||
tzset();
|
||||
|
||||
t = date2sec(day, hour, min);
|
||||
|
||||
if (tzold) {
|
||||
|
@ -60,6 +60,7 @@ TESTS = \
|
||||
ical-010.sh \
|
||||
ical-011.sh \
|
||||
ical-012.sh \
|
||||
ical-013.sh \
|
||||
next-001.sh \
|
||||
next-002.sh \
|
||||
next-003.sh \
|
||||
@ -138,6 +139,7 @@ EXTRA_DIST = \
|
||||
data/ical-008.ical \
|
||||
data/ical-009.ical \
|
||||
data/ical-012.ical \
|
||||
data/rfc5545.ical \
|
||||
data/rfc5545 \
|
||||
data/todo \
|
||||
data/todo-export
|
||||
|
@ -46,7 +46,25 @@ DTSTAMP:
|
||||
UID:
|
||||
DTSTART;VALUE=DATE:20200502
|
||||
DTEND;VALUE=DATE:20200504
|
||||
DESCRIPTION:The first weekend in May is a two-day event.
|
||||
DESCRIPTION:The first weekend in May is a two-day event.\nNon-repeating event.
|
||||
SUMMARY:First weekend in May
|
||||
END:VEVENT
|
||||
BEGIN:VEVENT
|
||||
DTSTAMP:
|
||||
UID:
|
||||
DTSTART;VALUE=DATE:20200502
|
||||
DTEND;VALUE=DATE:20200504
|
||||
DESCRIPTION:First weekend in May is a two-day event!\nRepeating event\, three years.
|
||||
SUMMARY:First weekend in May
|
||||
RRULE:FREQ=YEARLY;BYDAY=1SA;BYMONTH=5;COUNT=3
|
||||
END:VEVENT
|
||||
BEGIN:VEVENT
|
||||
DTSTAMP:
|
||||
UID:
|
||||
DTSTART:20200502T000000
|
||||
DTEND:20200504T000000
|
||||
DESCRIPTION:First weekend in May is a two-day event!\nRepeating appointment.
|
||||
SUMMARY:First weekend in May
|
||||
RRULE:FREQ=YEARLY;BYDAY=1SA;BYMONTH=5;COUNT=3
|
||||
END:VEVENT
|
||||
END:VCALENDAR
|
||||
|
238
test/data/rfc5545.ical
Normal file
238
test/data/rfc5545.ical
Normal file
@ -0,0 +1,238 @@
|
||||
BEGIN:VCALENDAR
|
||||
VERSION:2.0
|
||||
PRODID:
|
||||
BEGIN:VEVENT
|
||||
DTSTAMP:
|
||||
UID:
|
||||
DTSTART;TZID=America/New_York:19970901T090000
|
||||
SUMMARY:Every other week on Monday\, Wednesday\, and Friday until December 24\, 1997\, starting on Monday\, September 1\, 1997
|
||||
RRULE:FREQ=WEEKLY;INTERVAL=2;UNTIL=19971224T000000Z;WKST=SU;BYDAY=MO,WE,FR
|
||||
END:VEVENT
|
||||
BEGIN:VEVENT
|
||||
DTSTAMP:
|
||||
UID:
|
||||
DTSTART;TZID=America/New_York:19970902T090000
|
||||
SUMMARY:Every other week on Tuesday and Thursday\, for 8 occurrences
|
||||
RRULE:FREQ=WEEKLY;INTERVAL=2;COUNT=8;WKST=SU;BYDAY=TU,TH
|
||||
END:VEVENT
|
||||
BEGIN:VEVENT
|
||||
DTSTAMP:
|
||||
UID:
|
||||
DTSTART;TZID=America/New_York:19970905T090000
|
||||
SUMMARY:Monthly on the first Friday for 10 occurrences
|
||||
RRULE:FREQ=MONTHLY;COUNT=10;BYDAY=1FR
|
||||
END:VEVENT
|
||||
BEGIN:VEVENT
|
||||
DTSTAMP:
|
||||
UID:
|
||||
DTSTART;TZID=America/New_York:19970905T090000
|
||||
SUMMARY:Monthly on the first Friday until December 24\, 1997
|
||||
RRULE:FREQ=MONTHLY;UNTIL=19971224T000000Z;BYDAY=1FR
|
||||
END:VEVENT
|
||||
BEGIN:VEVENT
|
||||
DTSTAMP:
|
||||
UID:
|
||||
DTSTART;TZID=America/New_York:19970907T090000
|
||||
SUMMARY:Every other month on the first and last Sunday of the month for 10 occurrences
|
||||
RRULE:FREQ=MONTHLY;INTERVAL=2;COUNT=10;BYDAY=1SU,-1SU
|
||||
END:VEVENT
|
||||
BEGIN:VEVENT
|
||||
DTSTAMP:
|
||||
UID:
|
||||
DTSTART;TZID=America/New_York:19970922T090000
|
||||
SUMMARY:Monthly on the second-to-last Monday of the month for 6 months
|
||||
RRULE:FREQ=MONTHLY;COUNT=6;BYDAY=-2MO
|
||||
END:VEVENT
|
||||
BEGIN:VEVENT
|
||||
DTSTAMP:
|
||||
UID:
|
||||
DTSTART;TZID=America/New_York:19970928T090000
|
||||
SUMMARY:Monthly on the third-to-the-last day of the month\, forever
|
||||
RRULE:FREQ=MONTHLY;BYMONTHDAY=-3
|
||||
END:VEVENT
|
||||
BEGIN:VEVENT
|
||||
DTSTAMP:
|
||||
UID:
|
||||
DTSTART;TZID=America/New_York:19970902T090000
|
||||
SUMMARY:Monthly on the 2nd and 15th of the month for 10 occurrences
|
||||
RRULE:FREQ=MONTHLY;COUNT=10;BYMONTHDAY=2,15
|
||||
END:VEVENT
|
||||
BEGIN:VEVENT
|
||||
DTSTAMP:
|
||||
UID:
|
||||
DTSTART;TZID=America/New_York:19970930T090000
|
||||
SUMMARY:Monthly on the first and last day of the month for 10 occurrences
|
||||
RRULE:FREQ=MONTHLY;COUNT=10;BYMONTHDAY=1,-1
|
||||
END:VEVENT
|
||||
BEGIN:VEVENT
|
||||
DTSTAMP:
|
||||
UID:
|
||||
DTSTART;TZID=America/New_York:19970910T090000
|
||||
SUMMARY:Every 18 months on the 10th thru 15th of the month for 10 occurrences
|
||||
RRULE:FREQ=MONTHLY;INTERVAL=18;COUNT=10;BYMONTHDAY=10,11,12,13,14,15
|
||||
END:VEVENT
|
||||
BEGIN:VEVENT
|
||||
DTSTAMP:
|
||||
UID:
|
||||
DTSTART;TZID=America/New_York:19970902T090000
|
||||
DURATION:PT1H
|
||||
SUMMARY:Daily for 10 occurrences
|
||||
RRULE:FREQ=DAILY;COUNT=10
|
||||
END:VEVENT
|
||||
BEGIN:VEVENT
|
||||
DTSTAMP:
|
||||
UID:
|
||||
DTSTART;TZID=America/New_York:19970902T090000
|
||||
SUMMARY:Every Tuesday\, every other month
|
||||
RRULE:FREQ=MONTHLY;INTERVAL=2;BYDAY=TU
|
||||
END:VEVENT
|
||||
BEGIN:VEVENT
|
||||
DTSTAMP:
|
||||
UID:
|
||||
DTSTART;TZID=America/New_York:19970610T090000
|
||||
SUMMARY:Yearly in June and July for 10 occurrences
|
||||
RRULE:FREQ=YEARLY;COUNT=10;BYMONTH=6,7
|
||||
END:VEVENT
|
||||
BEGIN:VEVENT
|
||||
DTSTAMP:
|
||||
UID:
|
||||
DTSTART;TZID=America/New_York:19970310T090000
|
||||
SUMMARY:Every other year on January\, February\, and March for 10 occurrences
|
||||
RRULE:FREQ=YEARLY;INTERVAL=2;COUNT=10;BYMONTH=1,2,3
|
||||
END:VEVENT
|
||||
BEGIN:VEVENT
|
||||
DTSTAMP:
|
||||
UID:
|
||||
DTSTART;TZID=America/New_York:19970519T090000
|
||||
SUMMARY:Every 20th Monday of the year\, forever
|
||||
RRULE:FREQ=YEARLY;BYDAY=20MO
|
||||
END:VEVENT
|
||||
BEGIN:VEVENT
|
||||
DTSTAMP:
|
||||
UID:
|
||||
DTSTART;TZID=America/New_York:19970313T090000
|
||||
SUMMARY:Every Thursday in March\, forever
|
||||
RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=TH
|
||||
END:VEVENT
|
||||
BEGIN:VEVENT
|
||||
DTSTAMP:
|
||||
UID:
|
||||
DTSTART;TZID=America/New_York:19970605T090000
|
||||
SUMMARY:Every Thursday\, but only during June\, July\, and August\, forever
|
||||
RRULE:FREQ=YEARLY;BYDAY=TH;BYMONTH=6,7,8
|
||||
END:VEVENT
|
||||
BEGIN:VEVENT
|
||||
DTSTAMP:
|
||||
UID:
|
||||
DTSTART;TZID=America/New_York:19980213T090000
|
||||
SUMMARY:Every Friday the 13th\, forever
|
||||
RRULE:FREQ=MONTHLY;BYDAY=FR;BYMONTHDAY=13
|
||||
END:VEVENT
|
||||
BEGIN:VEVENT
|
||||
DTSTAMP:
|
||||
UID:
|
||||
DTSTART;TZID=America/New_York:19970913T090000
|
||||
SUMMARY:The first Saturday that follows the first Sunday of the month\, forever
|
||||
RRULE:FREQ=MONTHLY;BYDAY=SA;BYMONTHDAY=7,8,9,10,11,12,13
|
||||
END:VEVENT
|
||||
BEGIN:VEVENT
|
||||
DTSTAMP:
|
||||
UID:
|
||||
DTSTART;TZID=America/New_York:19961105T090000
|
||||
SUMMARY:Every 4 years\, the first Tuesday after a Monday in November\, forever (U.S. Presidential Election day)
|
||||
RRULE:FREQ=YEARLY;INTERVAL=4;BYMONTH=11;BYDAY=TU;BYMONTHDAY=2,3,4,5,6,7,8
|
||||
END:VEVENT
|
||||
BEGIN:VEVENT
|
||||
DTSTAMP:
|
||||
UID:
|
||||
DTSTART;TZID=America/New_York:19970805T090000
|
||||
SUMMARY:An example where the days generated makes a difference because of WKST
|
||||
RRULE:FREQ=WEEKLY;INTERVAL=2;COUNT=4;BYDAY=TU,SU;WKST=MO
|
||||
END:VEVENT
|
||||
BEGIN:VEVENT
|
||||
DTSTAMP:
|
||||
UID:
|
||||
DTSTART;TZID=America/New_York:19970805T090000
|
||||
SUMMARY:changing only WKST from MO to SU\, yields different results...
|
||||
RRULE:FREQ=WEEKLY;INTERVAL=2;COUNT=4;BYDAY=TU,SU;WKST=SU
|
||||
END:VEVENT
|
||||
BEGIN:VEVENT
|
||||
DTSTAMP:
|
||||
UID:
|
||||
DTSTART;TZID=America/New_York:19970902T090000
|
||||
DURATION:PT30M
|
||||
SUMMARY:Daily until December 24\, 1997
|
||||
RRULE:FREQ=DAILY;UNTIL=19971224T000000Z
|
||||
END:VEVENT
|
||||
BEGIN:VEVENT
|
||||
DTSTAMP:
|
||||
UID:
|
||||
DTSTART;TZID=America/New_York:20070115T090000
|
||||
SUMMARY:An example where an invalid date (i.e.\, February 30) is ignored
|
||||
RRULE:FREQ=MONTHLY;BYMONTHDAY=15,30;COUNT=5
|
||||
END:VEVENT
|
||||
BEGIN:VEVENT
|
||||
DTSTAMP:
|
||||
UID:
|
||||
DTSTART;TZID=America/New_York:19970902T090000
|
||||
DURATION:PT5M
|
||||
SUMMARY:Every other day - forever
|
||||
RRULE:FREQ=DAILY;INTERVAL=2
|
||||
END:VEVENT
|
||||
BEGIN:VEVENT
|
||||
DTSTAMP:
|
||||
UID:
|
||||
DTSTART;TZID=America/New_York:19970902T090000
|
||||
SUMMARY:Every 10 days\, 5 occurrences:
|
||||
RRULE:FREQ=DAILY;INTERVAL=10;COUNT=5
|
||||
END:VEVENT
|
||||
BEGIN:VEVENT
|
||||
DTSTAMP:
|
||||
UID:
|
||||
DTSTART;TZID=America/New_York:19980101T090000
|
||||
SUMMARY:(1) Every day in January\, for 3 years:
|
||||
RRULE:FREQ=YEARLY;UNTIL=20000131T140000Z;BYMONTH=1;BYDAY=SU,MO,TU,WE,TH,FR,SA
|
||||
END:VEVENT
|
||||
BEGIN:VEVENT
|
||||
DTSTAMP:
|
||||
UID:
|
||||
DTSTART;TZID=America/New_York:19980101T090000
|
||||
SUMMARY:(2) Every day in January\, for 3 years:
|
||||
RRULE:FREQ=DAILY;UNTIL=20000131T140000Z;BYMONTH=1
|
||||
END:VEVENT
|
||||
BEGIN:VEVENT
|
||||
DTSTAMP:
|
||||
UID:
|
||||
DTSTART;TZID=America/New_York:19970902T090000
|
||||
SUMMARY:Weekly for 10 occurrences
|
||||
RRULE:FREQ=WEEKLY;COUNT=10
|
||||
END:VEVENT
|
||||
BEGIN:VEVENT
|
||||
DTSTAMP:
|
||||
UID:
|
||||
DTSTART;TZID=America/New_York:19970902T090000
|
||||
SUMMARY:Weekly until December 24\, 1997
|
||||
RRULE:FREQ=WEEKLY;UNTIL=19971224T000000Z
|
||||
END:VEVENT
|
||||
BEGIN:VEVENT
|
||||
DTSTAMP:
|
||||
UID:
|
||||
DTSTART;TZID=America/New_York:19970902T090000
|
||||
SUMMARY:Every other week - forever
|
||||
RRULE:FREQ=WEEKLY;INTERVAL=2;WKST=SU
|
||||
END:VEVENT
|
||||
BEGIN:VEVENT
|
||||
DTSTAMP:
|
||||
UID:
|
||||
DTSTART;TZID=America/New_York:19970902T090000
|
||||
SUMMARY:Weekly on Tuesday and Thursday for five weeks (UNTIL)
|
||||
RRULE:FREQ=WEEKLY;UNTIL=19971007T000000Z;WKST=SU;BYDAY=TU,TH
|
||||
END:VEVENT
|
||||
BEGIN:VEVENT
|
||||
DTSTAMP:
|
||||
UID:
|
||||
DTSTART;TZID=America/New_York:19970902T090000
|
||||
SUMMARY:Weekly on Tuesday and Thursday for five weeks (COUNT)
|
||||
RRULE:FREQ=WEEKLY;COUNT=10;WKST=SU;BYDAY=TU,TH
|
||||
END:VEVENT
|
||||
END:VCALENDAR
|
@ -8,13 +8,13 @@ if [ "$1" = 'actual' ]; then
|
||||
cp "$DATA_DIR/conf" .calcurse || exit 1
|
||||
"$CALCURSE" -D "$PWD/.calcurse" -i "$DATA_DIR/ical-003.ical"
|
||||
"$CALCURSE" -D "$PWD/.calcurse" -s01/01/2000 -r365
|
||||
"$CALCURSE" -D "$PWD/.calcurse" -s05/01/2020 --to 01/01/2022
|
||||
"$CALCURSE" -D "$PWD/.calcurse" -s05/01/2020 --to 01/01/2023
|
||||
cat "$PWD/.calcurse/notes"/*
|
||||
rm -rf .calcurse || exit 1
|
||||
elif [ "$1" = 'expected' ]; then
|
||||
cat <<EOD
|
||||
Import process report: 0052 lines read
|
||||
6 apps / 1 event / 0 todos / 0 skipped
|
||||
Import process report: 0070 lines read
|
||||
7 apps / 2 events / 0 todos / 0 skipped
|
||||
01/01/00:
|
||||
- 00:00 -> 01:30
|
||||
Recurring appointment
|
||||
@ -136,9 +136,14 @@ Import process report: 0052 lines read
|
||||
Recurring appointment
|
||||
05/02/20:
|
||||
* First weekend in May
|
||||
* First weekend in May
|
||||
- 00:00 -> ..:..
|
||||
First weekend in May
|
||||
|
||||
05/03/20:
|
||||
* First weekend in May
|
||||
- ..:.. -> 00:00
|
||||
First weekend in May
|
||||
|
||||
05/26/20:
|
||||
- 12:00 -> 13:17
|
||||
@ -182,6 +187,15 @@ Import process report: 0052 lines read
|
||||
- 21:45 -> 22:00
|
||||
monthly on 31th, count 10, exceptions 31/7/2020 and 31/1/2021
|
||||
|
||||
05/01/21:
|
||||
* First weekend in May
|
||||
- 00:00 -> ..:..
|
||||
First weekend in May
|
||||
|
||||
05/02/21:
|
||||
- ..:.. -> 00:00
|
||||
First weekend in May
|
||||
|
||||
05/31/21:
|
||||
- 21:45 -> 22:00
|
||||
monthly on 31th, count 10, exceptions 31/7/2020 and 31/1/2021
|
||||
@ -201,7 +215,23 @@ Import process report: 0052 lines read
|
||||
12/31/21:
|
||||
- 21:45 -> 22:00
|
||||
monthly on 31th, count 10, exceptions 31/7/2020 and 31/1/2021
|
||||
|
||||
05/07/22:
|
||||
* First weekend in May
|
||||
- 00:00 -> ..:..
|
||||
First weekend in May
|
||||
|
||||
05/08/22:
|
||||
- ..:.. -> 00:00
|
||||
First weekend in May
|
||||
First weekend in May is a two-day event!
|
||||
Repeating appointment.
|
||||
The first weekend in May is a two-day event.
|
||||
Non-repeating event.
|
||||
--
|
||||
Import: multi-day event changed to one-day event
|
||||
First weekend in May is a two-day event!
|
||||
Repeating event, three years.
|
||||
--
|
||||
Import: multi-day event changed to one-day event
|
||||
EOD
|
||||
|
1800
test/ical-013.sh
Executable file
1800
test/ical-013.sh
Executable file
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user