np_notify_rrule — Syntax reference

np_notify_rrule is parsed by recpyx next_occurrence().

It accepts English expressions (canonical grammar) and French expressions (auto-normalised to English before parsing).

Timezone suffix is supported with values such as in Europe/Paris.

Grammaire BNF complète des expressions acceptées par next_occurrence

Grammaire BNF complète des expressions acceptées par next_occurrence


1) Lexique

<digit>         ::= "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
<yyyy>          ::= <digit><digit><digit><digit>
<mm>            ::= <digit><digit>
<dd>            ::= <digit><digit>
<hh>            ::= <digit> | <digit><digit>
<min2>          ::= <digit><digit>
<date>          ::= <yyyy> "-" <mm> "-" <dd>
<month-day>     ::= <mm> "-" <dd>
<time24>        ::= <hh> ":" <min2>
<time12>        ::= <hh> [":" <min2>] ("am" | "pm")
<time>          ::= <time24> | <time12>
<timezone>      ::= <tz-token> "/" <tz-token>
<tz-token>      ::= letter { letter | "_" }
<int>           ::= <digit> { <digit> }

<weekday>       ::= "monday" | "tuesday" | "wednesday" | "thursday" | "friday" | "saturday" | "sunday"
<weekday-list>  ::= <weekday> { ("and" | ",") <weekday> }
<month-name>    ::= "january" | "february" | "march" | "april" | "may" | "june" |
                    "july" | "august" | "september" | "october" | "november" | "december"
<ordinal>       ::= "first" | "second" | "third" | "fourth" | "fifth" | "last"
<monthday>      ::= ("1".."31") ["st" | "nd" | "rd" | "th"]
<monthday-list> ::= <monthday> { ("and" | ",") <monthday> }
<time-list>     ::= <time> { ("and" | ",") <time> }

2) Grammaire de haut niveau

<schedule>              ::= <rule-list> [<tz-suffix>]
<rule-list>             ::= <rule> { ", and" <rule> }
<tz-suffix>             ::= " in " <timezone>

<rule>                  ::= <base-rule> { <suffix-clause> }
<suffix-clause>         ::= <date-window> | <until-window> | <except-clause> | <weekend-shift>

3) Règles de base

<base-rule> ::= <oneshot>
              | <every-day>
              | <every-weekday>
              | <every-weekday-list>
              | <every-n-units>
              | <hourly-between>
              | <step-within-day>
              | <monthly-rule>
              | <yearly-date>
              | <yearly-nth-weekday>

<oneshot>              ::= <date> " at " <time>
<every-day>            ::= "every day at " <time-list>
<every-weekday>        ::= "every weekday at " <time-list>
<every-weekday-list>   ::= "every " <weekday-list> " at " <time-list>

<every-n-units>        ::= "every " <int> " " <unit> [" on " <weekday-list>] [" at " <time-list>]
<unit>                 ::= "minutes" | "hours" | "days" | "weeks"

<hourly-between>       ::= "every hour between " <time> " and " <time>
                         | "every " <int> " hours between " <time> " and " <time>

<step-within-day>      ::= "every " <day-scope> " every " <int> " " <step-unit>
                           " between " <time> " and " <time>
<day-scope>            ::= "day" | "weekday"
<step-unit>            ::= "hours" | "minutes"

<monthly-rule>         ::= "every month on the " <monthly-selector> " at " <time>
<monthly-selector>     ::= "last day"
                         | <monthday-list>
                         | <ordinal> " " <weekday>

<yearly-date>          ::= "every year on " <month-day> " at " <time>
<yearly-nth-weekday>   ::= "every year on the " <ordinal> " " <weekday>
                           " of " <month-name> " at " <time>

4) Suffixes (ordre libre)

<date-window>   ::= " between " <date> " and " <date>
<until-window>  ::= " until " <date>
<except-clause> ::= " except " <except-item-list>
<except-item-list> ::= <except-item> { ("," | " ") <except-item> }
<except-item>   ::= <weekday>
                  | <date>
                  | "public holidays"
                  | "on public holidays"
<weekend-shift> ::= " if weekend then next monday"
                  | " if weekend then next business day"

Exemples exhaustifs par cas de la grammaire

A) One-shot date/time

2026-01-15 at 09:00
2026-12-31 at 11:45pm

B) Every day

every day at 09:00
every day at 09:00 and 17:00

C) Every weekday

every weekday at 09:00
every weekday at 9am and 5pm

D) Named weekday list

every monday and wednesday at 08:30
every tuesday, thursday and friday at 14:00

E) Every N units

every 15 minutes
every 2 hours
every 2 weeks on monday at 08:30

F) Hourly between

every hour between 09:00 and 17:00
every 2 hours between 08:00 and 20:00

G) Step within day

every day every 2 hours between 08:00 and 20:00
every weekday every 30 minutes between 09:00 and 18:00

H) Monthly patterns

every month on the 1st and 15th at 09:00
every month on the last day at 18:00
every month on the first monday at 10:00

I) Yearly fixed date

every year on 07-14 at 09:00
every year on 12-31 at 23:30

J) Yearly nth weekday

every year on the first monday of september at 09:00
every year on the last friday of november at 18:00

K) Date windows / until

every day at 09:00 between 2026-01-01 and 2026-03-31
every weekday at 09:00 until 2026-12-31

L) Exceptions

every weekday at 09:00 except monday
every day at 09:00 except 2026-08-15
every day at 09:00 except public holidays
every day at 09:00 except on public holidays

M) Weekend shifts

every month on the 1st at 09:00 if weekend then next monday
every year on 01-01 at 09:00 if weekend then next business day

N) Multi-rule schedule and timezone suffix

every weekday at 09:00, and every month on the last friday at 18:00
every day at 09:00, and every day at 17:00 in Europe/Paris

Équivalents français (normalisés automatiquement)

Ces formulations françaises sont acceptées, puis normalisées en anglais en interne avant parsing.

tous les jours à 09:00
tous les jours ouvrés à 09:00 et 17:00
toutes les 2 semaines le lundi à 08:30
chaque mois le dernier vendredi à 18:00
tous les jours à 09:00 en Europe/Paris
tous les jours à 09:00 sauf jours fériés
tous les jours à 09:00 sauf le lundi
tous les jours à 09:00 jusqu'au 2026-12-31

Example library (ready to copy/paste)

1) Daily basics

every day at 09:00
every day at 08:00 and 18:00
every day at 07:30 and 12:00 and 20:30
every day at 6am
every day at 8:15pm
tous les jours à 09:00
tous les jours à 08:00 et 18:00

2) Weekdays vs named weekdays

every weekday at 09:00
every weekday at 09:00 and 17:00
every monday and wednesday and friday at 08:30
every tuesday and thursday at 10:00
every saturday and sunday at 11:00
tous les jours ouvrés à 09:00
tous les lundis, mercredis et vendredis à 08:30

3) Every N minutes/hours/days/weeks

every 15 minutes
every 30 minutes
every 2 hours
every 4 hours at 09:00
every 2 days at 08:00
every 2 weeks on monday at 08:30
every 3 weeks on tuesday and thursday at 14:00
toutes les 2 semaines le lundi à 08:30

4) Hourly between

every hour between 09:00 and 17:00
every hour between 8am and 6pm
every 2 hours between 08:00 and 20:00
every 3 hours between 00:00 and 23:00
every hour between 06:30 and 22:30
toutes les heures entre 09:00 et 17:00

5) Step within day

every day every 2 hours between 08:00 and 20:00
every day every 30 minutes between 09:00 and 12:00
every weekday every 60 minutes between 09:00 and 18:00
every weekday every 15 minutes between 08:30 and 10:00
every weekday every 2 hours between 10:00 and 16:00
tous les jours ouvrés toutes les 30 minutes entre 09:00 et 18:00

6) Monthly patterns

every month on the 1st at 09:00
every month on the 1st and 15th at 09:00
every month on the last day at 18:00
every month on the first monday at 10:00
every month on the last friday at 18:00
every month on the 5th, 10th and 20th at 07:45
chaque mois le premier lundi à 10:00
chaque mois le dernier vendredi à 18:00

7) Yearly patterns

every year on 01-01 at 09:00
every year on 07-14 at 09:00
every year on 12-31 at 23:30
every year on the first monday of september at 09:00
every year on the last friday of november at 18:00
every year on the third thursday of june at 14:00
chaque année le 14-07 à 09:00

8) Date windows / until

every day at 09:00 between 2026-01-01 and 2026-01-31
every weekday at 09:00 between 2026-02-01 and 2026-06-30
every 2 weeks on monday at 08:30 between 2026-01-01 and 2026-12-31
every month on the last friday at 18:00 until 2027-12-31
every day every 2 hours between 08:00 and 20:00 until 2026-09-30
tous les jours à 09:00 jusqu'au 2026-12-31

9) Exceptions

every day at 09:00 except monday
every weekday at 09:00 except friday
every day at 09:00 except 2026-08-15
every day at 09:00 except 2026-08-15, 2026-08-16
every day at 09:00 except public holidays
every day at 09:00 except on public holidays
tous les jours à 09:00 sauf le lundi
tous les jours à 09:00 sauf jours fériés

10) Weekend shift

every month on the 1st at 09:00 if weekend then next monday
every month on the last day at 09:00 if weekend then next monday
every year on 01-01 at 09:00 if weekend then next business day
every year on 12-31 at 18:00 if weekend then next business day
every month on the first monday at 09:00 if weekend then next business day
chaque mois le 1er à 09:00 si week-end alors lundi suivant

11) Time formats

every day at 09:00
every day at 9:00
every day at 9am
every day at 9:30am
every day at 5pm
every day at 11:45pm
every weekday at 9am and 5pm

12) Multi-rule schedules with ", and"

every weekday at 09:00, and every month on the last friday at 18:00
every day at 09:00, and every day at 17:00
every 2 weeks on monday at 08:30, and every year on 12-31 at 18:00
every day at 09:00 except public holidays, and every month on the 1st at 08:00
every weekday at 09:00 until 2026-12-31, and every year on 01-01 at 09:00
tous les jours à 09:00, and every month on the last day at 18:00

13) Timezones

every day at 09:00 in Europe/Paris
every weekday at 09:00 and 17:00 in Europe/Paris
every day at 09:00 in America/New_York
every month on the last friday at 18:00 in America/New_York
every day at 09:00 in Asia/Manila
every year on 12-31 at 23:30 in Asia/Manila

Quick start

  • every day at 09:00 — one reminder every day at 09:00.
  • every weekday at 09:00 and 17:00 — two reminders on business days.
  • every 2 weeks on monday at 08:30 — bi-weekly reminder on Monday morning.
  • every month on the last friday at 18:00 — month-end close reminder.
  • every day at 09:00 in Europe/Paris — explicit timezone schedule.

Common errors

  • Wrong pluralisation: use every day, not every days.
  • Missing "at": use every weekday at 09:00 and 17:00.
  • Wrong timezone format: use IANA zones like Europe/Paris, not UTC+1.
  • Multi-rule separator: use , and between rules.
  • Mixed FR/EN tokens: avoid mixed forms like tous les jours at 09:00; use either tous les jours à 09:00 or every day at 09:00.