AnvilJSON utilities

Anvil › Docs › /v1/cron/explain

Cron explainer API: plain-English schedule + next runs

Paste a cron expression and get back what it means in one sentence, which values each field expands to, a warning when day-of-month and day-of-week are ORed, and the next times it will fire in the zone you name. Same rules as crontab, Kubernetes CronJobs and Tooltern's browser cron explainer — useful from a script, CI job or admin page.

In one line: GET /v1/cron/explain?expr=%2A/15%209-17%20%2A%20%2A%20mon-fri&tz=UTC&count=5 returns JSON. No key, CORS on, 60 requests a minute.
GET

/v1/cron/explain

Explain a cron schedule in plain English, with next runs. Change the values and press Send request to call the live API.

Parameters

NameTypeWhat it doesDefault
expr requiredstring5-field cron expression or @daily, @hourly…—
tzstringTime zone the schedule runs inUTC
countintegerNext runs to list, 1 to 505
fromstringStart after this moment (ISO 8601 / Unix)now

Example

Request:

GET https://api.oddlathe.com/v1/cron/explain?expr=%2A/15%209-17%20%2A%20%2A%20mon-fri&tz=UTC&count=5

Response (generated by the real code when these docs were last built; random or time-based values will differ for you):

{
 "expr": "*/15 9-17 * * mon-fri",
 "shortcut": null,
 "description": "Every 15 minutes, between 09:00 and 17:59, on Monday through Friday.",
 "fields": [
  {
   "name": "minute",
   "raw": "*/15",
   "any": false,
   "values": [
    0,
    15,
    30,
    45
   ],
   "values_text": "0, 15, 30, 45"
  },
  {
   "name": "hour",
   "raw": "9-17",
   "any": false,
   "values": [
    9,
    10,
    11,
    12,
    13,
    14,
    15,
    16,
    17
   ],
   "values_text": "9, 10, 11, 12, 13, 14, 15, 16, 17"
  },
  {
   "name": "day of month",
 …

Code examples

curl
curl -G 'https://api.oddlathe.com/v1/cron/explain' \
  --data-urlencode 'expr=*/15 9-17 * * mon-fri' \
  --data-urlencode 'tz=UTC' \
  --data-urlencode 'count=5'
JavaScript (browser or Node 18+)
const params = new URLSearchParams({
  expr: "*/15 9-17 * * mon-fri",
  tz: "UTC",
  count: "5"
});
const res = await fetch(`https://api.oddlathe.com/v1/cron/explain?${params}`);
if (!res.ok) throw new Error((await res.json()).error.message);
const data = await res.json();
console.log(data);
Python (standard library only)
import json, urllib.parse, urllib.request

params = urllib.parse.urlencode({"expr": "*/15 9-17 * * mon-fri", "tz": "UTC", "count": "5"})
url = "https://api.oddlathe.com/v1/cron/explain?" + params
# Send a User-Agent: the edge network refuses Python's default one.
req = urllib.request.Request(url, headers={"User-Agent": "my-script/1.0"})
with urllib.request.urlopen(req, timeout=10) as r:
    data = json.load(r)
print(data)

When it's useful

  • Showing "next backup at…" with a human label in an admin UI
  • CI checks that a CronJob or crontab change still means what you think
  • Teaching the day-of-month OR day-of-week rule before someone ships Friday-the-13th-only by mistake
  • Sanity-checking schedules that never run (30 February) before deploy

Good to know

  • Five fields: minute, hour, day of month, month, day of week. Lists (1,15), ranges (9-17), steps (*/15), names (mon-fri, jan), 7 as Sunday, and @hourly, @daily, @weekly, @monthly, @yearly / @annually, @midnight.
  • description is one plain-English sentence. fields lists each field with raw, any, the expanded values and a short values_text.
  • The OR rule: if both day-of-month and day-of-week are restricted, a day matching either one counts. The response sets dom_dow_or: true and adds a dom_dow_or warning. Example: 0 0 13 * 5 runs on every 13th and every Friday.
  • Times skipped when clocks go forward are left out; times that repeat when clocks go back run once. Encode spaces as %20 (or use curl -G --data-urlencode).
  • Prefer next-run times only? Use sibling /v1/cron/next. Prefer a page to an API? Tooltern's cron expression explainer runs entirely in your browser.

Sibling of /v1/cron/next and of Tooltern's cron explainer: breaks each field down, writes one plain-English sentence, lists the next runs (DST-aware) and warns when day-of-month and day-of-week are ORed. Lists, ranges, steps, month/weekday names, 7 as Sunday, and @hourly/@daily/@weekly/@monthly/@yearly. Pure parsing; nothing is stored.

Errors

Errors are JSON like {"error": {"code": "…", "message": "…"}}. The ones this endpoint can return:

  • missing_param (400): a required parameter is missing or empty
  • bad_param (400): a value is the wrong type or out of range (the message says which)
  • bad_timezone (400): the zone isn't a known IANA name
  • bad_cron (400): the expression can't be parsed; the message names the field
  • rate_limited (429): over 60 requests a minute; wait for Retry-After seconds

Questions

How is this different from /v1/cron/next?

Both return next runs. This endpoint also returns a plain-English description, a per-field breakdown and OR-rule warnings — everything Tooltern's cron page shows, as JSON.

Does it support seconds or a year field?

No. Six- or seven-field formats are Quartz/Spring extensions; this API reads classic 5-field Vixie cron.

What about @reboot?

It returns bad_cron: @reboot fires once when the daemon starts, so there is no repeating schedule to explain.

Which time zone should I use?

Match the machine (or CRON_TZ) that will run the job. Servers are usually UTC; GitHub Actions schedules are UTC and often start a few minutes late under load.

Related endpoints

Prefer a page to an API?

Published , updated · OpenAPI 3.1 spec · Limits and privacy