feat(monthly): add support for MONTHLY recurrence (P07, P08)

- Add `monthly_pattern`, `simple_monthly` types and `monthly` field to
  `rem`
- Implement `render_monthly` and `add_until_monthly` in `remind.ml`
- Handle `BYMONTHDAY` (P07) and nth-weekday `BYDAY` (P08) patterns in
  `eventPredicates.ml`
- Add `add_months` utility for date arithmetic
- Mark P07 and P08 as implemented in documentation
This commit is contained in:
2026-05-17 23:51:54 +02:00
parent c246ec6775
commit 425ce06816
3 changed files with 108 additions and 5 deletions

View File

@@ -58,7 +58,7 @@ open Utils
snippet: 'REM FROM 2025-10-01 UNTIL 2025-10-10 AT 08:30 MSG Daily'
priorita: Subito
- id: P07
- id: P07
pattern: Ricorrenza mensile per giorno fisso
ics: "RRULE:FREQ=MONTHLY;BYMONTHDAY=…"
remind_support: nativo
@@ -66,7 +66,7 @@ open Utils
snippet: 'REM 15 AT 10:00 FROM 2025-01-01 MSG Fatture'
priorita: Dopo
- id: P08
- id: P08
pattern: Ricorrenza “n-esimo weekday” del mese
ics: "RRULE:FREQ=MONTHLY;BYDAY=MO;BYSETPOS=3"
remind_support: espansione
@@ -323,6 +323,38 @@ RRULE: (`Weekly, (Some `Until (`Utc (2026-07-01 09:00:00 +00:00))), None, [])
Remind.weekly = Some { count_or_until; interval; byday = days; week_start };
}
end
| Some (_, (`Monthly, count_or_until, interval, recurs)) ->
begin match interval with
| Some n when n > 1 ->
Printf.eprintf "Warning: MONTHLY INTERVAL=%d not supported\t\t\tUID: %s\n" n (Utils.get_uid ev);
debug_print_of_recurrence_and_skip ev (`Monthly, count_or_until, interval, recurs)
| _ -> (
let bymonthday =
List.find_map
(function
| `Bymonthday (d :: _) -> Some d
| _ -> None)
recurs
in
let byday =
List.find_map
(function
| `Byday pairs -> List.find_map (fun (n, wd) -> if n <> 0 then Some (n, wd) else None) pairs
| _ -> None)
recurs
in
let pattern =
match (bymonthday, byday) with
| _, Some (n, wd) -> Some (Remind.By_nth_weekday (n, wd)) (* BYDAY takes precedence *)
| Some day, None -> Some (Remind.By_month_day day)
| None, None -> Some (Remind.By_month_day (Timedesc.Date.day rem.Remind.date))
in
match pattern with
| None ->
Printf.eprintf "Warning: MONTHLY with unsupported BYDAY\t\t\tUID: %s\n" (Utils.get_uid ev);
debug_print_of_recurrence_and_skip ev (`Monthly, count_or_until, interval, recurs)
| Some p -> Ok { rem with Remind.monthly = Some { count_or_until; interval; pattern = p } })
end
| Some (_, recurs) -> debug_print_of_recurrence_and_skip ev recurs
| None -> Ok rem