Expression Syntax
September 10, 2025 · View on GitHub
NaturalCron supports a simple, human-readable syntax for defining recurring schedules.
You can use keywords like every, on, at, between, upto, and from to build powerful recurrence rules.
Note:
The @ prefix is optional.
For example:
@every day @at 9:00amorevery day at 9:00am✅
Supported Rules
every— Main recurrence intervalon,in,at— Specific occurrencesbetween— Range filtersupto,from— Boundary filterstimezoneortz— Time zone specification
every or @every — Main Recurrence Interval
Defines how often the recurrence happens.
The interval must be a positive integer, and the time unit must be one of the supported units.
Syntax:
every <number> <time-unit>
Examples:
every day— every dayevery 2 weeks— every 2 weeksevery 6 months— every 6 monthsevery year— every year
Anchored Recurrences
The AnchoredOn keyword lets you fix the schedule to a specific anchor point, useful for fiscal or seasonal rules.
Syntax:
every <number> <time-unit> AnchoredOn <month|number|week|ordinal day>
Note: The anchor must be of the same time unit as the recurrence interval (e.g., for
every 2 months, only months are valid forAnchoredOn).
Examples:
every 2 months AnchoredOn Nov on 1st
→ Always runs on the 1st of Nov, Jan, Mar, May, Jul, Sep.every 6 months AnchoredOn Feb on 1st
→ Always runs in Feb and Aug.
Notes:
- Only one
everyrule is allowed per expression. - The interval must be greater than zero (e.g.,
every 0 daysis invalid).
Shortcut Keywords
secondly,minutely,hourly,daily,weekly,monthly,yearly
These are equivalent to every 1 <time-unit>:
hourly between 09:00 and 17:00monthly on 1st
You can use these shortcuts for more concise and readable recurrence expressions.
on, in, at or @on, @in, @at — Specific Occurrences
Defines when the recurrence happens.
Syntax:
on <time-unit> <number>in <time-unit> <number>at <time-unit> <number>
For multiple uses bracket the time units and numbers:
on [<time-unit> <number>, ...]in [<time-unit> <number>, ...]at [<time-unit> <number>, ...]
Examples:
on day 10— on the 10th day of the month or juston 10thin month 10— in october or usein octoberorin octat hour 10 at minute 30orat 10:30am— at 10:30am
Examples:
on [day 1, day 20, day 30]oron [1st, 20th, 30th]— on the 1st, 20th, and 30th days of the monthat [10:00pm, 12:00am]orat [22:00, 00:00]orat [10:00pm, 12:00am]— If neitheramnorpmis specified, the time will be interpreted using 24-hour notation by default.on [friday, saturday]oron [fri, sat]— on Friday or Saturday
Special Days
-
Closest weekday to a specific day:
on ClosestWeekdayTo <number>— Matches the weekday (Monday–Friday) that is closest to the given day of the month.
Example:on ClosestWeekdayTo 15th— the closest weekday to the 15th of the month.Edge Cases:
- If the given day falls on a weekday (Monday–Friday), it is selected directly.
- If it falls on a Saturday, the engine will select the preceding Friday.
- If it falls on a Sunday, the engine will select the following Monday.
- Special case: If the first day of the month is a Saturday (
on ClosestWeekdayTo 1st), the closest weekday is the following Monday (the 3rd of the month). - Similarly, if the last day of the month is a Sunday, the closest weekday is the preceding Friday.
Examples:
- If the 1st of the month is a Saturday,
on ClosestWeekdayTo 1stmatches the 3rd (Monday). - If the 1st is a Sunday, it matches the 2nd (Monday).
- If the 15th is a Saturday, it matches the 14th (Friday).
- If the 15th is a Sunday, it matches the 16th (Monday).
-
First weekday of the month:
on FirstWeekday— Matches the first weekday (Monday–Friday) of the month.
Example:on FirstWeekday -
Last weekday of the month:
on LastWeekday— Matches the last weekday (Monday–Friday) of the month.
Example:on LastWeekday -
First or last day of the month:
You can use any of the following interchangeable keywords to match the first or last day of the month:-
Last day of the month:
on LastDayOfTheMonthon LastDayOfMonthon LastDay
-
First day of the month:
on FirstOfTheMonthon FirstDayOfMonthon FirstDay
Examples:
every month on LastDay— triggers on the last day of every month.every month on FirstDayOfMonth— triggers on the first day of every month.
-
-
Specific weekday occurrence in the month:
Use numeric or word-based ordinals, and full or abbreviated weekday names. Ordinals from1stto5thare supported (note: not all months have a 5th occurrence).- Examples:
on 1stMon,on 1stMonday,on FirstMon,on FirstMonday— all specify the first Monday of the month.on 2ndTuesday,on ThirdFri,on 5thMonday— specify the second Tuesday, third Friday, or fifth Monday of the month, respectively.
- Examples:
-
Basic arithmetic with day keywords:
The recurrence engine supports simple arithmetic operations (+and-) with day-based keywords.
Examples:on LastDay - 1— matches the day before the last day of the month (i.e., the second-to-last day).on FirstDay + 2— matches the third day of the month. It never crosses month boundaries, e.gon FirstDay + 31it will match the last day of the month. oron LastDay - 31it will match the first day of the month.
Note:
The recurrence engine does not make a strict distinction between on, at, and in when used in expressions.
This design choice is intentional to prioritize flexibility and ease of use. By treating these keywords equivalently, the recurrence engine allows users to write expressions in a way that feels most natural to them, without worrying about strict syntax rules. This approach also simplifies parsing and ensures that the system can accommodate a wide range of user preferences and writing styles.
between or @between Between Rules
The between rule allows you to restrict occurrences to a specific range—such as a range of days in the month, times within a day, or other supported units.
Syntax:
<start>and<end>can be days, times, or other supported units/aliases.
Examples:
every hour between 10th and 15th
Matches only the 10th through 15th day of each hour.every hour between 09:00 and 17:00
Matches only occurrences between 9:00am and 5:00pm each hour.every week between Jun and Dec
Matches weekly occurrences between June and December.every day between 2nd and LastDayMatches only the second through last day of month each dayevery 25 secs between [1:00pm and 03:00pm, 6:00pm and 8:00pm]Matches only occurrences between 1:00pm and 3:00pm, and 6:00pm and 8:00pm, every 25 seconds.
Notes:
- The boundaries in the
betweenrule are inclusive. For example,between 10th and 15thincludes both the 10th and the 15th. - You can use any supported aliases for days, times, or months in the
betweenrule. betweencan be combined with other rules (such ason,at, etc.) for more precise filtering.
upto and from or @upto and @from Rules
The upto and from rules allow you to restrict occurrences to only those before or after a specific point (such as a time, day, or other supported unit), relative to the recurrence interval.
Syntax:
upto <value>from <value>
<value> can be a time, day, or any supported alias (e.g., upto 13:00, after 09:00, upto 15th).
Examples:
every 10 secs upto 1:00pm
Matches every 10 seconds, including 1:00pm, but only up to and including 1:00pm each 10 seconds.every minute from 18:00
Matches every minute, including 6:00pm, and all times after on each minute.every day upto 15th
Matches all days up to and including the 15th of each month.every hour from 09:00
Matches every hour, starting from and including 9:00am each hour.
Notes:
- The boundary value itself is included; for example,
upto 1:00pmmatches up to and including 1:00pm. - You can use any supported aliases for times, days, or months.
uptoandfromcan be combined with other rules (such ason,at, etc.) for more precise filtering.
Time Zone Support
You can specify the time zone for your recurrence expressions using either timezone or the shorthand tz.
This ensures that all date and time calculations are made in the specified IANA time zone.
Syntax:
timezone <IANA-timezone>or@timezone <IANA-timezone>tz <IANA-timezone>ortz <IANA-timezone>
Examples:
every day at 09:00 timezone America/New_Yorkorevery day at 09:00 tz America/New_Yorkmonthly on 1st tz Asia/Tokyoormonthly on 1st tz Asia/Tokyo
Notes:
- The engine uses IANA time zone names (e.g.,
America/Los_Angeles,Europe/London). - Time zone rules affect all time-based calculations, including DST transitions.
Supported time units and aliases
The following units and their aliases can be used with all relevant rules, such as every, on, and between, as well as upto and from:
| Unit | Aliases |
|---|---|
| second | second, sec, secs, seconds |
| minute | minute, min, mins, minutes |
| hour | hour, hr, hrs, hours |
| day | day, dy, days, dys |
| week | week, wk, weeks, wks |
| month | month, mth, months, mths |
| year | year, yr, years, yrs |
Examples:
every 2 weekson day 10between hour 9 and hour 17on month 12
You can use any alias interchangeably in your recurrence expressions.
Specifying Time in Recurrence Expressions
You can specify times in your recurrence expressions using several supported formats. The engine accepts both 12-hour and 24-hour notation, and you can include seconds if needed.
Supported Time Formats:
2:00pm— 12-hour clock witham/pm14:00— 24-hour clock (hours and minutes)14:00:10— 24-hour clock with seconds2:00:10pm— 12-hour clock with seconds andam/pm
Examples:
every day at 2:00pm— triggers at 2:00pm each dayevery day at 14:00— triggers at 14:00 (2:00pm) each dayevery day at 14:00:10— triggers at 2:00:10pm each dayevery day at 2:00:10pm— triggers at 2:00:10pm each day
Notes:
- If neither
amnorpmis specified, the time is interpreted as 24-hour format by default. - Seconds are optional; if omitted, the time matches at the start of the specified minute.
- You can use these formats in any rule that accepts a time value, such as
at,on,between,from, andupto.
Specifying Dates in Recurrence Expressions
You can specify dates in your recurrence expressions using the following formats:
Supported Date Formats: Ordinal Date (e.g., 1st, 2nd, 3rd, 4th, 5th, etc.):
1st— the first day of the month2nd— the second day of the month3rd— the third day of the month4th— the fourth day of the month etc.
Month Name (e.g., January, February, etc.):
JanuaryorJanFebruaryorFebetc.
Weekday Name (e.g., Monday, Tuesday, etc.):
MondayorMonTuesdayorTueetc.
Time with am/pm:
10pmor10:00pmor22:00
Dashed Separated Date (e.g., 2023-01-23):
Jan-23— January 23rd12-31— December 31st2023-01-23— January 23rd, 20232023-12-31— December 31st, 20232023-JAN— January 2023
Ordinal Day + Month Name (e.g., 1st January, 2nd February, etc.):
1st Januaryor1st JanorJanuary 1storJan 1st2nd Februaryor2nd FeborFebruary 2ndorFeb 2nd
Ordinal Day + Month Name + Year (e.g., 1st January 2023, 2nd February 2023, etc.):
1st January 2023or1st Jan 2023orJanuary 1st 2023orJan 1st 20232nd February 2023or2nd Feb 2023orFebruary 2nd 2023orFeb 2nd 2023
Colon + Dashed Separated Date (e.g., 2023-01-23): it allows the combination of date and time
2023-01-23 14:00— January 23rd, 2023 at 14:00JAN-23 14:00:10— January 23rd, 2023 at 14:00:10
Colon + ordinal day (e.g. 1st JAN 14:00)
1st JAN 14:00or1st JAN 14:00:10or1st JAN 2:00pmor1st JAN 2:00:10pmor1st JAN 2pm
Weekday + time with am/pm:
Mon 14:00orMon 2pm
Special Date + Time:
1stMonday 2pmor1stMonday 14:00or1stMonday 2:00pm2ndTuesday 2pmor2ndTuesday 14:00or2ndTuesday 2:00pmFirstWeekDay 2pmorFirstWeekDay 14:00orFirstWeekDay 2:00pm
Note: Commas are ignored in single date expressions but not allowed in bracketed multiple date expressions.
on 1st, January(comma is ignored) ✅on [1st, January](invalid syntax in brackets) ❌