Quick answer
The cron expression for twice a day is 0 0,12 * * *, which runs at midnight and noon. The comma makes a list, so the hour field matches exactly 0 and 12, while the 0 in the minute field runs the job on the hour. Change the list to any two hours you like: 0 9,21 * * * runs at 09:00 and 21:00.
- Live next runs
- Any time zone
- Field-by-field breakdown
- Seven platform snippets
- Daylight saving aware
How to use this schedule
- 1Copy
0 0,12 * * *with the Copy expression button. - 2Check Next runs in your time zone to confirm it fires when you expect, including around daylight saving changes.
- 3Pick your platform under Use it on your platform and copy the ready-made crontab line, workflow, manifest or timer.
- 4Need a different time or day? Click Customize to open it in the cron expression generator and change any field.
How do I pick the two times?
The comma in 0,12 builds a list: the hour field matches each listed value and nothing else. Swap in any two hours from 0 to 23. They don't have to be twelve hours apart:
| Expression | Runs at |
|---|---|
0 0,12 * * * | 00:00 and 12:00 |
0 9,21 * * * | 09:00 and 21:00 |
30 6,18 * * * | 06:30 and 18:30 |
0 8,17 * * 1-5 | 08:00 and 17:00, weekdays only |
There is one catch: an expression has a single minute field, and it applies to both hours. 30 9,17 * * * means 09:30 and 17:30. If the two runs need different minutes, say 09:00 and 17:30, write two lines with the same command:
0 9 * * * /path/to/job
30 17 * * * /path/to/jobTwice a day or every 12 hours?
For midnight and noon, 0 0,12 * * * and 0 */12 * * * are the same schedule. Choose the form that says what you mean. The list reads as "at these two times" and is easy to edit into uneven pairs; the step reads as "every twelve hours" and is the natural fit when equal spacing matters. The every 12 hours page covers the step form in depth.
Uneven pairs change what each run should do. With 08:00 and 17:00, the gaps are 9 hours and 15 hours, so a job that processes a fixed "last 12 hours" window will double-count during the day and miss data overnight. Track the timestamp of the last successful run and process everything since then.
Twice daily suits start-of-day and end-of-day work: a morning summary and an evening reconciliation, syncing a partner feed before and after business hours, or backing up a busy database at quiet times. If once is enough, see every day at midnight or every day at noon.
What does each field in 0 0,12 * * * mean?
| Field | Value | Allowed | Meaning |
|---|---|---|---|
| Minute | 0 | 0–59 | at minute 0 (on the hour) |
| Hour | 0,12 | 0–23 | at 00:00 and 12:00 (midnight and noon) |
| Day of month | * | 1–31 | every day of the month |
| Month | * | 1–12, JAN–DEC | every month |
| Day of week | * | 0–7 (0 and 7 are Sunday), SUN–SAT | every day of the week |
Read together: At midnight and noon (00:00 and 12:00) every day.
How do I adjust 0 0,12 * * * to my own schedule?
Small edits to 0 0,12 * * * cover most real-world needs:
| Expression | What it does |
|---|---|
0 9,21 * * * | Twice a day at 09:00 and 21:00 |
30 6,18 * * * | Twice a day at 06:30 and 18:30 |
0 8,17 * * 1-5 | At the start and end of the working day, Monday to Friday |
0 */12 * * * | Every 12 hours, the step version of midnight and noon |
0 0,8,16 * * * | Three times a day, every 8 hours |
Need something else? Click Customize at the top of the page to open this schedule in the cron expression generator and change any field.
Related schedules: Every 12 hours · Every day at midnight · Every day at noon · Every 6 hours
Browse all schedules in the cron schedule library.
How do I run 0 0,12 * * * in crontab, GitHub Actions, Kubernetes and the cloud?
| Platform | Write it as | Time zone |
|---|---|---|
| Linux crontab | 0 0,12 * * * | Server's time zone; CRON_TZ= in cronie |
| GitHub Actions | - cron: "0 0,12 * * *" | UTC by default; add timezone: (IANA name) |
| Kubernetes CronJob | schedule: "0 0,12 * * *" | Set timeZone: (1.27+) |
| Cloudflare Workers | 0 0,12 * * * | UTC only; numbers weekdays from 1 = Sunday, so use names |
| Vercel Cron Jobs | 0 0,12 * * * | UTC only; more than once a day needs Pro (Hobby: once a day) |
| AWS EventBridge Scheduler | cron(0 0,12 * * ? *) | Takes a time zone; legacy scheduled rules are UTC only |
| systemd timer | OnCalendar=*-*-* 00,12:00:00 | Add a zone after the time, e.g. Europe/London |
In a crontab (crontab -e), the full line looks like this:
0 0,12 * * * /path/to/job.sh >> /var/log/job.log 2>&1The live panel at the top of the page builds complete, copy-ready files for each platform (workflow, CronJob manifest, wrangler.toml, vercel.json, AWS CLI and systemd units) and can shift the schedule to UTC for platforms that need it.
What can go wrong with 0 0,12 * * *?
- The minute field is shared by both hours.
30 9,17 * * *runs at 09:30 and 17:30; for 09:00 and 17:30 you need two separate lines. - Writing
0,12 * * * *puts the list in the minute field: that runs at :00 and :12 of every hour, 48 times a day. - With uneven times such as 08:00 and 17:00 the gaps are 9 and 15 hours. A job that processes a fixed 12-hour window will double-count or miss data, so track the last successful run instead.
- Midnight and noon in UTC are 20:00 and 08:00 in New York during daylight time. Decide whose midnight you mean before choosing UTC or local time.
- On UTC-only platforms (Cloudflare Workers, Vercel, legacy EventBridge rules), the local time this runs at moves by an hour when daylight saving time starts or ends. Use GitHub's
timezone:, KubernetestimeZone, EventBridge Scheduler or cronie'sCRON_TZto pin it to local time.
Frequently asked questions
Last updated by the Playxoft engineering team.