Skip to main content
Tools Harbor

Cron expression for every weekday

The cron expression 0 9 * * 1-5 runs a job at 9 AM Monday through Friday — five runs per week, none on weekends. The 1-5 is the day-of-week range using Unix numbering (Sunday=0, Saturday=6). AWS EventBridge needs cron(0 9 ? * MON-FRI *) because its day-of-week numbering starts at 1 (Sun=1, Sat=7).

Quick reference

PlatformExpressionDay-of-week numbering
Unix / Linux crontab0 9 * * 1-5Sun=0, Mon=1, …, Sat=6 (7 also = Sun)
Kubernetes CronJob0 9 * * 1-5Same as Unix
GitHub Actions0 9 * * 1-5Same as Unix
AWS EventBridgecron(0 9 ? * MON-FRI *)Sun=1, Mon=2, …, Sat=7
Quartz (Java)0 0 9 ? * MON-FRI *Same as AWS

Why does day-of-week numbering differ between Unix and AWS?

This is one of the most stubborn cron gotchas. Unix cron (and Vixie cron, used by Linux/macOS/Kubernetes) uses 0-based numbering where Sunday is 0. AWS EventBridge and Quartz use 1-based numbering where Sunday is 1.

So:

DayUnix cronAWS EventBridge
Sunday0 (or 7)1
Monday12
Friday56
Saturday67

This means 0 9 * * 1-5 (weekdays 9 AM in Unix) is cron(0 9 ? * 2-6 *) in AWS — both numbers shift by one. Get it wrong and Unix’s “Mon-Fri” becomes AWS’s “Sun-Thu”, silently dropping Friday and adding Sunday.

The clearest fix: use named days everywhere AWS accepts them. cron(0 9 ? * MON-FRI *) is unambiguous — there’s no off-by-one.

Variations

ScheduleExpression
9 AM weekdays (the canonical example)0 9 * * 1-5
8:30 AM weekdays30 8 * * 1-5
5 PM weekdays (end-of-day report)0 17 * * 1-5
Weekends only (Saturday + Sunday)0 9 * * 6,0
Every weekday at 9 AM and 5 PM (twice daily)0 9,17 * * 1-5
Weekdays in AWS (named form)cron(0 9 ? * MON-FRI *)
Weekdays in AWS (numeric form)cron(0 9 ? * 2-6 *)

How do I use it on each platform?

Linux crontab:

0 9 * * 1-5 /usr/local/bin/morning-report

Kubernetes CronJob:

apiVersion: batch/v1
kind: CronJob
metadata:
  name: morning-report
spec:
  schedule: "0 9 * * 1-5"
  timeZone: "America/New_York"     # so 9 AM is Eastern, not UTC
  jobTemplate:
    spec:
      template:
        spec:
          containers:
            - name: report
              image: my-org/morning-report:1.0
          restartPolicy: OnFailure

AWS EventBridge Scheduler (with timezone):

Type: AWS::Scheduler::Schedule
Properties:
  Name: morning-report
  ScheduleExpression: 'cron(0 9 ? * MON-FRI *)'    # named days are unambiguous
  ScheduleExpressionTimezone: 'America/New_York'
  FlexibleTimeWindow:
    Mode: 'OFF'
  Target:
    Arn: !GetAtt ReportFunction.Arn
    RoleArn: !GetAtt SchedulerRole.Arn

GitHub Actions (UTC):

on:
  schedule:
    - cron: '0 14 * * 1-5'     # 9 AM EST = 14:00 UTC during standard time

GitHub Actions has no timezone option. If you want “9 AM Eastern”, convert to UTC and accept that DST will shift the firing time twice a year.

Common mistakes

Off-by-one when porting between Unix and AWS. * * * * 1-5 (Unix Mon-Fri) becomes cron(* * ? * 2-6 *) in AWS — both numbers shift up by one. Easier to remember: just use named days in AWS.

Using 0 for Sunday in AWS. AWS treats 0 as invalid (its range is 1-7). The Unix-style 0 0 * * 0 (Sunday in Unix) becomes cron(0 0 ? * 1 *) in AWS. Or just write SUN.

Forgetting ? in AWS when restricting day-of-week. AWS requires ? for whichever of dom/dow you’re not constraining. cron(0 9 * * MON-FRI *) is rejected; cron(0 9 ? * MON-FRI *) is the valid form.

For other schedules see common cron schedules, or build a custom expression with the Cron Expression Builder.

Frequently asked questions

Why does Sunday have two valid numbers in Unix cron?
Vixie cron accepts both `0` and `7` as Sunday for backwards compatibility with older System V cron implementations. So `0 0 * * 0` and `0 0 * * 7` both mean "every Sunday at midnight". Modern documentation prefers `0`. AWS EventBridge does NOT accept `7` for Sunday — it uses 1-based numbering where Sunday is `1` and Saturday is `7`.
How do I write "every weekday" in AWS EventBridge?
Use named days to dodge the off-by-one risk: `cron(0 9 ? * MON-FRI *)`. The numeric form is `cron(0 9 ? * 2-6 *)` because AWS counts Monday as `2` (Sunday=1). The named form is harder to get wrong and shows the intent clearly in code review.
How do I exclude public holidays from a weekday cron?
Cron has no concept of holidays. Either filter inside the job (check the date and exit early), use a workflow scheduler that supports calendars (Airflow, Argo Workflows), or maintain a list of explicit "skip dates" in your job logic. For a small set of US federal holidays, a 30-line wrapper script is usually enough.

Need a different schedule?

Build cron expressions for Unix, Kubernetes and AWS — with a human-readable description and the next 5 run times.

Open the Cron Expression Builder →

Related