Blog
DevOps & Infrastructure••10 min read

Cron Expressions Explained: From Syntax Mechanics to Critical Daylight Saving Time Traps

Master standard 5-field and 6-field Cron scheduling syntax, understand exact matching vs step intervals, and prevent catastrophic duplicate and missed job executions during DST clock shifts.

Automated scheduling is the backbone of modern software engineering. From running midnight database vacuuming and orchestrating ETL data pipelines to triggering billing cycles and generating daily customer digests, developers rely heavily on Cron expressions.

Conceived by Ken Thompson in Unix Version 7 in 1979, the cron syntax has stood the test of time for nearly five decades. Yet, behind its succinct string notation (0 2 * * *) lies an intricate state engine prone to edge cases.

In this guide, we break down standard cron syntax mechanics, explore subtle dialect differences between POSIX, Quartz, and AWS EventBridge, and reveal the single most dangerous hazard in background automation: Daylight Saving Time (DST) clock anomalies.


1. Anatomy of Standard 5-Field POSIX Cron

The standard cron format consists of five whitespace-separated fields representing distinct units of time:

 ┌───────────── Minute (0 - 59)
 │ ┌─────────── Hour (0 - 23)
 │ │ ┌───────── Day of Month (1 - 31)
 │ │ │ ┌─────── Month of Year (1 - 12 or JAN - DEC)
 │ │ │ │ ┌───── Day of Week (0 - 6, where 0 = Sunday, or SUN - SAT)
 │ │ │ │ │
 * * * * *

Core Operator Syntax

Every field accepts a variety of operators that dictate schedule frequency:

Operator Name Meaning Example
* Asterisk (Wildcard) Matches every possible value in that field * in Minute means every minute
, Comma (List) Defines a set of discrete values 1,15,30 in Minute matches at 1m, 15m, and 30m
- Hyphen (Range) Matches an inclusive range of values 9-17 in Hour matches from 9 AM to 5 PM
/ Slash (Step) Specifies execution increments within a range */15 in Minute matches every 15 minutes

The “Day-of-Month” vs. “Day-of-Week” OR Logic (The Hidden Quirk)

One of the most common pitfalls in standard cron is understanding how the Day of Month and Day of Week fields interact:

Important POSIX Rule: If both Day of Month and Day of Week are explicitly specified (i.e. neither is *), the schedule evaluates them as a logical OR, not a logical AND.

For example, the expression:

0 12 15 * 1

Does NOT mean “Run at noon on Monday the 15th”. Instead, it means: “Run at noon on the 15th of the month OR on any Monday”.

To restrict execution to a specific weekday on a specific week (e.g., “the second Monday of every month”), systems like Quartz Scheduler or Spring Framework introduce the ? (no specific value) or # operator (1#2).


2. Dialect Differences: POSIX vs. Quartz vs. AWS EventBridge

When writing cron expressions across different cloud providers and frameworks, syntax variances frequently lead to deployment bugs:

POSIX (Linux, Kubernetes CronJob, Node-cron):
[Minute] [Hour] [Day-of-Month] [Month] [Day-of-Week]

Quartz / Spring:
[Second] [Minute] [Hour] [Day-of-Month] [Month] [Day-of-Week] [Year (optional)]

AWS EventBridge / CloudWatch Rules:
[Minute] [Hour] [Day-of-Month] [Month] [Day-of-Week] [Year]
(Requires '?' in either Day-of-Month or Day-of-Week)

Notice that standard Linux / Kubernetes cron schedules do not support seconds. If your task requires sub-minute granularity, using standard POSIX cron will result in syntax parsing exceptions.


3. The Daylight Saving Time (DST) Nightmare

The most critical production outages caused by cron occur twice a year during Daylight Saving Time (DST) transitions: “Spring Forward” and “Fall Back”.

If your server or database scheduler runs on a local timezone (e.g. America/New_York or Europe/London) instead of UTC, scheduled jobs will behave unexpectedly:

Spring Forward (+1 Hour):
01:59:59 AM  ──>  03:00:00 AM  (02:00:00 - 02:59:59 is SKIPPED completely)

Fall Back (-1 Hour):
01:59:59 AM  ──>  01:00:00 AM  (01:00:00 - 01:59:59 OCCURS TWICE)

Scenario 1: The Missed Midnight Payroll / Database Vacuum (Spring Forward)

Suppose you schedule a heavy database cleanup job:

30 2 * * *   # Run daily at 2:30 AM

On the second Sunday in March in North America, clocks jump from 01:59:59 AM straight to 03:00:00 AM. 2:30 AM never occurs. Depending on the implementation of the cron daemon:

  • The job is skipped entirely for that day; OR
  • The daemon detects a missed trigger and executes it unexpectedly at 03:00:01 AM alongside heavy morning peak workloads.

Scenario 2: Double Invoicing & Duplicate Billing (Fall Back)

Suppose you schedule customer invoice billing:

30 1 * * *   # Run daily at 1:30 AM

On the first Sunday in November, clocks reach 01:59:59 AM and fall back to 01:00:00 AM. 1:30 AM occurs twice. If your billing worker lacks idempotent payment locking, customers will be billed twice within a single 60-minute window.


4. Production Architectural Rules for Reliable Scheduling

Rule 1: Always Run Schedulers in Coordinated Universal Time (UTC)

Never configure your production scheduler or worker containers (crond, Kubernetes CronJob, Celery Beat, BullMQ) to use local timezones.

# Kubernetes CronJob Best Practice:
spec:
  timeZone: "Etc/UTC" # Always declare explicit UTC
  schedule: "0 6 * * *" # Runs at 06:00 UTC (1:00 AM EST, consistent year-round)

UTC does not observe Daylight Saving Time and increases monotonically without skipped or repeated hours.

Rule 2: Ensure Idempotency with Distributed Locks

Never assume a cron job will fire exactly once. Network retries, node failovers, and daemon restarts can cause duplicate runs. Use an idempotent key in Redis or your database:

async function executeDailyPayouts() {
  const todayKey = `lock:payouts:${new Date().toISOString().slice(0, 10)}`;
  
  // Acquire distributed lock with TTL
  const acquired = await redis.set(todayKey, "locked", "NX", "EX", 86400);
  if (!acquired) {
    console.warn("Payout task already running or completed for today. Skipping.");
    return;
  }

  // Execute mission-critical job...
}

5. Summary & Interactive Tools

To quickly build, inspect, and verify complex schedules without deploying broken configurations:

Tags:#Cron#Scheduling#DevOps#Timezones#Daylight Saving Time#Distributed Systems#Backend
← Back to all engineering guides

More Technical Guides

Continue exploring our architecture and systems engineering library.