Cron: run on the last day of the month — and the last business day
Translated from the canonical Japanese page recipes/cron-last-day-of-month.md.
“Run at the end of every month” is one of cron’s most common stumbling blocks (325k views on Stack Overflow). In Kairos, both variants are one-line expressions:
monthEnd # last day of the month
bizDay |> within(month) |> last # last business day of the month
What happens with cron
- Standard cron has no “last day”. The usual workaround is listing
28-31and testing in a script; Kubernetes CronJob sees the same request re-raised in issues over and over. - Quartz’s dialect
L(last day) andLW(last weekday) are handy but not portable across schedulers, and holidays are out of reach (the W inLWonly avoids weekends). - For the last business day, even Google Calendar only accepts it via an ICS import that then carries an “uneditable” warning.
The root cause is not a missing feature but that expressions do not compose — even if you can produce “month-end”, you cannot feed the result into the next rule (“roll backward onto business days”).
Writing it in Kairos
The holiday-aware last business day of the month, under the standard @JP premise (whose bizDay
is derived from weekends plus Japan’s holiday data):
# eval: 2026-01-01..2026-07-01
@JP
bizDay |> within(month) |> last
#=> 2026-01-30 2026-02-27 2026-03-31 2026-04-30 2026-05-29 2026-06-30
January (1/31 Sat) and May (5/30 Sat, 5/31 Sun) correctly retreat to Friday. “Build the stream of
business days, take the last point of each month” — the structure reads exactly as stated, the
holidays come from calendar data (with covering:), and when that data runs out the result
carries an annotation instead of silently degrading.
Counting back from month-end composes from the same vocabulary:
monthEnd |> roll(Preceding, on: bizDay) |> shift(-3, unit: bizDay) # 3 business days before month-end
Try it in your browser
A self-contained form (the holiday table inline) is ready to run in the Playground — move from/to around, add holidays, and watch the behavior.
Related
- Same family: the 31st of every month (writing the two different intents for missing months as two different expressions), the Nth business day, every N business days — study 11, measured section
- Vocabulary:
within·last·roll·shift - Bringing in holiday data and governing its freshness (
covering:/asof:): spec §4.10