OneWebDesk

cron 표현식 작성법: 5개 필드 완전 정복

크론탭 5개 필드의 의미와 자주 쓰는 패턴, 타임존·DST 함정까지 예제로 정리.

cron 표현식은 리눅스 crontab, GitHub Actions, Kubernetes CronJob, Jenkins 등 거의 모든 스케줄러가 쓰는 “언제 실행할지”의 표준 문법입니다. 30 2 * * 1-5같은 다섯 칸짜리 줄 하나가 “평일 새벽 2시 30분마다”라는 뜻인데, 처음 보면 암호처럼 느껴지는 게 당연합니다. 이 가이드는 5개 필드의 의미와 * , - / 네 가지 기호, 실무에서 바로 복사해 쓰는 패턴 표, 그리고 많은 장애의 원인이 되는 요일·날짜 OR 함정과 타임존·DST 함정까지 예제 중심으로 정리합니다.

표현식을 작성한 뒤에는 반드시 실제 실행 시각을 확인하세요. 머릿속 해석과 스케줄러의 해석이 다른 경우가 생각보다 많습니다. 크론 다음 실행 시각 계산기에 표현식을 붙여 넣으면 앞으로의 실행 시각 목록을 바로 보여주므로, 배포 전에 10초면 검증이 끝납니다.

5개 필드: 분 시 일 월 요일

표준 crontab 표현식은 공백으로 구분된 다섯 개의 필드로 이루어지며, 왼쪽부터 다음 순서입니다.

위치필드허용 범위비고
1분 (minute)0-59 
2시 (hour)0-2324시간제
3일 (day of month)1-31매월 몇 일
4월 (month)1-12jan-dec 약어 가능
5요일 (day of week)0-70과 7 둘 다 일요일, sun-sat 약어 가능

각 필드에는 값 외에 네 가지 기호를 쓸 수 있습니다.

  • * — 모든 값. 분 필드의 *는 “매분”.
  • , — 나열. 0,30은 0분과 30분, 즉 30분마다 두 번.
  • - — 범위. 1-5는 1부터 5까지 전부(요일 필드면 월~금).
  • / — 간격(step). */5는 0, 5, 10, … 처럼 5 간격. 10-50/10처럼 범위와 조합도 가능.

주의할 점 하나: */5는 “5로 나누어떨어지는 값”이지 “마지막 실행 후 5분 뒤”가 아닙니다. 시작 기준은 항상 필드 범위의 처음(분이면 0)입니다. 그래서 */7을 분 필드에 쓰면 0, 7, 14, …, 56분에 돌고 다음 시각의 0분으로 리셋되어 56분→0분 사이 간격은 4분이 됩니다. 정확한 N분 간격이 필요하면 cron만으로는 불가능하고 systemd timer 등이 필요합니다.

실습: 30 2 * * 1-5 해석하기

많이 쓰는 표현식 하나를 필드 단위로 분해해 봅시다. 30 2 * * 1-5:

  1. 분 = 30 → 매시 30분에.
  2. 시 = 2 → 새벽 2시에만. 분과 합치면 “02:30”.
  3. 일 = * → 며칠인지는 상관없음.
  4. 월 = * → 몇 월인지도 상관없음.
  5. 요일 = 1-5 → 월요일(1)부터 금요일(5)까지.

합치면 “매주 월~금 새벽 02:30에 실행”입니다. 백업이나 배치 집계처럼 트래픽이 적은 시간대에 평일만 돌리고 싶을 때의 전형적인 패턴입니다. 읽는 순서를 “분→시→일→월→요일”로 고정해 두면 어떤 표현식이든 같은 방식으로 해석할 수 있습니다.

자주 쓰는 패턴 모음

표현식의미
*/5 * * * *5분마다 (00, 05, 10, …)
0 * * * *매시 정각 (1시간마다)
0 3 * * *매일 새벽 03:00
0 9 * * 1-5평일(월~금) 오전 09:00
0 0 1 * *매월 1일 자정
0 */6 * * *6시간마다 (00, 06, 12, 18시)
30 2 * * 0매주 일요일 02:30

crontab에는 축약형도 있습니다. @hourly(= 0 * * * *), @daily(= 0 0 * * *), @weekly, @monthly, @yearly는 대응하는 표현식의 별칭이고, @reboot은 시각이 아니라 “시스템 부팅 직후 1회”라는 특수 트리거입니다. 캐시 워밍업이나 데몬 재기동 스크립트에 유용하지만 모든 cron 구현이 지원하는 건 아니니(예: 일부 컨테이너 환경) 문서를 확인하세요.

가장 큰 함정: 일(dom)과 요일(dow)을 동시에 쓰면 OR

직관과 정반대로 동작하는 규칙이 하나 있습니다. 일 필드와 요일 필드가 둘 다 *가 아니면, 두 조건은 AND가 아니라 OR로 결합됩니다. POSIX crontab 명세에 정의된 동작입니다.

예를 들어 0 0 13 * 5를 “13일의 금요일 자정”이라고 기대하기 쉽지만, 실제로는 “매월 13일” 또는 “매주 금요일” 둘 중 하나라도 맞으면실행됩니다. 즉 한 달에 4~5번 이상 돌아갑니다. “매월 첫째 주 월요일” 같은 조건도 0 9 1-7 * 1로는 안 되고(1~7일 전부 + 매주 월요일에 실행됨), 표현식에는 요일만 남기고(0 9 * * 1) 스크립트 첫 줄에서 [ $(date +\%d) -le 7 ] || exit 0 같은 날짜 가드를 넣는 게 정석입니다.

이런 조합은 눈으로 검증하기가 특히 어렵기 때문에, 의심스러우면 크론 다음 실행 시각 계산기에 넣어 향후 실행 시각 목록이 기대와 일치하는지 꼭 확인하세요.

타임존과 DST: 새벽 2시대는 피하라

crontab은 시스템(또는 데몬)의 타임존 기준으로 동작합니다. 서버가 UTC면 0 3 * * *은 한국 시각 정오(12:00)에 돌고, 서버가 KST면 새벽 3시에 돕니다. 같은 표현식이라도 서버마다 다른 시각에 실행될 수 있다는 뜻입니다. 다중 리전 서버라면 전부 UTC로 통일하고, 로그를 볼 때 로그 타임스탬프 변환기로 UTC↔KST를 변환하는 운영 방식이 사고를 가장 줄여줍니다.

서머타임(DST)을 쓰는 타임존에서는 함정이 하나 더 있습니다. 시계가 앞으로 건너뛰는 봄에는 02:00~02:59가 통째로 사라져 30 2 * * *그날 아예 실행되지 않을 수 있고, 시계가 뒤로 돌아가는 가을에는 같은 시각이 두 번 존재해 두 번 실행되거나 구현에 따라 한 번만 실행됩니다(Vixie cron은 보정 로직이 있지만 모든 구현이 그렇진 않습니다). 한국은 DST가 없지만 해외 리전 서버·글로벌 SaaS 스케줄러를 쓴다면 남의 일이 아닙니다. 대응은 간단합니다:

  • 서버 타임존은 UTC로 고정한다 (UTC에는 DST가 없음).
  • DST 타임존을 꼭 써야 하면 01:00~03:59 사이 스케줄을 피한다.
  • 중복 실행에 대비해 잡 자체를 멱등(idempotent)하게 만들거나 락 파일을 쓴다.

crontab 환경 함정: PATH와 % 이스케이프

“터미널에서는 되는데 cron에서는 안 돼요”의 원인 대부분은 환경 차이입니다. cron은 로그인 셸이 아니어서 .bashrc를 읽지 않고, PATH /usr/bin:/bin 수준으로 최소화되어 있습니다. docker, node, aws같은 명령이 “command not found”로 죽는 이유죠. 해결책은 두 가지입니다: crontab 상단에 PATH=/usr/local/bin:/usr/bin:/bin을 선언하거나, 명령을 /usr/local/bin/node처럼 절대 경로로 적는 것입니다.

또 하나, crontab 명령 줄에서 %는 특수문자입니다. 첫 % 이후는 표준 입력으로 전달되고 개행으로 해석되므로, date +%F를 그대로 쓰면 조용히 깨집니다. 반드시 date +\%F처럼 백슬래시로 이스케이프하세요. 마지막으로 출력을 버리지 말고 >> /var/log/myjob.log 2>&1처럼 로그로 남겨야 실패를 추적할 수 있습니다.

자주 묻는 질문

요일 필드에서 0과 7은 뭐가 다른가요?
둘 다 일요일입니다. POSIX 표준은 0-6(0=일요일)이지만 대부분의 cron 구현이 7도 일요일로 받아줍니다. 호환성을 생각하면 0 또는 sun 약어를 쓰는 것이 가장 안전합니다.
일(day of month)과 요일(day of week)을 동시에 지정하면 어떻게 되나요?
두 필드가 모두 *가 아니면 AND가 아니라 OR로 동작합니다. 예를 들어 0 0 13 * 5는 '13일이면서 금요일'이 아니라 '매월 13일 또는 매주 금요일'에 실행됩니다. 두 조건을 모두 만족해야 할 때는 요일만 표현식에 두고 날짜 검사는 스크립트 안에서 하세요.
cron 표현식이 6칸이나 7칸인 경우도 있던데요?
표준 crontab은 5칸이지만 Quartz(Java)나 일부 클라우드 스케줄러는 맨 앞에 초 필드를 추가한 6칸, 맨 뒤에 연도를 추가한 7칸을 씁니다. 사용하는 시스템의 문서에서 필드 수를 먼저 확인하고, 5칸 표현식을 6칸 시스템에 그대로 붙여 넣지 마세요.
*/5는 '마지막 실행 5분 뒤'인가요?
아닙니다. */5는 필드 범위의 시작(분이면 0)부터 5로 나누어떨어지는 값, 즉 0·5·10…분을 의미합니다. 시계 기준 고정 시각이므로 잡이 3분 걸려도 다음 실행은 밀리지 않고 정해진 분에 시작됩니다.
cron에서만 스크립트가 실패하는 이유는 뭔가요?
대부분 환경 차이입니다. cron은 .bashrc를 읽지 않아 PATH가 최소한으로만 설정되고, 홈 디렉터리가 아닌 곳에서 실행될 수 있으며, 명령 줄의 %는 이스케이프하지 않으면 개행으로 해석됩니다. 절대 경로 사용, crontab 상단 PATH 선언, 출력 로그 리다이렉트로 대부분 해결됩니다.
서머타임(DST)이 있는 서버에서 새벽 2시 30분 잡은 위험한가요?
네. 봄에 시계가 02:00에서 03:00으로 건너뛰면 02:30이 존재하지 않아 그날 실행이 빠질 수 있고, 가을에는 02:30이 두 번 존재해 중복 실행될 수 있습니다. 서버를 UTC로 운영하거나 01:00~03:59 스케줄을 피하는 것이 안전합니다.

이 가이드와 함께 쓰면 좋은 도구

관련 가이드