Notamify NOTAM Schedules & RRULE Parsing
This article expands on how Notamify represents and parses NOTAM schedules and how you can use them for client-side time filtering. It includes fully working Python and JavaScript examples.
TL;DR
Notamify exposes schedule recurrences using a standards-compliant RFC 5545 RRULE string plus a separate
duration_hrs.Duration is not encoded in the RRULE. We keep duration in
duration_hrsto avoid non-standard RRULEs and to properly handle windows that cross midnight (e.g., 20:00–04:00).Each schedule RRULE produces a list of start datetimes; you derive the end by
start + duration_hrs.Always intersect schedule windows with the NOTAM’s overall validity
[starts_at, ends_at].
Data Model
Within each NOTAM, schedules live at notam.interpretation.schedules[]:
{
"description": "On April 4-6, 11-13, 18-20, 25-27 from 20:00 to 04:00.",
"duration_hrs": 8,
"is_sunrise_sunset": false,
"rrule": "DTSTART:20250404T200000Z\nRRULE:FREQ=DAILY;UNTIL=20250627T040000Z;BYDAY=TH,FR,SA,SU,MO,TU,WE;COUNT=15",
"source": "APR 04-06 11-13 18-20 25-27 2000-0400"
}Contract & invariants
rrule(string): An iCalendar RRULE string that includes aDTSTARTline in UTC (ending withZ). RRULEs are bounded (viaCOUNTorUNTIL).duration_hrs(number): The event window length in hours for each occurrence generated by the RRULE.is_sunrise_sunset(boolean): Iftrue, duration/instants derive from astronomical times (out of scope here).description/source: Human-readable; do not parse from these.
Note: The NOTAM object also carries
starts_atandends_at—the overall validity window. Schedule windows must be intersected with this validity.
Client-Side Usage Pattern
Parse the RRULE to get start datetimes.
Compute end = start + duration_hrs.
Intersect each
[start, end)with:The NOTAM validity
[starts_at, ends_at), andAny query window you care about (e.g., “show what’s active on 2025-05-10”).
When possible, prefer windowed enumeration (
between(...)) to avoid expanding very long recurrences.
Python (dateutil)
Key callouts
rule = rrulestr(rrule_str)is the only dateutil-specific line you need to parse bothDTSTARTandRRULE.Use
rule.between(start, end, inc=True)whenever you can bound expansion.
JavaScript/TypeScript (rrule)
IMPORTANT: Use
rrulestrfrom therrulepackage. Other RRULE string parsing mechanism from the package might not work as expected.
Quick Recipe: “Is this NOTAM active at T?”
T?”Python
JavaScript/TS
Summary
RRULE gives you when each occurrence starts;
duration_hrstells you how long it runs.Expand, add duration, and intersect with the NOTAM’s validity (and your query).
Use dateutil (
rrulestr) in Python and rrule (rrulestr) in JavaScript for robust, standards-compliant parsing.
Last updated