Build a cron expression and see its next runs in the zone the job will actually run in, with the day-of-month OR day-of-week rule and the daylight saving rules of crontab(5) applied
Initializing in your browser…
Generate realistic fake data for testing and development. Create names, usernames, emails, addresses, phone numbers, and more. Export to JSON or CSV format
Build a Content Security Policy and see what a browser will actually apply, including the CSP3 rules that silently discard what you wrote.
Generate passwords from the Web Crypto generator by rejection sampling, with the entropy stated exactly from the alphabet, the cost of every rule computed, and crack times against four named attacker models
Two schedules that look obvious and are not. Someone writes 0 0 13 * 5 meaning Friday the 13th, and someone else puts a backup at 02:30 on a server in New York.
Typed
0 0 13 * 5 30 2 * * * (zone: America/New_York)
What each one really does
0 0 13 * 5
At 00:00 on the 13th of the month OR on Friday
crontab(5) ORs the two day fields when both are restricted
Both day fields are restricted, so crontab(5) says the job runs when
EITHER matches, not when both do.
Fri, 19 Jun 2026, 00:00
Fri, 26 Jun 2026, 00:00
Fri, 03 Jul 2026, 00:00
Fri, 10 Jul 2026, 00:00
Mon, 13 Jul 2026, 00:00
Fri, 17 Jul 2026, 00:00
30 2 * * * in America/New_York, from the evening of 7 March 2026
At 02:30.
Sun, 08 Mar 2026, 03:00 -04:00
02:30 does not exist on this date because the clocks go forward.
crontab(5) says a job that would have run in the skipped interval
runs immediately, so it fires at 03:00 instead.
Mon, 09 Mar 2026, 02:30 -04:00
Tue, 10 Mar 2026, 02:30 -04:00The first expression is the classic. It reads like Friday the 13th and it is not: crontab(5) says that when both day fields are restricted the job runs when either matches, so it fires on every Friday and additionally on the 13th of every month, which is 13 July 2026, a Monday. A tool that ANDs the two fields lists only the Friday the 13ths, which are years apart, and the job then runs far more often in production than its run list promised. The second is the other one. 02:30 happens on 364 mornings a year in New York and not on the 365th, and crontab(5) says the job that would have run in the skipped interval runs immediately, so it fires at 03:00 that once. The same job on the November morning fires once at the first of the two 01:30s rather than twice. Both behaviours depend on the hour field being restricted; a job at */30 follows real time and gets neither treatment. Every run time here is checked in the project's tests against a second implementation of crontab(5) written in Python, across 22 expressions and five time zones.
Write a cron expression and find out what it actually does before you deploy it. Every field is read against crontab(5), the schedule is read back in plain language, and the next eight runs are computed in whichever time zone the job will run in, not in yours. Two rules that catch people out are applied and explained on the page: when both day fields are restricted the job runs when EITHER matches, and a job at a specific hour behaves differently on the two mornings a year when the clocks change.
The first is the day fields. crontab(5) says: "if both fields are restricted (that is, do not contain the * character), the command will be run when either field matches the current time". So `0 0 13 * 5` does not mean Friday the 13th. It means the 13th of every month, and also every Friday, which from 15 June 2026 gives 19 June, 26 June, 3 July, 10 July, 13 July and 17 July. A tool that ANDs the two fields would list only the Friday the 13ths, which are years apart. Both day fields restricted is flagged on the page with the rule quoted, because the expression is usually not what its author meant.
The second is daylight saving. crontab(5) again: "Local time changes of less than three hours ... are handled specially. This only applies to jobs that run at a specific time... If time has moved forward, those jobs that would have run in the interval that has been skipped will be run immediately. Conversely, if time has moved backward, care is taken to avoid running jobs twice." So `30 2 * * *` in America/New_York on 8 March 2026 fires at 03:00, because 02:30 does not exist that morning, and `30 1 * * *` on 1 November fires once, at the first of the two 01:30s. A job whose hour field is `*` is not given that treatment at all: it follows real time, so an hourly job really does run twice in the repeated hour. The page marks each affected run, says which rule applied, and has a panel showing what happens at the next change in the chosen zone.
The zone is a control rather than an assumption. A cron job runs in the time zone of the machine running it, which on a cloud scheduler is usually UTC and is almost never the zone of the person writing the expression. All the zones the browser knows are offered, the abbreviation in force at the moment is shown beside the selection, and the offset is printed against every run.
Everything else follows from reading the fields properly. Month and day names work (`0 9 * * MON-FRI`, `0 0 1 JAN *`), 7 is Sunday as well as 0, `5/15` means from minute 5 in steps of 15, and the `@daily`, `@hourly`, `@weekly`, `@monthly`, `@yearly`, `@annually` and `@midnight` macros expand to the expressions crontab(5) gives them. `@reboot` is recognised and refused, because it has no schedule to show. Anything that cannot be read is refused with the reason and the field is outlined, rather than being silently replaced by `* * * * *`.
Three dialects are offered because three are in use. The five-field Unix form is what crontab, GitHub Actions, GitLab CI and a Kubernetes CronJob take. A six-field form with seconds on the front is what node-cron and Spring's `@Scheduled` take. Quartz has both a seconds field and an optional year field, its own operators (`?`, `L`, `LW`, `L-3`, `15W`, `6#2`) and, importantly, its own day-of-week numbering that starts at 1 for Sunday, so every weekday number is one higher than in Unix cron. That difference is called out in the reference table rather than left to be discovered in production.
The search walks the calendar rather than every minute. `0 0 29 2 *` finds its next three runs after examining three candidate times; stepping minute by minute would take about 5.3 million steps to reach the third leap year, and an expression that can never fire would cost a full year of minutes on every keystroke.
All of this is checked. The project's tests compare the run times against a second implementation of crontab(5) written in Python, over 22 expressions in 5 time zones, and the daylight saving cases against instants computed from the transitions themselves: 262 assertions in the module and 87 in the browser.
0 9 * * 1-5 reads as "At 09:00 on weekdays". 0 9 * * MON-FRI is the same expression with names, and both produce the same runs.
0 0 13 * 5 is flagged and read back as "At 00:00 on the 13th of the month OR on Friday", because crontab(5) ORs the two day fields when both are restricted.
GitHub Actions and GitLab CI both run cron in UTC. Set the zone to UTC here and the run list is what will actually happen, rather than what it would do on your laptop.
Set the zone to the server's and check the clock-change panel. A backup at 02:30 has one morning a year where it does not exist and one where it happens twice.
Paste the line and read it back in words. If both day fields are set, the warning tells you it fires far more often than the author probably meant.
Switch dialect to compare. A Quartz day-of-week number is one higher than the Unix one for the same day, which is the usual reason a migrated job runs on the wrong day.
Expressions such as 0 0 30 2 * are named as impossible, and anything with no run in the next twelve years is reported rather than shown as an empty list.
No, and this is the single most common cron mistake. crontab(5) says that when both day fields are restricted the job runs when either matches, so it runs on the 13th of every month and on every Friday. To get Friday the 13th you need a scheduler that supports it or a guard inside the job itself.
crontab(5) says a job that would have run in the skipped interval runs immediately, so it fires at the moment the clock jumps, which is 03:00. The run is marked here and the reason is given. Not every scheduler follows Vixie cron on this; a cloud scheduler running in UTC has no clock change at all, which is a good reason to run one there.
A job at a specific hour fires once, at the first of the two identical wall clocks. A job whose hour field is * follows real time and fires in both hours, which is what crontab(5) means by treating frequent jobs normally.
The time zone of the machine running it. That is UTC on GitHub Actions, GitLab CI and most cloud schedulers, and whatever the system is set to on a server. This page lets you pick, and defaults to your browser zone with a note that it is probably not the right one.
*/5 is every fifth value over the whole range, so in the minute field it fires at 0, 5, 10 and so on. 5/15 starts at 5 and steps by 15 to the end of the range, so 5, 20, 35 and 50. Both are accepted here.
It should not, but the reason a migrated one often does is that Quartz numbers the days of the week from 1 for Sunday while Unix cron numbers them from 0. Quartz 2 is Monday and Unix 2 is Tuesday. Switching dialect at the top handles it, and the reference table shows both numberings.
Yes. Vixie cron accepts both 0 and 7 for Sunday, and so does this. Quartz does not use 0 at all.
This runs as client-side JavaScript. Keys, tokens, payloads, and other inputs never leave your device.