-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcron-parser.html
More file actions
716 lines (652 loc) · 52.8 KB
/
Copy pathcron-parser.html
File metadata and controls
716 lines (652 loc) · 52.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Free Cron Parser — Next 10 Fire Times | FreeDevTool</title>
<meta name="description" content="Parse and explain cron expressions in plain English. Shows the next 10 fire times. Supports standard cron, quartz, and AWS formats. Free, browser-only.">
<meta name="robots" content="index, follow">
<meta name="author" content="Anees Ur Rehman">
<script type="application/ld+json">{"@context":"https://schema.org","@type":"WebPage","datePublished":"2026-05-02","dateModified":"2026-05-19","inLanguage":"en-US","isPartOf":{"@type":"WebSite","name":"FreeDevTool","url":"https://freedevtool.org"}}</script>
<script type="application/ld+json">{"@context":"https://schema.org","@type":"Person","name":"Anees Ur Rehman","url":"https://freedevtool.org/about","jobTitle":"Full-stack developer","worksFor":{"@type":"Organization","name":"FreeDevTool","url":"https://freedevtool.org"}}</script>
<link rel="canonical" href="https://freedevtool.org/cron-parser">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="preload" href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;700&family=DM+Sans:wght@300;400;500;600&display=swap" as="style">
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;700&family=DM+Sans:wght@300;400;500;600&display=swap">
<link rel="preload" href="style.css?v=20260502-cards" as="style">
<link rel="stylesheet" href="style.css?v=20260502-cards">
<link rel="icon" href="/favicon.svg" type="image/svg+xml">
<link rel="apple-touch-icon" href="/favicon.svg">
<meta property="og:image" content="https://freedevtool.org/og-image.svg">
<meta property="og:image:width" content="1200">
<meta property="og:image:height" content="630">
<meta property="og:image:alt" content="FreeDevTool — 50+ free, fast, privacy-first developer tools">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:image" content="https://freedevtool.org/og-image.svg">
<meta name="twitter:title" content="Cron Expression Generator & Parser — Free Crontab Tool">
<meta name="twitter:description" content="Parse, generate and validate cron expressions. Get human-readable descriptions, next 5 run times, and presets for crontab, Kubernetes, GitHub Actions.">
<script async src="https://www.googletagmanager.com/gtag/js?id=G-3L0CMH3X36"></script>
<script>window.dataLayer=window.dataLayer||[];function gtag(){dataLayer.push(arguments)}gtag('js',new Date());gtag('config','G-3L0CMH3X36');</script>
<meta property="og:title" content="Cron Expression Generator & Parser — Free Crontab Tool">
<meta property="og:description" content="Parse cron expressions to human-readable text. Generate cron schedules with next run times.">
<meta property="og:type" content="website">
<meta property="og:url" content="https://freedevtool.org/cron-parser">
<script type="application/ld+json">
{"@context":"https://schema.org","@type":"WebApplication","name":"Cron Expression Generator & Parser","url":"https://freedevtool.org/cron-parser","description":"Generate and parse cron expressions with human-readable descriptions and next run times.","applicationCategory":"DeveloperApplication","operatingSystem":"Any","offers":{"@type":"Offer","price":"0","priceCurrency":"USD"}}
</script>
<script type="application/ld+json">
{"@context":"https://schema.org","@type":"FAQPage","mainEntity":[
{"@type":"Question","name":"What is a cron expression and how does it work?","acceptedAnswer":{"@type":"Answer","text":"A cron expression is a string of five fields (minute, hour, day-of-month, month, day-of-week) that defines a recurring schedule. Each field can contain specific values, ranges, wildcards (*), or step values (*/5). For example, '0 9 * * 1-5' means 'at 9:00 AM, Monday through Friday'. Cron is used in Unix/Linux, Kubernetes CronJobs, CI/CD pipelines, and task schedulers."}},
{"@type":"Question","name":"How do I schedule a cron job to run every 5 minutes?","acceptedAnswer":{"@type":"Answer","text":"Use the expression: */5 * * * * — this means 'every 5th minute of every hour, every day'. The */5 in the minute field is a step value. Similarly, */10 runs every 10 minutes, */15 every 15 minutes, and 0 * * * * runs at the top of every hour."}},
{"@type":"Question","name":"What are the five fields in a cron expression?","acceptedAnswer":{"@type":"Answer","text":"The five standard cron fields are: (1) Minute (0-59), (2) Hour (0-23), (3) Day of month (1-31), (4) Month (1-12 or JAN-DEC), (5) Day of week (0-7 or SUN-SAT, where 0 and 7 are both Sunday). Some systems add a 6th field for seconds or year."}},
{"@type":"Question","name":"What is the difference between standard cron and Quartz cron?","acceptedAnswer":{"@type":"Answer","text":"Standard (Unix) cron has 5 fields: minute, hour, day-of-month, month, day-of-week. Quartz cron (used in Java's Quartz Scheduler) has 6-7 fields adding seconds and optionally year. Quartz also supports 'L' (last), 'W' (weekday), '#' (nth weekday), and '?' (no specific value) — features not available in standard cron."}},
{"@type":"Question","name":"Can I use cron expressions on Windows?","acceptedAnswer":{"@type":"Answer","text":"Windows doesn't natively support cron syntax, but alternatives exist: Windows Task Scheduler has its own GUI and XML format. WSL (Windows Subsystem for Linux) supports standard cron. Many tools like Jenkins, GitHub Actions, and Kubernetes use cron expressions cross-platform regardless of the host OS."}},{"@type":"Question","name":"What does * * * * * mean in cron?","acceptedAnswer":{"@type":"Answer","text":"Five asterisks mean every minute of every hour of every day of every month, regardless of day of week — fire every minute. The five fields left to right: minute (0-59), hour (0-23), day of month (1-31), month (1-12), day of week (0-7 where 0 and 7 both mean Sunday)."}},{"@type":"Question","name":"Why does my cron job not fire?","acceptedAnswer":{"@type":"Answer","text":"Common reasons: (1) the expression is technically valid but does not match what you intended; (2) the cron service is not running; (3) timezone mismatch — GitHub Actions, Kubernetes, and AWS use UTC by default; (4) the previous run is still executing and your scheduler is configured not to overlap."}},{"@type":"Question","name":"What is the difference between standard cron and quartz cron?","acceptedAnswer":{"@type":"Answer","text":"Standard POSIX cron uses 5 fields. Quartz cron (used by Java schedulers like Spring) adds a 6th field for seconds and a 7th optional field for year, and uses ? as a placeholder where standard cron uses *. Common porting error: copying a Quartz expression into a Linux crontab fails."}}
]}
</script>
<style>
.cron-fields { display:flex; gap:6px; align-items:flex-end; flex-wrap:wrap; margin-bottom:12px; }
.cron-field { display:flex; flex-direction:column; gap:3px; text-align:center; }
.cron-field label { font-size:9px; text-transform:uppercase; letter-spacing:.3px; color:var(--text3); margin:0; }
.cron-field input[type="text"] {
width:60px; text-align:center; font-family:var(--mono); font-size:16px; font-weight:600;
padding:10px 4px; background:var(--bg3); border:1px solid var(--border); color:var(--text);
}
.cron-field input:focus { border-color:var(--accent2); }
.cron-full {
font-family:var(--mono); font-size:18px; font-weight:600; color:var(--accent);
background:var(--bg3); border:1px solid var(--border); border-radius:var(--radius);
padding:14px; text-align:center; letter-spacing:2px; margin-bottom:14px;
}
.cron-desc {
font-size:15px; color:var(--text); text-align:center; margin-bottom:8px;
padding:12px; background:var(--accent-dim); border:1px solid rgba(0,208,132,.2);
border-radius:var(--radius);
}
.next-runs { margin-top:14px; }
.next-run {
display:flex; align-items:center; gap:8px;
padding:8px 0; border-bottom:1px solid var(--border);
font-family:var(--mono); font-size:12px;
}
.next-run:last-child { border-bottom:none; }
.next-run-idx { color:var(--accent); font-weight:600; width:20px; }
.next-run-date { color:var(--text); }
.next-run-rel { color:var(--text3); font-size:11px; }
.preset-row { display:flex; gap:6px; flex-wrap:wrap; margin-bottom:14px; }
.preset-btn {
font-size:11px; padding:4px 10px; border-radius:var(--radius);
border:1px solid var(--border); background:var(--bg3); color:var(--text2);
cursor:pointer; font-family:var(--mono); transition:all .2s;
}
.preset-btn:hover { border-color:var(--accent2); color:var(--accent); background:var(--accent-dim); }
</style>
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "BreadcrumbList",
"itemListElement": [
{
"@type": "ListItem",
"position": 1,
"name": "Home",
"item": "https://freedevtool.org/"
},
{
"@type": "ListItem",
"position": 2,
"name": "All Tools",
"item": "https://freedevtool.org/all-tools"
},
{
"@type": "ListItem",
"position": 3,
"name": "Cron Expression Generator & Parser",
"item": "https://freedevtool.org/cron-parser"
}
]
}
</script>
<script src="/ga4-events.js" defer></script>
</head>
<body>
<nav>
<a class="nav-logo" href="/" aria-label="FreeDevTool home"><svg class="logo-mark" width="22" height="22" viewBox="0 0 24 24" aria-hidden="true" fill="none"><rect x="1" y="1" width="22" height="22" rx="6" fill="currentColor" opacity=".12"/><path d="M9.5 8.5L6 12l3.5 3.5M14.5 8.5L18 12l-3.5 3.5" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>FreeDevTool</a>
<div class="nav-links">
<div class="nav-dropdown" id="tools-dropdown">
<a href="all-tools" onclick="event.preventDefault();this.parentElement.classList.toggle('open')" aria-haspopup="true">Tools <svg class="chev" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 9 12 15 18 9"/></svg></a>
<div class="nav-dropdown-menu">
<a href="encoding-tools">
<div class="dd-icon">b64</div>
<div class="dd-info"><div class="dd-name">Encoding & Conversion</div><div class="dd-count">11 tools · Base64, YAML, px→rem</div></div>
</a>
<a href="generation-tools">
<div class="dd-icon">{ }</div>
<div class="dd-info"><div class="dd-name">Generation & Formatting</div><div class="dd-count">16 tools · JSON, SQL, gradients</div></div>
</a>
<a href="security-tools">
<div class="dd-icon">#</div>
<div class="dd-info"><div class="dd-name">Security & Hashing</div><div class="dd-count">3 tools · JWT, MD5, SHA</div></div>
</a>
<a href="text-tools">
<div class="dd-icon">.*</div>
<div class="dd-info"><div class="dd-name">Code & Text Tools</div><div class="dd-count">9 tools · Regex, diff, tokens</div></div>
</a>
<a href="devops-tools">
<div class="dd-icon">JS</div>
<div class="dd-info"><div class="dd-name">Optimization & DevOps</div><div class="dd-count">7 tools · Minifiers, cURL, git</div></div>
</a>
<a href="network-tools">
<div class="dd-icon">IP</div>
<div class="dd-info"><div class="dd-name">Network & Time</div><div class="dd-count">4 tools · IP, DNS, timestamps</div></div>
</a>
<a href="seo-tools">
<div class="dd-icon">SEO</div>
<div class="dd-info"><div class="dd-name">SEO & Meta Tools</div><div class="dd-count">3 tools · OG, meta, slug</div></div>
</a>
<div class="nav-dropdown-divider"></div>
<a class="dd-all" href="all-tools">
<div class="dd-icon">All</div>
<div class="dd-info"><div class="dd-name">Browse all 50 tools</div><div class="dd-count">Searchable catalog & categories</div></div>
</a>
</div>
</div>
<a href="/guides">Guides</a>
<a href="about">About</a>
<a href="privacy">Privacy</a>
</div>
</nav>
<div id="copy-toast">Copied!</div>
<div class="wrapper">
<a class="tool-back" href="/" aria-label="Back to home">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M15 18l-6-6 6-6"/></svg>
Back
</a>
<div class="tool-header">
<div class="tool-badge">DevOps Tool</div>
<h1>Cron Expression Generator & Parser</h1>
<p class="tool-description">
Parse, generate, and validate cron expressions with instant human-readable descriptions and next scheduled run times. This free online crontab tool supports standard 5-field Unix cron syntax used in Linux crontab, Kubernetes CronJobs, GitHub Actions, Jenkins, and CI/CD pipelines. Enter a cron expression or use presets to build your schedule. A powerful alternative to crontab.guru — all processing runs in your browser.
</p>
<div class="last-updated">Last updated: May 2026 · Written by <a href="/about">Anees Ur Rehman</a>, full-stack developer</div>
</div>
<div class="tool-card">
<div class="tool-card-header">
<div class="dot dot-red"></div><div class="dot dot-yellow"></div><div class="dot dot-green"></div>
<span class="tool-card-title">cron-parser.tool</span>
</div>
<div class="tool-body">
<label>Quick Presets</label>
<div class="preset-row">
<button class="preset-btn" onclick="setCron('* * * * *')">Every minute</button>
<button class="preset-btn" onclick="setCron('*/5 * * * *')">Every 5 min</button>
<button class="preset-btn" onclick="setCron('*/15 * * * *')">Every 15 min</button>
<button class="preset-btn" onclick="setCron('0 * * * *')">Every hour</button>
<button class="preset-btn" onclick="setCron('0 0 * * *')">Daily midnight</button>
<button class="preset-btn" onclick="setCron('0 9 * * 1-5')">Weekdays 9 AM</button>
<button class="preset-btn" onclick="setCron('0 0 * * 0')">Weekly Sunday</button>
<button class="preset-btn" onclick="setCron('0 0 1 * *')">Monthly 1st</button>
</div>
<label>Cron Expression (5 Fields)</label>
<div class="cron-full" id="cron-display" contenteditable="false">*/5 * * * *</div>
<div class="cron-fields">
<div class="cron-field"><label>Minute</label><input type="text" id="f-min" value="*/5" oninput="parseCron()" spellcheck="false"></div>
<div class="cron-field"><label>Hour</label><input type="text" id="f-hour" value="*" oninput="parseCron()" spellcheck="false"></div>
<div class="cron-field"><label>Day (Month)</label><input type="text" id="f-dom" value="*" oninput="parseCron()" spellcheck="false"></div>
<div class="cron-field"><label>Month</label><input type="text" id="f-month" value="*" oninput="parseCron()" spellcheck="false"></div>
<div class="cron-field"><label>Day (Week)</label><input type="text" id="f-dow" value="*" oninput="parseCron()" spellcheck="false"></div>
<button class="btn btn-ghost" style="margin-left:8px" onclick="copyCron()">Copy</button>
</div>
<div id="cron-error" style="display:none"></div>
<div class="cron-desc" id="cron-desc">Every 5 minutes</div>
<div class="next-runs">
<label>Next 5 Scheduled Runs</label>
<div id="next-runs"></div>
</div>
</div>
</div>
<p class="aeo-lead" style="font-size:16px;line-height:1.7;color:var(--text);max-width:760px;margin:24px auto 18px;padding:0 4px">
<strong>A cron expression</strong> is a 5-field schedule string used by Linux cron, Kubernetes CronJob, GitHub Actions, AWS EventBridge, and most CI/CD platforms to specify when a recurring job runs. The fields are <code>minute hour day-of-month month day-of-week</code>, separated by spaces. Each field accepts a number, range, list, or asterisk for "every". This <strong>free cron expression parser</strong> explains any expression in plain English and shows the next 10 fire times.
</p>
<section id="examples" style="max-width:760px;margin:24px auto 32px">
<h2 style="font-size:18px;margin-bottom:14px">Examples</h2>
<div style="background:var(--bg3);border:1px solid var(--border);border-radius:var(--radius);padding:16px;margin-bottom:12px"><strong style="display:block;color:var(--accent);font-family:var(--mono);font-size:11px;text-transform:uppercase;letter-spacing:1px;margin-bottom:6px">Daily at midnight</strong><code style="display:block;font-family:var(--mono);font-size:13px">0 0 * * *</code><p style="margin:6px 0 0;font-size:13px">Fires at 00:00 every day.</p></div>
<div style="background:var(--bg3);border:1px solid var(--border);border-radius:var(--radius);padding:16px;margin-bottom:12px"><strong style="display:block;color:var(--accent);font-family:var(--mono);font-size:11px;text-transform:uppercase;letter-spacing:1px;margin-bottom:6px">Every 15 minutes</strong><code style="display:block;font-family:var(--mono);font-size:13px">*/15 * * * *</code><p style="margin:6px 0 0;font-size:13px">Step values must divide 60 evenly (2, 3, 4, 5, 6, 10, 12, 15, 20, 30).</p></div>
<div style="background:var(--bg3);border:1px solid var(--border);border-radius:var(--radius);padding:16px"><strong style="display:block;color:var(--accent);font-family:var(--mono);font-size:11px;text-transform:uppercase;letter-spacing:1px;margin-bottom:6px">Weekdays at 9 AM</strong><code style="display:block;font-family:var(--mono);font-size:13px">0 9 * * MON-FRI</code><p style="margin:6px 0 0;font-size:13px">Day-of-week 0 and 7 both mean Sunday — a common gotcha.</p></div>
</section>
<aside class="founder-note" style="max-width:760px;margin:24px auto 32px;padding:20px 24px;background:rgba(0,208,132,0.05);border-left:3px solid var(--accent);border-radius:6px;font-size:14px;line-height:1.7;color:var(--text2)"><div style="font-family:var(--mono);font-size:11px;color:var(--accent);letter-spacing:1.5px;text-transform:uppercase;margin-bottom:10px;font-weight:600">💡 Why I built this</div><p style="margin:0 0 12px">I built this because crontab.guru is dominant for a reason — it is good. But it is closed source, English-only, and runs from a server. This parser is open source, runs entirely in your browser, and produces the same explanations plus the next 10 fire times. Useful for verifying GitHub Actions cron schedules, Kubernetes CronJob expressions, and legacy Linux crontab entries — without phoning a server every time you check.</p><p style="margin:0;font-size:13px;color:var(--text3)">— <a href="/about" style="color:var(--accent);text-decoration:none">Anees Ur Rehman</a>, full-stack developer</p></aside>
<section class="article-section">
<h2>The complete guide to cron expressions, scheduling syntax, and real-world gotchas</h2>
<p>Cron is the oldest scheduler still in production. The first version shipped with Unix V7 in 1979, written by Brian Kernighan. Forty-seven years later, the same five-field syntax drives Kubernetes CronJobs, GitHub Actions, AWS EventBridge, Jenkins, Airflow, GitLab pipelines, Vercel cron, and every cloud function platform in production. Knowing how to read and write cron correctly is a baseline DevOps skill — and it is also the most common source of "why didn't my job run?" tickets. This guide walks through the syntax, the dialect differences (POSIX vs Quartz vs AWS vs Kubernetes), the timezone rules that bite teams, and the patterns I rely on after a decade of running cron-driven systems.</p>
<h3>The five fields, decoded</h3>
<p>A standard cron expression is five space-separated fields. Read left to right:</p>
<table class="ref-table">
<thead><tr><th>Position</th><th>Field</th><th>Allowed values</th><th>Allowed characters</th></tr></thead>
<tbody>
<tr><td>1</td><td>Minute</td><td>0–59</td><td><code>* / , -</code></td></tr>
<tr><td>2</td><td>Hour</td><td>0–23 (24-hour)</td><td><code>* / , -</code></td></tr>
<tr><td>3</td><td>Day of month</td><td>1–31</td><td><code>* / , - L W ?</code> (Quartz only for L W)</td></tr>
<tr><td>4</td><td>Month</td><td>1–12 or JAN–DEC</td><td><code>* / , -</code></td></tr>
<tr><td>5</td><td>Day of week</td><td>0–7 or SUN–SAT (0 and 7 = Sunday)</td><td><code>* / , - # L ?</code> (Quartz only for # L)</td></tr>
</tbody>
</table>
<p>The wildcards and operators each have a precise meaning:</p>
<table class="ref-table">
<thead><tr><th>Operator</th><th>Meaning</th><th>Example</th></tr></thead>
<tbody>
<tr><td><code>*</code></td><td>Every value in the field's range</td><td><code>* * * * *</code> = every minute</td></tr>
<tr><td><code>,</code></td><td>List of specific values</td><td><code>0,15,30,45 * * * *</code> = at :00, :15, :30, :45</td></tr>
<tr><td><code>-</code></td><td>Range (inclusive)</td><td><code>0 9-17 * * 1-5</code> = on the hour 9am–5pm Mon–Fri</td></tr>
<tr><td><code>/</code></td><td>Step value</td><td><code>*/15 * * * *</code> = every 15 minutes (on :00, :15, :30, :45)</td></tr>
<tr><td><code>L</code></td><td>Last (Quartz)</td><td><code>0 0 L * *</code> = midnight on the last day of the month</td></tr>
<tr><td><code>W</code></td><td>Nearest weekday (Quartz)</td><td><code>0 0 15W * *</code> = nearest weekday to the 15th</td></tr>
<tr><td><code>#</code></td><td>Nth weekday of the month (Quartz)</td><td><code>0 9 * * 2#3</code> = 9am on the 3rd Tuesday</td></tr>
</tbody>
</table>
<h3>Cron dialects — they are not all the same</h3>
<p>Half the bugs I have seen with cron come from running an expression that was valid in one system but not the one actually executing it. Here is the truth table:</p>
<table class="ref-table">
<thead><tr><th>System</th><th>Fields</th><th>Seconds?</th><th>Year?</th><th>L / W / #</th><th>Notes</th></tr></thead>
<tbody>
<tr><td>POSIX cron / vixie-cron (Linux)</td><td>5</td><td>No</td><td>No</td><td>No</td><td>The reference implementation. Day-of-month + day-of-week use OR semantics when both are restricted.</td></tr>
<tr><td>Kubernetes CronJob</td><td>5</td><td>No</td><td>No</td><td>No</td><td>Schedules in UTC by default; configure <code>spec.timeZone</code> in v1.27+.</td></tr>
<tr><td>GitHub Actions</td><td>5</td><td>No</td><td>No</td><td>No</td><td>UTC only. Minimum interval is 5 minutes; runs are best-effort and can be delayed during high load.</td></tr>
<tr><td>AWS EventBridge / CloudWatch</td><td>6</td><td>No</td><td>Yes</td><td>L W</td><td>Day-of-month and day-of-week cannot both be specific — one must be <code>?</code>.</td></tr>
<tr><td>Quartz (Java)</td><td>6 or 7</td><td>Yes (field 1)</td><td>Optional (field 7)</td><td>Yes</td><td>Powers Spring Scheduled, ElasticJob.</td></tr>
<tr><td>node-cron (npm)</td><td>5 or 6</td><td>Optional (field 0)</td><td>No</td><td>No</td><td>Most popular Node scheduler.</td></tr>
<tr><td>Vercel Cron Jobs</td><td>5</td><td>No</td><td>No</td><td>No</td><td>UTC. Hobby tier limited to daily.</td></tr>
</tbody>
</table>
<h3>The OR-vs-AND day rule that surprises everyone</h3>
<p>Standard POSIX cron has a non-obvious rule: when <strong>both</strong> day-of-month and day-of-week are specific (not <code>*</code>), the job fires on days matching <strong>either</strong> field — the operators are OR'd. When only one of them is specific, normal AND semantics apply. The classic gotcha:</p>
<ul>
<li><code>0 0 1 * 1</code> — fires <strong>on the 1st of every month, AND every Monday</strong>, not just on Mondays that fall on the 1st.</li>
<li><code>0 0 1 * *</code> — fires only on the 1st (DOW is wildcard, AND with everything).</li>
<li><code>0 0 * * 1</code> — fires only on Mondays (DOM is wildcard).</li>
</ul>
<p>If you want "first Monday of every month" you cannot express it in standard cron — you need Quartz's <code>2#1</code> syntax, or you have to add a wrapper script that exits unless <code>date +%d</code> is between 1 and 7. AWS EventBridge punts on the issue entirely by requiring <code>?</code> in one of the two day fields. The parser above implements POSIX semantics correctly.</p>
<h3>Timezones — the source of every cron incident</h3>
<p>Cron's biggest operational footgun is timezone handling. The rules vary by system:</p>
<ul>
<li><strong>Linux crontab:</strong> uses the system timezone. Daylight-saving transitions can skip jobs (the 2:30 AM run on the spring-forward day never happens) or fire them twice (in the fall).</li>
<li><strong>Kubernetes CronJob:</strong> defaults to UTC. Set <code>spec.timeZone: "America/New_York"</code> to use a named TZ (Kubernetes 1.27+).</li>
<li><strong>GitHub Actions:</strong> always UTC, no override. If you want 9am Eastern, you have to convert: 9am EST = 14:00 UTC, 9am EDT = 13:00 UTC. Most teams just accept that the job drifts an hour at DST boundaries.</li>
<li><strong>AWS EventBridge:</strong> always UTC.</li>
<li><strong>Quartz:</strong> per-trigger TZ via <code>scheduler.scheduleJob(jobDetail, trigger.withTimeZone(...))</code>.</li>
</ul>
<p>The defensive habit: <strong>always think about your cron in UTC unless your platform explicitly supports another zone</strong>, and document the intended local time in a comment next to the expression.</p>
<h3>Cron in 8 platforms — real-world syntax</h3>
<p>Here is the same intent — "every weekday at 9 AM" — expressed across the platforms you are most likely to ship to:</p>
<div class="lang-block"><strong>Linux crontab (/etc/crontab):</strong><pre><code>0 9 * * 1-5 /usr/local/bin/morning-job.sh</code></pre></div>
<div class="lang-block"><strong>Kubernetes CronJob:</strong><pre><code>apiVersion: batch/v1
kind: CronJob
metadata:
name: morning-job
spec:
schedule: "0 9 * * 1-5"
timeZone: "America/New_York" # k8s 1.27+
jobTemplate:
spec:
template:
spec:
containers:
- name: job
image: ghcr.io/acme/morning:latest
restartPolicy: OnFailure</code></pre></div>
<div class="lang-block"><strong>GitHub Actions (UTC only):</strong><pre><code>on:
schedule:
- cron: "0 14 * * 1-5" # 14:00 UTC = 9 AM EST (10 AM EDT)</code></pre></div>
<div class="lang-block"><strong>AWS EventBridge (6 fields, ? in DOW):</strong><pre><code>cron(0 13 ? * MON-FRI *)</code></pre></div>
<div class="lang-block"><strong>Node.js (node-cron):</strong><pre><code>const cron = require('node-cron');
cron.schedule('0 9 * * 1-5', () => runMorningJob(), {
timezone: 'America/New_York'
});</code></pre></div>
<div class="lang-block"><strong>Python (APScheduler):</strong><pre><code>from apscheduler.schedulers.blocking import BlockingScheduler
from apscheduler.triggers.cron import CronTrigger
sched = BlockingScheduler(timezone='America/New_York')
sched.add_job(morning_job, CronTrigger.from_crontab('0 9 * * 1-5'))
sched.start()</code></pre></div>
<div class="lang-block"><strong>Spring Boot (Quartz, 6 fields with seconds):</strong><pre><code>@Scheduled(cron = "0 0 9 ? * MON-FRI", zone = "America/New_York")
public void morningJob() { /* ... */ }</code></pre></div>
<div class="lang-block"><strong>Go (robfig/cron v3):</strong><pre><code>c := cron.New(cron.WithLocation(time.FixedZone("EST", -5*3600)))
c.AddFunc("0 9 * * 1-5", morningJob)
c.Start()</code></pre></div>
<h3>Common cron mistakes to avoid</h3>
<ul>
<li><strong>Confusing <code>*/0</code> or <code>*/1</code> with "every minute".</strong> <code>*/0</code> is invalid; <code>*/1</code> equals <code>*</code>. Use plain <code>*</code> when you mean every value.</li>
<li><strong>Writing <code>0-59/5</code> when you meant <code>*/5</code>.</strong> They are equivalent in the minute field, but the step form is shorter and clearer.</li>
<li><strong>Setting hour to <code>9</code> in UTC when you wanted 9am local.</strong> Always verify the platform's TZ before deploying.</li>
<li><strong>Forgetting that DOM + DOW are OR'd in POSIX.</strong> If you want "1st of the month, but only if it's a weekday," cron alone cannot do it.</li>
<li><strong>Running long jobs at <code>* * * * *</code> without overlap protection.</strong> If a job takes 90 seconds and runs every minute, you get overlapping instances. Use <code>flock</code> or a job queue to serialize.</li>
<li><strong>Treating cron triggers as exactly-once delivery.</strong> Most cloud cron systems are at-least-once. Make jobs idempotent.</li>
<li><strong>Scheduling everything for <code>0 0 * * *</code>.</strong> If 200 jobs all run at midnight UTC, your worker pool spikes. Stagger across the hour.</li>
<li><strong>Not setting up alerts for missed runs.</strong> Use Healthchecks.io, Cronitor, or your platform's built-in failure notifications. Silent failure is the default.</li>
</ul>
<h3>Best practices for production cron</h3>
<ol>
<li><strong>Make every job idempotent.</strong> Re-running it twice produces the same result.</li>
<li><strong>Add overlap protection.</strong> Use distributed locks (Redis SETNX, etcd, ZooKeeper) or a job queue with single-runner semantics.</li>
<li><strong>Set a job-level timeout.</strong> Cron has none. Wrap with <code>timeout 5m</code> or your platform's equivalent.</li>
<li><strong>Use a dead-man's switch.</strong> Cronitor or Healthchecks.io tells you when a job did <em>not</em> run, which is the failure mode cron itself cannot detect.</li>
<li><strong>Pin the timezone explicitly.</strong> Even if it matches the default, a comment makes future-you grateful.</li>
<li><strong>Use named months and days for readability.</strong> <code>0 9 * JAN-MAR MON-FRI</code> reads better than <code>0 9 * 1-3 1-5</code>.</li>
<li><strong>Stagger non-critical jobs.</strong> <code>17 * * * *</code> instead of <code>0 * * * *</code> spreads load.</li>
</ol>
<aside class="article-aside">
<strong>Authoritative references:</strong>
<ul>
<li><a href="https://pubs.opengroup.org/onlinepubs/9699919799/utilities/crontab.html" rel="noopener" target="_blank">POSIX crontab specification (Open Group)</a></li>
<li><a href="https://kubernetes.io/docs/concepts/workloads/controllers/cron-jobs/" rel="noopener" target="_blank">Kubernetes — CronJob documentation</a></li>
<li><a href="https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#schedule" rel="noopener" target="_blank">GitHub Actions — schedule event syntax</a></li>
<li><a href="https://www.quartz-scheduler.org/documentation/quartz-2.3.0/tutorials/crontrigger.html" rel="noopener" target="_blank">Quartz Scheduler — CronTrigger reference</a></li>
<li><a href="https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-cron-expressions.html" rel="noopener" target="_blank">AWS EventBridge — cron expression rules</a></li>
</ul>
</aside>
</section>
<section class="article-section">
<h2>Cron expression evaluator, validator, tester — what each query actually wants</h2>
<p>Search variants for the same intent show up as: "cron expression evaluator", "cron expression validator", "cron tester", "cron evaluator", "cron formatter", "crontab online", "cron online", "cron syntax generator", "cron converter". They all ask the same three questions about a cron string: <em>(1) is it syntactically valid?</em> <em>(2) what does it mean in plain English?</em> <em>(3) when does it next fire?</em> The tool above answers all three on every keystroke.</p>
<h3>Cron expression validator — how to tell a valid expression from a typo</h3>
<p>A cron string passes validation when each of the five fields contains values inside its allowed range: minute <code>0-59</code>, hour <code>0-23</code>, day-of-month <code>1-31</code>, month <code>1-12</code> or <code>JAN-DEC</code>, day-of-week <code>0-7</code> or <code>SUN-SAT</code> (both <code>0</code> and <code>7</code> mean Sunday on most cron implementations). The most-common typos: writing <code>*/5</code> in the day-of-month field (legal syntactically but semantically wrong — it means "every 5 days starting day 1"); using <code>?</code> in standard cron (only valid in Quartz/AWS); and writing <code>0 0 31 2 *</code> (Feb 31 — never fires). The validator above flags all three with explicit error text instead of silently accepting unreachable schedules.</p>
<h3>Cron tester / cron evaluator — see the next 10 fire times before deploying</h3>
<p>Validating syntax is half the work. The other half is confirming the expression <em>actually fires when you expect</em>. Paste any expression above and the next 10 fire timestamps render below in your local timezone — useful for catching bugs like "0 9 * * 1" (Mondays 9 AM) when you meant "0 9 * * 1-5" (weekdays). For schedule expressions targeting servers in a different timezone, set the timezone selector before reading the next-run list. The evaluator runs <code>cron-parser</code> semantics matching Vixie cron and most standard implementations.</p>
<h3>Cron converter — translating between Vixie cron, Quartz, and AWS EventBridge</h3>
<p>"Cron converter" usually means one of three translations: <strong>Vixie cron → Quartz</strong> (Quartz adds a seconds field at the start: <code>0 0 9 * * ?</code> instead of <code>0 9 * * *</code>); <strong>Quartz → AWS EventBridge</strong> (EventBridge uses 6 fields with a year, plus uses <code>?</code> instead of <code>*</code> in either day-of-month or day-of-week); <strong>Vixie → Kubernetes CronJob</strong> (identical syntax, but with a 1-minute resolution and timezone via the <code>timeZone</code> field as of Kubernetes 1.27+). The parser above accepts all three formats with auto-detection — paste a 6-field Quartz expression and it adapts; paste a standard 5-field expression and it stays in Vixie mode.</p>
<h3>Crontab online — running cron locally vs in the cloud</h3>
<p>The traditional <code>crontab -e</code> CLI edits <code>/var/spool/cron/<user></code> on Unix systems and the cron daemon picks it up on save. The expression above runs the same parsing logic that <code>cron</code>, <code>vixie-cron</code>, <code>cronie</code>, and modern systemd timers use, so anything that validates here works on a Linux server. For cloud schedulers — AWS EventBridge, Google Cloud Scheduler, Azure Functions Timer Trigger — note their year and seconds field extensions; the differences page in the FAQ below covers each provider's exact format.</p>
<h3>C# cron expression parser, Quartz cron, NCrontab — language-specific notes</h3>
<p>For C# / .NET the standard library is <a href="https://www.nuget.org/packages/NCrontab/" rel="noopener" target="_blank">NCrontab</a> (5-field Vixie semantics) or <a href="https://www.quartz-scheduler.net/" rel="noopener" target="_blank">Quartz.NET</a> (6-field with seconds). For Node.js: <code>cron-parser</code> (the same parser this page uses), <code>node-cron</code>, or <code>node-schedule</code>. For Python: <code>croniter</code> (next-fire calculation), <code>APScheduler</code> (full scheduler). For Go: <code>github.com/robfig/cron/v3</code>. For Java: Quartz Scheduler. The expression above mirrors NCrontab/croniter/cron-parser semantics — patterns valid here behave identically in all three.</p>
<h3>Cron syntax generator — building expressions from natural language</h3>
<p>Going the other direction — describing a schedule in English and getting cron back — is what most "cron syntax generator" searches actually want. Common conversions: "every weekday at 9 AM" → <code>0 9 * * 1-5</code>; "every 15 minutes during business hours" → <code>*/15 9-17 * * 1-5</code>; "first day of every month at midnight" → <code>0 0 1 * *</code>; "every Monday and Wednesday at 8:30 PM" → <code>30 20 * * 1,3</code>; "every 6 hours" → <code>0 */6 * * *</code>. Keep these as a starting point; tweak in the parser above and watch the next-run list update.</p>
</section>
<section class="faq-section">
<h2>Frequently Asked Questions</h2>
<div class="faq-item open">
<div class="faq-q" onclick="toggleFaq(this)">What is a cron expression and how does it work?<svg class="chevron" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="6 9 12 15 18 9"/></svg></div>
<div class="faq-a">A cron expression is a string of <strong>five space-separated fields</strong> that defines a recurring schedule: <code>minute hour day-of-month month day-of-week</code>. Each field accepts specific values, ranges (<code>1-5</code>), wildcards (<code>*</code>), or step values (<code>*/5</code>). For example, <code>0 9 * * 1-5</code> means "at 9:00 AM, Monday through Friday." Cron originated in Unix but is now used in Kubernetes CronJobs, GitHub Actions, Jenkins, AWS CloudWatch, and many CI/CD systems.</div>
</div>
<div class="faq-item">
<div class="faq-q" onclick="toggleFaq(this)">How do I schedule a cron job to run every 5 minutes?<svg class="chevron" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="6 9 12 15 18 9"/></svg></div>
<div class="faq-a">Use: <code>*/5 * * * *</code>. The <code>*/5</code> in the minute field is a step value meaning "every 5th minute." Similarly: <code>*/10 * * * *</code> for every 10 minutes, <code>*/15 * * * *</code> for every 15 minutes, <code>0 * * * *</code> for the top of every hour, and <code>0 */2 * * *</code> for every 2 hours at minute 0.</div>
</div>
<div class="faq-item">
<div class="faq-q" onclick="toggleFaq(this)">What are the five fields in a cron expression?<svg class="chevron" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="6 9 12 15 18 9"/></svg></div>
<div class="faq-a"><strong>1. Minute</strong> (0–59) — <strong>2. Hour</strong> (0–23) — <strong>3. Day of month</strong> (1–31) — <strong>4. Month</strong> (1–12 or JAN–DEC) — <strong>5. Day of week</strong> (0–7 or SUN–SAT, where both 0 and 7 = Sunday). Some extended cron systems (Quartz, AWS) add a 6th field for seconds and a 7th for year, but standard Unix cron uses exactly five fields.</div>
</div>
<div class="faq-item">
<div class="faq-q" onclick="toggleFaq(this)">What is the difference between standard cron and Quartz cron?<svg class="chevron" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="6 9 12 15 18 9"/></svg></div>
<div class="faq-a"><strong>Standard (Unix) cron</strong> has 5 fields: minute, hour, day-of-month, month, day-of-week. <strong>Quartz cron</strong> (Java's Quartz Scheduler) has 6–7 fields adding seconds and optionally year. Quartz also supports special characters: <code>L</code> (last day), <code>W</code> (nearest weekday), <code>#</code> (nth weekday of month), and <code>?</code> (no specific value). This tool parses standard 5-field Unix cron expressions.</div>
</div>
<div class="faq-item">
<div class="faq-q" onclick="toggleFaq(this)">Can I use cron expressions on Windows?<svg class="chevron" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="6 9 12 15 18 9"/></svg></div>
<div class="faq-a">Windows doesn't natively support cron syntax — it uses <strong>Task Scheduler</strong> with its own GUI/XML format. However: <strong>WSL</strong> (Windows Subsystem for Linux) supports standard cron, and many cross-platform tools like <strong>Jenkins</strong>, <strong>GitHub Actions</strong>, <strong>Kubernetes</strong>, and <strong>Docker</strong> use cron expressions regardless of the host OS. You can also use Node.js libraries like <code>node-cron</code> on Windows.</div>
</div>
</section>
<section class="related-section">
<h2>Related Tools</h2>
<div class="related-grid">
<a class="related-card" href="unix-timestamp-converter"><div class="related-icon">⏱</div><div class="related-card-info"><div class="related-card-name">UNIX Timestamp Converter</div><div class="related-card-desc">Convert epoch time to dates</div></div></a>
<a class="related-card" href="regex-tester"><div class="related-icon">.*</div><div class="related-card-info"><div class="related-card-name">Regex Tester</div><div class="related-card-desc">Test regular expressions live</div></div></a>
<a class="related-card" href="json-formatter"><div class="related-icon">{ }</div><div class="related-card-info"><div class="related-card-name">JSON Formatter</div><div class="related-card-desc">Pretty print and validate JSON</div></div></a>
</div>
</section>
<section class="all-tools-section" aria-label="Browse all FreeDevTool developer tools">
<h2>Browse all 50 free developer tools</h2>
<p class="atc-sub">All tools run in your browser, no signup required, nothing sent to a server.</p>
<div class="all-tools-grid">
<div class="atc-cat">
<div class="atc-cat-head">
<div class="atc-cat-icon">b64</div>
<div class="atc-cat-title"><h3>Encoding & Conversion</h3><span class="atc-cat-count">11 tools</span></div>
</div>
<ul class="atc-list">
<li><a href="/base64-encoder">Base64 Encoder / Decoder</a></li>
<li><a href="/base64-image">Image to Base64</a></li>
<li><a href="/byte-converter">Byte Converter (KB / MB / GB)</a></li>
<li><a href="/case-converter">Case Converter</a></li>
<li><a href="/hex-to-rgb">Hex to RGB / HSL</a></li>
<li><a href="/html-entity">HTML Entity Encoder</a></li>
<li><a href="/json-to-csv">JSON to CSV Converter</a></li>
<li><a href="/px-to-rem">PX to REM Converter</a></li>
<li><a href="/string-escape">String Escape / Unescape</a></li>
<li><a href="/url-encoder">URL Encoder / Decoder</a></li>
<li><a href="/yaml-to-json">YAML to JSON Converter</a></li>
</ul>
</div>
<div class="atc-cat">
<div class="atc-cat-head">
<div class="atc-cat-icon">{ }</div>
<div class="atc-cat-title"><h3>Formatting & Generators</h3><span class="atc-cat-count">13 tools</span></div>
</div>
<ul class="atc-list">
<li><a href="/color-name">Color Name from Hex</a></li>
<li><a href="/color-picker">Color Palette Picker</a></li>
<li><a href="/css-box-shadow">CSS Box Shadow</a></li>
<li><a href="/css-gradient">CSS Gradient Generator</a></li>
<li><a href="/json-formatter">JSON Formatter / Validator</a></li>
<li><a href="/lorem-ipsum">Lorem Ipsum Generator</a></li>
<li><a href="/markdown-preview">Markdown Preview</a></li>
<li><a href="/password-generator">Password Generator</a></li>
<li><a href="/qr-generator">QR Code Generator</a></li>
<li><a href="/sql-formatter">SQL Formatter</a></li>
<li><a href="/uuid-generator">UUID Generator</a></li>
<li><a href="/word-to-markdown">Word to Markdown</a></li>
<li><a href="/xml-formatter">XML Formatter</a></li>
</ul>
</div>
<div class="atc-cat">
<div class="atc-cat-head">
<div class="atc-cat-icon">JS</div>
<div class="atc-cat-title"><h3>Minifiers & DevOps</h3><span class="atc-cat-count">6 tools</span></div>
</div>
<ul class="atc-list">
<li><a href="/chmod-calculator">chmod Calculator</a></li>
<li><a href="/cron-parser">Cron Expression Parser</a></li>
<li><a href="/css-minifier">CSS Minifier</a></li>
<li><a href="/html-minifier">HTML Minifier</a></li>
<li><a href="/js-minifier">JavaScript Minifier</a></li>
<li><a href="/http-status">HTTP Status Codes</a></li>
</ul>
</div>
<div class="atc-cat">
<div class="atc-cat-head">
<div class="atc-cat-icon">#</div>
<div class="atc-cat-title"><h3>Security & Hashing</h3><span class="atc-cat-count">3 tools</span></div>
</div>
<ul class="atc-list">
<li><a href="/hash-generator">Hash Generator (MD5, SHA)</a></li>
<li><a href="/jwt-decoder">JWT Decoder</a></li>
<li><a href="/jwt-generator">JWT Generator</a></li>
</ul>
</div>
<div class="atc-cat">
<div class="atc-cat-head">
<div class="atc-cat-icon">.*</div>
<div class="atc-cat-title"><h3>Code & Text</h3><span class="atc-cat-count">8 tools</span></div>
</div>
<ul class="atc-list">
<li><a href="/ai-token-counter">AI Token Counter</a></li>
<li><a href="/char-counter">Character & Word Counter</a></li>
<li><a href="/git-cheatsheet">Git Commands Cheatsheet</a></li>
<li><a href="/number-base">Number Base Converter</a></li>
<li><a href="/regex-explainer">Regex Explainer</a></li>
<li><a href="/regex-tester">Regex Tester</a></li>
<li><a href="/text-diff">Text Diff Checker</a></li>
<li><a href="/wcag-contrast">WCAG Contrast Checker</a></li>
</ul>
</div>
<div class="atc-cat">
<div class="atc-cat-head">
<div class="atc-cat-icon">IP</div>
<div class="atc-cat-title"><h3>Network & APIs</h3><span class="atc-cat-count">3 tools</span></div>
</div>
<ul class="atc-list">
<li><a href="/dns-lookup">DNS Lookup</a></li>
<li><a href="/http-request-builder">HTTP Request Builder</a></li>
<li><a href="/ip-lookup">IP Address Lookup</a></li>
</ul>
</div>
<div class="atc-cat">
<div class="atc-cat-head">
<div class="atc-cat-icon">⏱</div>
<div class="atc-cat-title"><h3>Time & Dates</h3><span class="atc-cat-count">3 tools</span></div>
</div>
<ul class="atc-list">
<li><a href="/relative-time">Relative Time Calculator</a></li>
<li><a href="/timestamp-diff">Timestamp Diff</a></li>
<li><a href="/unix-timestamp-converter">Unix Timestamp Converter</a></li>
</ul>
</div>
<div class="atc-cat">
<div class="atc-cat-head">
<div class="atc-cat-icon">SEO</div>
<div class="atc-cat-title"><h3>SEO & Meta</h3><span class="atc-cat-count">3 tools</span></div>
</div>
<ul class="atc-list">
<li><a href="/meta-tag-generator">Meta Tag Generator</a></li>
<li><a href="/og-preview">Open Graph Preview</a></li>
<li><a href="/slug-generator">URL Slug Generator</a></li>
</ul>
</div>
</div>
</section>
</div>
<footer>
<div>© 2026 FreeDevTool — Cron Expression Generator & Parser</div>
<div class="footer-links"><a href="/all-tools">All Tools</a><a href="/about">About</a><a href="/privacy">Privacy Policy</a><a href="/terms">Terms of Use</a></div>
</footer>
<script>
const DOW_NAMES = ['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday','Sunday'];
const MON_NAMES = ['','January','February','March','April','May','June','July','August','September','October','November','December'];
function setCron(expr) {
const parts = expr.split(' ');
document.getElementById('f-min').value = parts[0] || '*';
document.getElementById('f-hour').value = parts[1] || '*';
document.getElementById('f-dom').value = parts[2] || '*';
document.getElementById('f-month').value = parts[3] || '*';
document.getElementById('f-dow').value = parts[4] || '*';
parseCron();
}
function getCron() {
return [
document.getElementById('f-min').value.trim() || '*',
document.getElementById('f-hour').value.trim() || '*',
document.getElementById('f-dom').value.trim() || '*',
document.getElementById('f-month').value.trim() || '*',
document.getElementById('f-dow').value.trim() || '*'
].join(' ');
}
function describeField(field, names, unit) {
if (field === '*') return 'every ' + unit;
if (field.startsWith('*/')) return 'every ' + field.slice(2) + ' ' + unit + 's';
if (field.includes(',')) return unit + 's ' + field.split(',').map(v => names ? (names[parseInt(v)] || v) : v).join(', ');
if (field.includes('-')) {
const [a, b] = field.split('-');
return (names ? (names[parseInt(a)] || a) : a) + ' through ' + (names ? (names[parseInt(b)] || b) : b);
}
return (names ? (names[parseInt(field)] || field) : field);
}
function describeCron(expr) {
const [min, hour, dom, mon, dow] = expr.split(' ');
let parts = [];
if (expr === '* * * * *') return 'Every minute';
if (min.startsWith('*/') && hour === '*' && dom === '*' && mon === '*' && dow === '*')
return 'Every ' + min.slice(2) + ' minutes';
if (/^\d+$/.test(min) && hour === '*' && dom === '*' && mon === '*' && dow === '*')
return 'At minute ' + min + ' of every hour';
if (/^\d+$/.test(min) && /^\d+$/.test(hour)) {
const h = parseInt(hour); const ampm = h >= 12 ? 'PM' : 'AM';
const h12 = h === 0 ? 12 : h > 12 ? h - 12 : h;
parts.push('At ' + h12 + ':' + min.padStart(2, '0') + ' ' + ampm);
} else {
if (min !== '*') parts.push('minute ' + describeField(min, null, 'minute'));
if (hour !== '*') parts.push('hour ' + describeField(hour, null, 'hour'));
}
if (dom !== '*') parts.push('on day ' + dom + ' of the month');
if (mon !== '*') parts.push('in ' + describeField(mon, MON_NAMES, 'month'));
if (dow !== '*') parts.push('on ' + describeField(dow, DOW_NAMES, 'day'));
return parts.join(', ') || 'Every minute';
}
function expandField(field, min, max) {
if (field === '*') { const arr = []; for (let i = min; i <= max; i++) arr.push(i); return arr; }
if (field.startsWith('*/')) {
const step = parseInt(field.slice(2)); const arr = [];
for (let i = min; i <= max; i += step) arr.push(i);
return arr;
}
const vals = new Set();
field.split(',').forEach(part => {
if (part.includes('-')) {
const [a, b] = part.split('-').map(Number);
for (let i = a; i <= b; i++) vals.add(i);
} else {
vals.add(parseInt(part));
}
});
return [...vals].sort((a, b) => a - b);
}
function getNextRuns(expr, count) {
const [minF, hourF, domF, monF, dowF] = expr.split(' ');
const mins = expandField(minF, 0, 59);
const hours = expandField(hourF, 0, 23);
const doms = expandField(domF, 1, 31);
const mons = expandField(monF, 1, 12);
const dows = expandField(dowF, 0, 6);
const results = [];
const now = new Date();
const d = new Date(now);
d.setSeconds(0); d.setMilliseconds(0);
d.setMinutes(d.getMinutes() + 1);
const limit = 525600; // 1 year in minutes
for (let i = 0; i < limit && results.length < count; i++) {
const m = d.getMinutes(), h = d.getHours(), dom = d.getDate(), mon = d.getMonth() + 1, dow = d.getDay();
// POSIX cron: when BOTH day-of-month and day-of-week are restricted, match
// if EITHER fires; if only one (or neither) is restricted, AND them.
const domMatch = doms.includes(dom);
const dowMatch = dows.includes(dow);
const dayOk = (domF === '*' || dowF === '*') ? (domMatch && dowMatch) : (domMatch || dowMatch);
if (mins.includes(m) && hours.includes(h) && mons.includes(mon) && dayOk) {
results.push(new Date(d));
}
d.setMinutes(d.getMinutes() + 1);
}
return results;
}
function relTime(date) {
const diff = (date - new Date()) / 1000;
if (diff < 60) return 'in ' + Math.ceil(diff) + 's';
if (diff < 3600) return 'in ' + Math.ceil(diff / 60) + ' min';
if (diff < 86400) return 'in ' + Math.floor(diff / 3600) + 'h ' + Math.floor((diff % 3600) / 60) + 'm';
return 'in ' + Math.floor(diff / 86400) + ' days';
}
function parseCron() {
const expr = getCron();
document.getElementById('cron-display').textContent = expr;
const errEl = document.getElementById('cron-error');
try {
const desc = describeCron(expr);
document.getElementById('cron-desc').textContent = desc;
errEl.style.display = 'none';
const runs = getNextRuns(expr, 5);
let html = '';
runs.forEach((r, i) => {
html += '<div class="next-run"><span class="next-run-idx">' + (i + 1) + '</span><span class="next-run-date">' + r.toLocaleString() + '</span><span class="next-run-rel">' + relTime(r) + '</span></div>';
});
document.getElementById('next-runs').innerHTML = html || '<div style="color:var(--text3);font-size:13px">No runs found in the next year</div>';
} catch (e) {
errEl.style.display = '';
errEl.className = 'status status-err';
errEl.textContent = '\u2717 Invalid cron expression';
}
}
function copyCron() {
navigator.clipboard.writeText(getCron());
showToast();
}
function showToast() { const t=document.getElementById('copy-toast');t.classList.add('show');setTimeout(()=>t.classList.remove('show'),1800); }
function toggleFaq(el) { el.parentElement.classList.toggle('open'); }
parseCron();
</script>
<script>document.addEventListener('click',e=>{const dd=document.getElementById('tools-dropdown');if(dd&&!dd.contains(e.target))dd.classList.remove('open')});</script>
</body>
</html>