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

Cron식 작성 마스터 가이드: 5개 필드와 특수 문자를 실제 예제로 이해하기

이 글에서는 Cron식의 5개 필드와 특수 문자를 실제 표현식과 그 의미를 짝지어 정리합니다. 마지막에는 현장에서 빠지기 쉬운 함정과 자주 묻는 질문도 담았습니다.

Cron식의 기본 구조: 5개 필드

표준 crontab의 Cron식은 공백으로 구분된 5개 필드로 구성됩니다.

┌───────────── 분        (0 - 59)
│ ┌───────────── 시      (0 - 23)
│ │ ┌───────────── 일    (1 - 31)
│ │ │ ┌───────────── 월  (1 - 12)
│ │ │ │ ┌───────────── 요일 (0 - 7, 0과 7은 일요일)
│ │ │ │ │
* * * * *

각 필드가 가질 수 있는 값의 범위는 다음과 같습니다.

필드범위비고
0–59
0–230이 자정, 23이 23시
1–31월의 날짜
1–12JANDEC도 가능(구현에 따라)
요일0–70과 7이 일요일, 1이 월요일; SUNSAT도 가능

참고: 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 * * *입니다. 스케줄러에 타임존 지정이 있다면 그것을 쓰는 것이 가장 확실합니다.

*/50/5는 같은가요?

분 필드에서는 둘 다 “5분마다(0,5,10,…)”로 사실상 같습니다. */5는 “전체 범위를 5 간격으로”, 0/5는 “0부터 5 간격으로”라는 의미로, 시작 위치를 옮기고 싶을 때(예 7/15) 명시적인 시작 지정이 유용합니다.