ilusm.dev

cal

Calendar and scheduling - create events with recurrence rules, export and import iCal/ICS, query events by date range or attendee, check availability, generate meeting-time suggestions, produce free/busy reports, and count business days.

Load with: use cal

What this module does

cal is a full-featured calendaring library. Build a calendar with named events, attach recurrence rules (daily, weekly, monthly, yearly), export to standard .ics format consumable by Google Calendar, Outlook, or Apple Calendar, and import .ics files back into a calendar object.

Queries let you find events in a time window, events at a specific moment, or events by attendee email. Availability checks find free slots of a required duration, and calsg suggests the best meeting times across a search window.

Quick example

use cal
use tim

# Create a calendar
c = calne("Work")

# Add a recurring weekly meeting
now = tim.now()
ev = clvne("Team sync", now, now + 3600, {
    loc: "Conference Room A",
    rrule: clrrn("WEEKLY", {byday: ["MO"], cnt: 10})
})
c = caldd(c, ev)

# Export to ICS
ics = cl2cs(c)
fs.wr("work.ics", ics)

# Import from ICS
c2 = clfrm(fs.rd("other.ics"))

# Find free slots for a 1-hour meeting tomorrow
slots = clfre(c, now + 86400, 3600, 300)
prn(slots)

# Count business days
days = clbsd(now, now + 14 * 86400, nil)

Functions

Calendar

calne(name)

Creates a new calendar with a name, empty event list, default timezone from tim.tzdf(), and a standard PRODID.

caldd(calendar, event)

Appends an event to the calendar. Returns the updated calendar.

calrm(calendar, uid)

Removes an event by UID. Returns the updated calendar.

calgt(calendar, uid)

Returns the event with the given UID, or nil.

calpd(calendar, event)

Updates an existing event (matched by UID) and sets mod to now. Returns the updated calendar.

Events

clvne(summary, start, end, opts)

Creates a VEVENT. start and end are Unix timestamps. Optional fields in opts: uid, loc, desc, url, org, att (attendees list), cat (categories), stat (default "CONFIRMED"), pri (default 0), cls (default "PUBLIC"), rrule, exdt (exclusion dates), and alarm.

calud()

Generates a unique event ID in the form "ilusm-{ms}-{rand}@ilusm".

Recurrence rules

clrrn(freq, opts)

Creates a recurrence rule. freq: "DAILY", "WEEKLY", "MONTHLY", "YEARLY". Options: int (interval, default 1), cnt (max occurrences), until (end timestamp), byday, bymth, bymd, byhour, bymin, wkst, setpos.

clxpd(rrule, start, end)

Expands a recurrence rule into a list of individual occurrence timestamps between start and end (capped at 1000). Respects exdt exclusions and cnt limits.

clnxt(rrule, dt)

Computes the next occurrence timestamp after dt. Daily adds 86400 × interval seconds; weekly adds 604800 × interval; monthly and yearly delegate to host natives __cal_add_mth and __cal_add_yr.

iCal export

cl2cs(calendar)

Serialises the calendar to a valid VCALENDAR string with CRLF line endings, ready to write to a .ics file.

clv2c(event)

Serialises a single event to a list of VEVENT lines. Includes UID, SUMMARY, DTSTART, DTEND, LOCATION, DESCRIPTION, URL, ORGANIZER, ATTENDEE, CATEGORIES, STATUS, CLASS, CREATED, LAST-MODIFIED, RRULE, EXDATE, and VALARM blocks.

clfmt(timestamp)

Formats a Unix timestamp as an iCal datetime string (YYYYMMDDTHHMMSSz).

clrr2(rrule)

Serialises a recurrence rule to an RRULE:... line.

iCal import

clfrm(ics_string)

Parses an ICS string and returns a calendar object. Parses UID, SUMMARY, DTSTART, DTEND, LOCATION, DESCRIPTION, and RRULE from VEVENT blocks.

Queries

clvbt(calendar, start, end)

Returns all events that overlap the given time range (event.start < end and event.end > start).

calvn(calendar, ts)

Returns all events that contain the given timestamp (start ≤ ts ≤ end).

clvtt(calendar, email)

Returns all events that include the given email in the attendee list.

Availability

clfre(calendar, start, duration, mingap)

Finds free time slots of at least duration seconds starting from start, with a minimum gap of mingap seconds between existing events. Returns a list of candidate start timestamps.

calsg(calendar, duration, opts)

Suggests up to opts.max meeting times (default 5) in a search window. Steps through the window in opts.step increments (default 30 min) and filters for free slots of duration.

calfb(calendar, start, end, resolution)

Returns a free/busy report listing all busy intervals in the range.

clfb2(freebusy)

Serialises a free/busy report to a VFREEBUSY ICS string.

Alarms

cllr1(action, trigger)

Creates a VALARM with the given action ("DISPLAY" or "EMAIL") and trigger.

cllr0(mins)

Creates a relative-before trigger: fires mins minutes before the event.

Attendees and RSVP

caltt(email, opts)

Creates an attendee with optional common name, role (default "REQ-PARTICIPANT"), RSVP flag, status (default "NEEDS-ACTION"), and type (default "INDIVIDUAL").

clrsv(event, email, response)

Updates an attendee's RSVP status. response is a status string like "ACCEPTED" or "DECLINED".

clnv2(event)

Generates an invitation ICS string with METHOD:REQUEST prepended - suitable for sending as a calendar invite.

Business days

clshl(timestamp, country)

Returns tru if the date is a public holiday in the given country (defaults to "US"). Delegates to host native __cal_is_holiday.

clbsd(start, end, calendars)

Counts business days between two timestamps - excludes weekends (tim.dow(d) ≥ 5) and US public holidays.

Notes

  • All timestamps are Unix seconds.
  • Monthly and yearly recurrence advance via host natives __cal_add_mth / __cal_add_yr to handle month-length differences correctly.
  • Holiday detection requires __cal_is_holiday in the host runtime.
  • Requires trl, txt, tim, and jsn.