Tools mentioned in this article
Open the browser-based tool while you read and try the workflow immediately.
0 3 * * 1-5라는 단 한 줄로 “평일 오전 3시에 실행”이라는 스케줄을 표현할 수 있습니다. 그것이 Cron식입니다. Linux의 crontab부터 GitHub Actions, Kubernetes CronJob, 각종 클라우드 스케줄러까지 정기 실행의 세계는 거의 이 문법으로 돌아갑니다.

이 글에서는 Cron식의 5개 필드와 특수 문자를 실제 표현식과 그 의미를 짝지어 정리합니다. 마지막에는 현장에서 빠지기 쉬운 함정과 자주 묻는 질문도 담았습니다.
Cron식의 기본 구조: 5개 필드
표준 crontab의 Cron식은 공백으로 구분된 5개 필드로 구성됩니다.
┌───────────── 분 (0 - 59)
│ ┌───────────── 시 (0 - 23)
│ │ ┌───────────── 일 (1 - 31)
│ │ │ ┌───────────── 월 (1 - 12)
│ │ │ │ ┌───────────── 요일 (0 - 7, 0과 7은 일요일)
│ │ │ │ │
* * * * *
각 필드가 가질 수 있는 값의 범위는 다음과 같습니다.
| 필드 | 범위 | 비고 |
|---|---|---|
| 분 | 0–59 | |
| 시 | 0–23 | 0이 자정, 23이 23시 |
| 일 | 1–31 | 월의 날짜 |
| 월 | 1–12 | JAN–DEC도 가능(구현에 따라) |
| 요일 | 0–7 | 0과 7이 일요일, 1이 월요일; SUN–SAT도 가능 |
참고: GitHub Actions와 Kubernetes도 기본은 이 5필드 형식입니다. 반면 Quartz나 AWS EventBridge는 ‘초’나 ‘연’을 더한 6~7필드 형식을 쓰기 때문에, 아래에서 설명하는
?나L같은 특수 문자가 필요합니다.
특수 문자를 실제 예제로 이해하기
Cron식의 표현력은 각 필드에 쓸 수 있는 특수 문자에서 나옵니다.
| 기호 | 의미 | 예시 | 읽는 법 |
|---|---|---|---|
* | 모든 값 | * * * * * | 매분 |
, | 값의 나열 | 0 9,12,18 * * * | 매일 9시·12시·18시 |
- | 범위 | 0 9-17 * * * | 매일 9시~17시의 매 정시 |
/ | 간격(스텝) | */15 * * * * | 15분마다 |
? | 지정 없음(일/요일) | 0 0 ? * MON | 매주 월요일 0시 |
L | 마지막(last) | 0 0 L * * | 매월 말일 0시 |
W | 가장 가까운 평일 | 0 0 15W * * | 15일에 가장 가까운 평일 |
# | n번째 요일 | 0 9 ? * MON#1 | 첫째 주 월요일 9시 |
?·L·W·#는 Quartz 계열 스케줄러(Spring, Jenkins, EventBridge 등)의 확장으로, 표준 crontab에서는 쓸 수 없다는 점에 주의하세요.
/(스텝) 읽는 법
*/15는 “0부터 시작해 15씩”, 즉 0,15,30,45를 의미합니다. 범위와 조합하면 시작 위치를 지정할 수 있습니다.
*/15 * * * * → 0,15,30,45분 (15분마다)
5/10 * * * * → 5,15,25,35,45,55분 (5분부터 10분마다)
0 9-17/2 * * * → 9,11,13,15,17시 (9~17시의 2시간마다)
자주 쓰는 스케줄 예시
그대로 복사해 쓸 수 있는, 현장에서 자주 나오는 패턴입니다.
| 하고 싶은 것 | Cron식 |
|---|---|
| 매분 | * * * * * |
| 5분마다 | */5 * * * * |
| 매시 0분 | 0 * * * * |
| 매일 자정 | 0 0 * * * |
| 매일 오전 9시 30분 | 30 9 * * * |
| 평일 오전 3시 | 0 3 * * 1-5 |
| 평일 9~18시의 30분마다 | */30 9-18 * * 1-5 |
| 매주 월요일 오전 9시 | 0 9 * * 1 |
| 매월 1일 자정 | 0 0 1 * * |
| 매월 말일 자정(Quartz 계열) | 0 0 L * * |
| 첫째 주 월요일 오전 9시(Quartz 계열) | 0 9 ? * MON#1 |
현장에서 빠지기 쉬운 함정
1. ‘일’과 ‘요일’을 둘 다 지정하면 OR 조건이 됩니다
0 0 1 * 1은 “1일 또는 월요일의 자정”입니다. “1일이 월요일일 때”라는 AND 조건이 아닙니다. 직관에 어긋나므로 둘 중 하나만 지정하고 다른 쪽은 *(Quartz 계열에서는 ?)로 두는 것이 안전합니다.
2. 타임존은 실행 환경에 따라 다릅니다
많은 cron은 서버의 타임존을, 컨테이너나 CI는 UTC로 도는 경우가 흔합니다. 0 0 * * *라고 써도 KST(UTC+9)의 0시가 아니라 UTC의 0시(=KST 오전 9시)에 도는 사고는 자주 일어납니다. KST 새벽 2시에 돌리고 싶다면 UTC 기준으로는 0 17 * * *입니다.
3. 분 필드를 *로 두면 매분 실행됩니다
* 3 * * *(매일 3시에 한 번 의도)는 3시대의 60번 실행됩니다. “3시 정각에 한 번”이라면 0 3 * * *입니다.
4. 너무 짧은 간격의 중복 실행
5분마다인 작업이 5분 안에 끝나지 않으면, 이전 작업이 도는 중에 다음 작업이 시작되어 다중 실행이 됩니다. 처리 시간에 여유를 둔 간격으로 설정하거나 잠금(lock) 메커니즘을 검토하세요.
도구로 ‘저장 전의 불안’을 없애기
Cron식은 읽고 쓰는 데 익숙함이 필요하고, 위의 함정들은 눈으로 알아채기 어렵습니다. Cron식 파서에서는 입력한 Cron식을 자연어 설명으로 변환하고, 다음 실행 일시를 시뮬레이션해 확인할 수 있습니다. 배포 전에 “정말 의도한 스케줄인지”를 한눈에 검증할 수 있습니다.
자주 묻는 질문
Cron식의 요일은 0과 7 중 어느 쪽이 일요일인가요?
많은 구현에서 0과 7 모두 일요일을 가리킵니다. 월요일은 1, 토요일은 6입니다. 혼란을 피하려면 SUN MON 같은 영어 세 글자 표기를 쓸 수 있는 환경에서는 그쪽을 쓰는 것이 안전합니다.
‘매월 마지막 날’은 어떻게 쓰나요?
Quartz나 EventBridge처럼 L을 지원하는 환경이라면 0 0 L * *로 표현할 수 있습니다. 표준 crontab에는 L이 없으므로, 월말 후보일(28~31일)에 실행해 스크립트 측에서 판정하거나, 프로그램으로 계산하는 우회책이 필요합니다.
UTC와 KST의 차이는 어떻게 다루나요?
KST는 UTC+9입니다. KST 시각에서 UTC Cron식을 만들려면 시 필드에서 9를 뺍니다(음수가 되면 전날 취급으로 +24). 예를 들어 KST 새벽 2시는 UTC 전날 17시이므로 0 17 * * *입니다. 스케줄러에 타임존 지정이 있다면 그것을 쓰는 것이 가장 확실합니다.
*/5와 0/5는 같은가요?
분 필드에서는 둘 다 “5분마다(0,5,10,…)”로 사실상 같습니다. */5는 “전체 범위를 5 간격으로”, 0/5는 “0부터 5 간격으로”라는 의미로, 시작 위치를 옮기고 싶을 때(예 7/15) 명시적인 시작 지정이 유용합니다.