Cron 표현식 문법 설명
cron 표현식은 개발자가 한 번 배우고 세부 사항을 잊은 다음 6개월마다 다시 찾아보는 주제 중 하나입니다. 30 9 * * 1-5 같은 5개 문자 문자열은 놀랍도록 구체적인 스케줄 — "평일 오전 9:30" — 을 인코딩할 수 있지만, 문법은 실제 혼란을 일으킬 만큼 충분한 엣지 케이스가 있습니다: 0 인덱스 대 1 인덱스 필드, 일요일이 0과 7 모두인 점, Unix 표준과 Quartz의 6필드 확장 간의 차이, 그리고 범위와 결합된 단계 값의 미묘한 동작.
이 가이드는 첫 원리에서 cron 문법을 다룬 다음 구체적인 예제와 함께 모든 특수 문자를 살펴봅니다. Linux 데몬용 cron 작업을 작성하든, GitHub Actions 스케줄을 구성하든, AWS EventBridge 규칙을 설정하든 동일한 기본 개념이 적용됩니다 — 그 과정에서 몇 가지 중요한 플랫폼 차이가 설명됩니다.
5개 표준 필드
표준 cron 표현식은 왼쪽에서 오른쪽으로 읽는 공백으로 구분된 5개의 필드를 가집니다: 분, 시, 일, 월, 요일. 각 필드는 그 차원을 따라 작업이 실행되는 시기를 제약합니다. 작업은 다섯 개의 필드가 모두 동시에 일치할 때만 실행됩니다.
# 필드 위치 범위 특수 문자
# ─────────────────────────────────────────────────
# 분 1 0-59 * / , -
# 시 2 0-23 * / , -
# 일 3 1-31 * / , - ? L W
# 월 4 1-12 또는 JAN-DEC * / , -
# 요일 5 0-7 (0=7=일) 또는 SUN-SAT * / , - ? L # 30 9 * * 1-5 같은 표현식 읽기: 분 30, 시 9, 모든 일, 모든 월, 요일 1부터 5(월요일부터 금요일). 결과: 매 평일 오전 9:30.
필드 1: 분 (0–59)
분 필드는 작업이 시의 어느 분(들)에 실행되어야 하는지 지정합니다. 0은 정시를 의미하고, 30은 30분, 59는 시가 바뀌기 1분 전을 의미합니다. *를 사용하면 작업이 매분 실행됩니다.
필드 2: 시 (0–23)
시는 24시간 시간을 사용합니다. 0은 자정, 12는 정오, 23은 오후 11:00입니다. cron에는 AM/PM이 없습니다 — 오전 9:00 작업은 시 9이고, 오후 9:00 작업은 시 21입니다.
필드 3: 일 (1–31)
다른 필드와 달리 일은 0이 아닌 1에서 시작합니다. 유효한 값은 1부터 31까지입니다. 주어진 달에 존재하지 않는 일을 지정하면(예: 4월의 31일) 그 달에는 작업이 실행되지 않습니다. Quartz에서 특수 문자 L은 그 달의 일수에 관계없이 마지막 날을 나타냅니다.
필드 4: 월 (1–12)
월 값은 1(1월)부터 12(12월)까지입니다. 많은 스케줄러는 세 글자 약어도 받습니다: JAN, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV, DEC. 이것들은 대부분의 구현에서 대소문자를 구분하지 않습니다.
필드 5: 요일 (0–7)
이것은 가장 많은 역사적 짐을 가진 필드입니다. 0과 7 모두 일요일을 나타냅니다 — 이는 초기 Unix의 호환성 특이성입니다. 월요일은 1, 화요일은 2, 토요일은 6까지입니다. 세 글자 이름도 여기서 작동합니다: SUN, MON, TUE, WED, THU, FRI, SAT.
일과 요일이 모두 지정되어 있을 때(어느 것도 *가 아님) 대부분의 Unix cron 데몬은 OR 로직을 사용합니다: 작업은 어느 하나라도 일치하면 실행됩니다. 이는 많은 개발자를 놀라게 합니다. "15일이지만 평일인 경우에만"을 원한다면 cron 표현식이 아닌 작업 스크립트 자체에서 처리해야 합니다.
특수 문자
별표 (*) — 모든 값
별표는 필드의 모든 유효한 값에 일치합니다. 분 필드에서 *는 0에서 59까지의 분을 의미합니다. 월 필드에서는 12개월 모두를 의미합니다. cron 표현식에서 가장 일반적인 문자입니다.
슬래시 (/) — 단계 값
슬래시는 단계 간격을 정의합니다. 분 필드의 */5는 "5분마다"를 의미합니다. 더 정확히는 "범위의 첫 번째 값에서 시작하여 5로 나뉘는 범위의 모든 값"을 의미합니다. 따라서 분의 */5는 0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55로 평가됩니다.
단계는 범위와 결합될 수 있습니다: 분 필드의 10-30/5는 분 10과 분 30 사이에 5분마다를 의미하며 10, 15, 20, 25, 30을 산출합니다. 단계는 범위의 하한에서 시작합니다.
쉼표 (,) — 값 목록
쉼표는 특정 값의 목록을 만듭니다. 월 필드의 1,3,5는 1월, 3월, 5월을 의미합니다. 시 필드의 9,17은 9:00과 17:00을 의미합니다. 필요한 만큼 많은 값을 나열하고 다른 구조와 결합할 수 있습니다.
대시 (-) — 범위
대시는 포괄적 범위를 지정합니다. 요일 필드의 1-5는 월요일부터 금요일까지를 의미합니다. 시 필드의 9-17은 오전 9시부터 오후 5시까지를 의미합니다. 범위는 양쪽 끝에서 포괄적입니다.
물음표 (?) — 특정 값 없음 (Quartz만)
표준 Unix cron은 ?를 지원하지 않습니다. Quartz Scheduler에서 일이나 요일 필드에서 "이 필드는 신경 쓰지 않는다"를 의미하는 데 사용됩니다. Quartz가 일과 요일 사이의 충돌을 항상 해결할 수 없기 때문에 다른 하나가 지정되었을 때 둘 중 하나는 ?로 설정되어야 합니다. 0 0 15 * ?는 "매월 15일, 모든 요일"을 의미합니다. 0 0 ? * MON은 "매주 월요일, 모든 일"을 의미합니다.
L — 마지막 (Quartz만)
일 필드의 L은 그 달의 마지막 날을 의미합니다. 요일 필드의 L은 토요일을 의미하거나, 숫자(예: 5L)와 결합되면 그 달의 그 요일의 마지막 발생을 의미합니다. 5L은 그 달의 마지막 금요일입니다.
W — 가장 가까운 평일 (Quartz만)
일 필드의 W는 주어진 날에 가장 가까운 평일(월요일–금요일)을 찾습니다. 15W는 15일에 가장 가까운 평일을 의미합니다. 15일이 토요일이면 작업은 14일(금요일)에 실행됩니다. 일요일이면 16일(월요일)에 실행됩니다. W는 월 경계를 넘지 않습니다.
해시 (#) — 월의 N번째 요일 (Quartz만)
#는 한 달에서 요일의 N번째 발생을 지정합니다. 5#2는 그 달의 두 번째 금요일을 의미합니다. 2#1은 첫 번째 화요일을 의미합니다. 지정된 발생이 주어진 달에 존재하지 않으면 그 달에는 작업이 실행되지 않습니다.
일반적인 Cron 패턴
# 매분
* * * * *
# 매일 자정(00:00)
0 0 * * *
# 매일 오전 9:30
30 9 * * *
# 매주 월요일 오전 8:00
0 8 * * 1
# 매월 1일 정오
0 12 1 * *
# 15분마다
*/15 * * * *
# 평일 오후 6:00
0 18 * * 1-5 모든 표현식에 대한 다음 다섯 개의 실행 시간을 보여주고 잘못된 문법을 강조 표시하는 Cron Parser 도구를 사용하여 이들 중 어느 것이든 테스트하고 검증할 수 있습니다. 특정 Unix 타임스탬프가 로컬 타임존에서 무엇에 해당하는지 확인해야 하는 경우 Timestamp Converter를 사용하세요.
6필드 확장: Quartz Scheduler
Quartz Scheduler — Java 생태계에서 많이 사용되며 많은 엔터프라이즈 스케줄러에 채택됨 — 는 표현식의 시작 부분에 필수 초 필드를 추가합니다. 형식은: 초 분 시 일 월 요일이 됩니다.
# Quartz 6필드: 초 분 시 일 월 요일
# 매시 정확히 00초, 30분에 실행
0 30 * * * ?
# 매일 자정에 실행
0 0 0 * * ?
# 5초마다 실행
0/5 * * * * ?
# 매월 마지막 날 오전 10:00
0 0 10 L * ?
# 매월 마지막 금요일 오후 3:00
0 0 15 ? * 6L
표준 cron과의 주요 차이점: 초 필드(0–59)가 먼저이며 필수입니다; 요일은 0–6이 아닌 1(일요일)에서 7(토요일)을 사용합니다; 다른 하나가 지정되었을 때 일이나 요일 중 하나에 ?가 필요합니다; 그리고 L, W, #가 유효한 특수 문자입니다.
초 필드를 제거하고 요일 번호를 조정하지 않고는 Quartz 표현식을 Unix crontab에 절대 붙여넣지 마세요. 파서는 상호 교환할 수 없습니다.
다양한 시스템의 Cron
Linux/Unix crontab (Vixie cron)
원래이며 가장 일반적인 형태. 5개 필드, 공백으로 구분, 명령어가 뒤따릅니다. CRON_TZ나 TZ 같은 환경 변수가 타임존을 설정합니다. 사용자 crontab은 crontab -e로 편집됩니다; 시스템 crontab은 /etc/cron.d/에 있습니다. @reboot, @daily, @hourly, @weekly, @monthly 단축키는 일반적인 패턴의 별칭으로 널리 지원됩니다.
GitHub Actions
GitHub Actions는 표준 5필드 cron 문법을 사용하지만 타임존은 항상 UTC입니다 — 표현식 자체에서 현지 타임존을 지정하는 방법은 없습니다. 표현식은 작업별이 아닌 저장소 수준에서 평가됩니다. GitHub 인프라의 고부하 기간 동안 예약된 워크플로가 몇 분 지연될 수 있다는 점에 유의하세요.
# GitHub Actions 스케줄 문법(5필드 UTC만)
on:
schedule:
# 매일 02:30 UTC에 실행
- cron: '30 2 * * *'
# 매주 월요일 09:00 UTC에 실행
- cron: '0 9 * * 1' 공식 GitHub Actions cron 문서는 최소 간격이 5분이라고 명시합니다 — 그보다 더 자주 실행되는 표현식은 조용히 무시됩니다.
AWS EventBridge (CloudWatch Events)
AWS EventBridge는 비율 표현식(rate(5 minutes))과 cron 표현식 모두를 지원합니다. 그들의 cron 변형은 6필드이지만 Quartz와 다릅니다: 요일은 Sun–Sat 이름이나 1이 일요일인 1–7을 사용하고, 모든 시간은 UTC이며, 일이나 요일 중 하나는 ?여야 합니다. AWS는 W나 # 문자를 지원하지 않습니다.
# AWS EventBridge(UTC의 cron, 6필드 변형)
# 매일 오전 10:00 UTC에 실행
cron(0 10 * * ? *)
# 매월 마지막 평일 오후 6:00에 실행
cron(0 18 L-1 * ? *) Kubernetes CronJob
Kubernetes CronJob은 표준 5필드 cron 문법을 사용합니다. 타임존은 기본적으로 kube-controller-manager 프로세스의 타임존(일반적으로 관리되는 클러스터에서 UTC)이 됩니다. Kubernetes 1.25는 시스템 타임존에 의존하지 않고 작업별 타임존 설정을 허용하는 timeZone 필드를 CronJob 사양에 추가했습니다.
Node.js (node-cron / cron npm)
인기 있는 node-cron 패키지는 표준 5필드 표현식과 함께 선택적인 6번째 초 필드를 앞에 붙이는 것을 지원합니다. cron 패키지는 Quartz 호환입니다. 둘 다 생성자 옵션으로 타임존 문자열(예: America/New_York)을 지원합니다. 어떤 형식을 기대하는지 확인하려면 특정 패키지의 문서를 확인하세요.
일반적인 함정
타임존 가정
cron은 서버나 컨테이너 타임존에서 실행되며, 클라우드 환경에서는 자주 UTC입니다. "오전 9시 업무 시간"에 실행하려는 작업을 0 9 * * *로 설정하면 오전 9시 UTC에 실행됩니다 — 이는 오프셋과 DST에 따라 현지 타임존에서 오전 4시, 오전 5시 또는 오전 11시일 수 있습니다. 항상 CRON_TZ를 설정하거나, 스케줄러의 타임존 필드를 사용하거나, 대상 시간을 명시적으로 UTC로 변환하세요. Timezone Converter는 모든 타임존에서 모든 현지 시간에 대한 UTC 등가물을 찾는 데 도움이 될 수 있습니다.
일/요일 OR 로직
Unix cron에서 일과 요일 필드가 모두 비-*일 때 데몬은 어느 하나라도 일치하면 작업을 실행합니다. 따라서 0 9 15 * 1은 매월 15일과 매주 월요일에 실행됩니다 — 15일에 해당하는 월요일에만 실행되는 것이 아닙니다. AND 로직을 달성하려면 작업 스크립트 내부에 추가 검사를 구현해야 합니다.
단계 값을 범위와 혼동
*/5는 "0에서 시작하여 5분마다"(0, 5, 10 ...)를 의미합니다. 5/5는 "5에서 시작하여 5분마다"(5, 10, 15 ...)를 의미합니다. 5-30/5는 "분 5와 분 30 사이에 5분마다"(5, 10, 15, 20, 25, 30)를 의미합니다. 시작 값에 대해 신중하지 않으면 이들을 범위와 혼합하면 예기치 않은 결과가 발생할 수 있습니다.
"매초" 함정
표준 5필드 형식에서 cron의 최소 해상도는 1분입니다. crontab을 사용하여 cron 작업이 매초 또는 몇 초마다 실행되도록 예약할 수 없습니다. 분 미만 스케줄링의 경우 cron 대신 언어 수준 타이머(Node.js의 setInterval, Python의 APScheduler)나 목적별 큐 시스템을 사용하세요. 30초마다 필요한 경우 두 개의 cron 작업을 실행하세요: 하나는 * * * * *에, 하나는 실행 전에 30초 동안 잠자는 것.
월 번호 매기기 놓치기
표준 cron에서 월은 1(1월)부터 12(12월)까지입니다. 일부 프로그래밍 언어 날짜 API에서 월은 0 인덱스입니다(0 = 1월, 11 = 12월). 날짜 객체에서 프로그래밍 방식으로 cron 표현식을 생성하는 경우 월 필드에서 1만큼 어긋나지 않는지 다시 확인하세요.
표현식 검증
Toova의 Cron Parser는 모든 표현식에 대한 다음 다섯 개의 예약된 실행 시간을 보여주고, 5필드와 6필드 Quartz 문법 모두를 지원하며, 잘못된 값을 인라인으로 표시합니다. 빠른 정상 검사를 위해 crontab.guru는 표현식을 평이한 영어로 설명하는 잘 알려진 대화형 도구입니다. 둘 다 북마크해 두면 유용합니다.
타임스탬프와 예약된 시간으로 작업할 때 Timestamp Converter는 모든 타임존에서 Unix 타임스탬프와 사람이 읽을 수 있는 날짜 간에 번역합니다. 타임존 민감 스케줄링이 포함된 작업의 경우 Timezone Converter와 짝지어 최종 표현식을 작성하기 전에 오프셋, DST 전환 및 UTC 등가물을 확인하세요.