CronTool
Cron expression editor & debugger

robfig/cron — last day of the month in Go

robfig/cron is the dominant cron library in the Go ecosystem, but its standard parser does not support the L modifier. To run a job on the last day of every month, you have two options: a runtime check inside the job, or the portable multi-cron approach with three cron entries.
See the full robfig/cron guide for the parser's syntax options and gotchas, or the general last-day-of-month guide for the cross-library overview.

Examples

  • 018***
    Every day at 18:00
  • 0*/5***
    Every 5 hours
  • 018**1-5
    Weekdays at 18:00
  • 001**
    Once a month

Cheatsheet

FieldRequiredValues RangeWildcardsminuteYes0-59, - * / hourYes0-59, - * / day of monthYes1-31, - * / L W monthYes1-12, - * /day of weekYes0-7, - * / L

Calendar

View future cron matches in a calendar

April 2026

Showing next 1000 cron schedules

Loading...

Runtime check inside the job

The cleanest pattern: schedule daily, check if today is the last day, exit early otherwise. The schedule expression stays standard cron; the “last day” logic lives in Go where it's easier to test.

package main

import (
    "time"

    "github.com/robfig/cron/v3"
)

func isLastDayOfMonth(t time.Time) bool {
    return t.AddDate(0, 0, 1).Day() == 1
}

func main() {
    c := cron.New()
    c.AddFunc("0 0 * * *", func() {
        if !isLastDayOfMonth(time.Now()) {
            return
        }
        // ... your last-day-of-month work here
    })
    c.Start()
    select {}
}

Multi-cron approach (no runtime check)

If you prefer to keep the “last day” logic in the cron expression itself, register three crons covering the actual last days of each month length:

c := cron.New()
c.AddFunc("0 0 30 4,6,9,11 *", monthEndJob)        // 30-day months
c.AddFunc("0 0 31 1,3,5,7,8,10,12 *", monthEndJob) // 31-day months
c.AddFunc("0 0 28 2 *", monthEndJob)               // February (28)
c.AddFunc("0 0 29 2 *", func() {                   // February (29) — leap years only
    if time.Now().Month() == time.February && isLastDayOfMonth(time.Now()) {
        monthEndJob()
    }
})
c.Start()

The Feb 29 entry needs a runtime check because the literal value 29 matches every Feb 29, not just leap years. The function double-checks “is today truly the last day of February?”.

Go cron libraries that support `L`

  • github.com/adhocore/gronx — supports L, W, # modifiers and step ranges. Quartz-compatible.
  • github.com/gorhill/cronexpr — supports L, W, L-N arithmetic. Last updated less frequently but stable.
  • github.com/go-co-op/gocron — uses its own interval API rather than cron strings; supports “last day of month” via scheduler.Cron(...) with a custom format.

If you're already on robfig/cron and just need last-day-of-month support, the runtime-check pattern is probably less disruptive than swapping libraries.

Pitfalls when faking `L` in robfig/cron

  • Timezone — robfig/cron defaults to local time; be explicit with cron.WithLocation(time.UTC) if your job runs in containers.
  • Daylight saving — the “last day at midnight” firing can be skipped or doubled when DST transitions happen at month boundaries.
  • Idempotency — if you use a runtime check, still make the job idempotent. A retry, a misfire or a container restart could trigger the job twice in the same day.

Frequently asked questions

Does robfig/cron support the L modifier?

Out of the box, robfig/cron v3 uses a strict standard parser that does NOT support `L`. You can opt into a more permissive parser via cron options, but as of v3.x there is no built-in `L` token. The portable approach is to schedule daily and self-skip in the job, or use a wrapper that computes the last day at runtime.

How do I get last-day-of-month behaviour with robfig/cron?

Schedule the job daily (`0 0 * * *`) and have the job's first action be a check: if `time.Now().AddDate(0, 0, 1).Day() == 1`, the current day is the last of the month — proceed. Otherwise, return early. This keeps the cron expression standard and the date logic in Go where it belongs.

Can I use the multi-cron last-day-of-month pattern with robfig?

Yes — call `c.AddFunc` three times with the standard month-length expressions: `0 0 30 4,6,9,11 *`, `0 0 31 1,3,5,7,8,10,12 *`, and `0 0 28 2 *` (or `0 0 28,29 2 *` for a leap-year-safe variant). robfig/cron's standard parser accepts all three.

What about other Go cron libraries?

Most Go cron libraries (gocron, cronexpr, adhocore/gronx) follow either standard cron syntax or Quartz-style. `gronx` from adhocore explicitly supports `L`. `cronexpr` supports `L` and `W`. If `L` support matters, prefer one of those over robfig/cron v3, or switch to a wrapper-based approach.

What options does robfig/cron's parser take?

robfig/cron's `cron.NewParser` accepts a bitmask of fields: `Second`, `Minute`, `Hour`, `Dom`, `Month`, `Dow`, `Descriptor`. To enable seconds: `cron.SecondOptional | cron.Minute | …`. The `L` modifier is not in this list — there's no flag to enable it.

Ready to schedule it?

Point Crontap at any URL. Pick any cron. Done.

WordPress, Shopify, Railway, Cloud Run, Vercel, HubSpot, Ghost, your own box. If it answers HTTP, Crontap can drive it on a clock you can read, in the timezone that actually matters, and page you when something breaks.

Free forever tier ・ No credit card required

Your next schedule
GET/wp-cron.php?doing_wp_cron=1

Schedule

every 5 minutes

Next run

in 23s

Apihustle Logo

This tool is part of the Apihustle suite - a collection of tools to test, improve and get to know your API inside and out.

  • Clobbr logo

    Clobbr

    The app & CLI tool to test API endpoint speed.

    Visit
  • Crontap logo

    Crontap

    Schedule recurring API calls using cron syntax.

    Visit
  • CronTool logo

    CronTool

    Debug multiple cron expressions on a calendar.

    Visit

  • Page AI

    AI Website Generator that designs and writes clean code.

    Visit
  • Shipixen

    Generate customized boilerplates in minutes.

    Visit
  • Page UI

    Landing page UI components for React & Next.js

    Visit