크론 표현식 읽는 법과 자주 쓰는 패턴
다섯 칸을 읽는 순서, 특수 문자의 정확한 뜻, 용도별 표현식과 실제 다음 실행 시각, 31일·2월 29일·일 간격의 함정, 일과 요일을 함께 쓰면 OR가 되는 규칙, UTC 서버에서 한국 시각 맞추기, 크론으로 표현할 수 없는 일정을 정리했습니다.
0 0 */2 * *는 "이틀에 한 번"이 아닙니다. 매월 1, 3, 5, …, 31일에 실행되므로 31일이 있는 달에는 31일과 다음 달 1일에 연달아 돌고, 0 0 1 * 1은 "매월 1일이면서 월요일"이 아니라 매월 1일과 매주 월요일 모두에 돕니다. 크론 표현식은 다섯 칸짜리 짧은 문법이지만 이렇게 직관과 어긋나는 규칙이 몇 개 있어, 읽는 법을 정확히 알아야 새벽에 두 번 도는 배치를 막을 수 있습니다. 이 글은 각 칸을 읽는 순서, 특수 문자의 정확한 뜻, 실제 다음 실행 시각으로 확인한 자주 쓰는 패턴, 그리고 크론으로 표현할 수 없는 일정을 정리합니다. 다음 실행 시각은 크론 표현식 해석기로 2026년 9월 6일 21:30(KST)을 기준으로 계산했습니다.
다섯 칸을 읽는 순서
| 칸 | 의미 | 범위 | 이름 표기 | | ---- | ---- | ------------- | ------------------ | | 1 | 분 | 0~59 | | | 2 | 시 | 0~23 | | | 3 | 일 | 1~31 | | | 4 | 월 | 1~12 | JAN~DEC | | 5 | 요일 | 0~7 (0과 7은 일요일) | SUN~SAT |
왼쪽부터 "분, 시, 일, 월, 요일"이고 각 칸은 공백으로 나뉩니다. 읽을 때는 오른쪽에서 왼쪽으로 읽는 것이 자연스럽습니다. 30 18 * * 1-5는 "월~금요일에, 매월, 매일, 18시, 30분"이므로 평일 18:30입니다. 요일 이름을 쓰면 0 12 * * SAT처럼 읽기 쉬워지고 해석기도 같은 결과(토요일 12:00)를 냅니다. 필드가 넷이거나 여섯이면 표준 크론이 아니며, 해석기는 "5개 필드여야 합니다. 현재 4개입니다"처럼 개수를 알려 줍니다. 범위를 벗어난 값(60 * * * *, 0 25 * * *)도 어느 칸이 어느 범위를 넘었는지 짚어 주므로 오타를 빨리 찾을 수 있습니다.
특수 문자의 정확한 뜻
*: 그 칸의 모든 값. 분 칸에 쓰면 매분입니다.,: 목록.0 9,18 * * *는 매일 09:00과 18:00 두 번입니다.-: 범위.9-18은 9시부터 18시까지 열 시간 모두를 뜻하므로, 18:00에도 실행됩니다. 업무시간을 18시 전까지로 잡으려면9-17입니다./: 간격.*/15는 0, 15, 30, 45분이고,9-18/3처럼 범위와 합치면 9, 12, 15, 18시입니다. 간격은 칸의 최솟값부터 시작하지 실행 시작 시점부터가 아닙니다.L,W,#,?: 표준 크론에는 없습니다.0 0 L * *(말일)를 넣으면 해석기가 "일 필드 L을 해석할 수 없습니다"라고 거부하는데, 이것은 도구의 한계가 아니라 리눅스 crontab이 실제로 거부하는 문법이기 때문입니다. Quartz(자바)나 일부 클라우드 스케줄러만 지원합니다.
자주 쓰는 패턴과 실제 다음 실행
| 용도 | 표현식 | 해석 | 다음 실행 (2026-09-06 21:30 기준) |
| --------------------------- | --------------------- | ------------------------- | ---------------------------------------------- |
| 헬스체크 | */5 * * * * | 5분마다 | 9/6 21:35, 21:40, 21:45 |
| 매시 집계 | 0 * * * * | 매시 정각 | 9/6 22:00, 23:00, 9/7 00:00 |
| 새벽 백업 | 0 3 * * * | 매일 03:00 | 9/7 03:00, 9/8 03:00, 9/9 03:00 |
| 출근 전 리포트 | 0 9 * * * | 매일 09:00 | 9/7 09:00, 9/8 09:00, 9/9 09:00 |
| 퇴근 전 알림 | 30 18 * * 1-5 | 평일 18:30 | 9/7 18:30, 9/8 18:30, 9/9 18:30 |
| 업무시간 15분 폴링 | */15 9-18 * * 1-5 | 평일 09:00~18:45, 하루 40회 | 9/7 09:00, 09:15, 09:30 |
| 주간 정리 | 0 0 * * 0 | 일요일 00:00 | 9/13, 9/20, 9/27 |
| 주말 배치 | 0 0 * * 6,0 | 토·일 00:00 | 9/12, 9/13, 9/19 |
| 월초 정산 | 0 0 1 * * | 매월 1일 00:00 | 10/1, 11/1, 12/1 |
| 격주 급여일 | 0 0 1,15 * * | 1일과 15일 | 9/15, 10/1, 10/15 |
| 연간 갱신 | 0 9 1 1 * | 1월 1일 09:00 | 2027/1/1, 2028/1/1, 2029/1/1 |
일요일은 0으로도 7로도 쓸 수 있지만 6,0 대신 6-7로 쓰면 구현마다 해석이 갈리므로 목록 표기가 안전합니다. 월요일 자정 작업 0 0 * * 1은 실무에서 "주말 동안 쌓인 것을 처리"하는 용도로 많이 쓰이는데, 주말이 없는 새벽 시간대라 같은 서버의 다른 배치와 겹치기 쉬우니 분 칸을 5나 17처럼 어긋나게 두는 습관이 도움이 됩니다.
날짜 칸이 만드는 함정
31일 지정 0 0 31 * *은 31일이 있는 달에만 실행되어 다음 실행이 10/31, 12/31, 다음 해 1/31로 건너뜁니다. 9월, 11월, 2월, 4월, 6월에는 아예 돌지 않습니다. 2월 29일 0 0 29 2 *은 2028년 2월 29일이 다음 실행이고 그 뒤로 4년에 한 번입니다. "매월 말일"을 원한다면 0 0 28-31 * *로 걸고 스크립트 첫 줄에서 내일이 1일인지 확인하는 것이 관례입니다.
일 칸의 간격 0 0 */2 * *은 1일부터 2일 간격이라 홀수 날에 실행됩니다. 30일까지 있는 달은 29일 다음이 다음 달 1일로 이틀 간격이 지켜지지만, 31일이 있는 달은 31일과 1일에 연달아 돕니다. 정확히 48시간마다 도는 작업은 크론으로 표현할 수 없고, 마지막 실행 시각을 파일이나 DB에 남겨 스크립트가 스스로 건너뛰게 해야 합니다. 분 칸의 */7도 같은 종류의 문제로, 56분 다음이 0분이라 4분 간격이 한 번 생깁니다.
일과 요일을 둘 다 쓰면 OR
일 칸과 요일 칸이 모두 *가 아니면 표준 크론은 둘 중 하나라도 맞으면 실행합니다. 0 0 13 * 5는 "13일의 금요일"이 아니라 매월 13일과 매주 금요일이라, 해석기의 다음 실행이 9/11(금), 9/13(일요일이지만 13일), 9/18(금)으로 나옵니다. 이 규칙은 1970년대 유닉스 크론부터 이어진 것이라 바꿀 수 없고, "매월 첫째 월요일" 같은 일정은 0 0 1-7 * 1로 걸어 두고 스크립트가 요일을 다시 확인하는 식으로 풉니다. 해석기의 한 줄 설명은 요일 쪽만 보여 주므로, 두 칸을 함께 쓴 표현식은 설명보다 다음 실행 목록을 믿어야 합니다.
UTC 서버에서 한국 시각 맞추기
클라우드 서버와 GitHub Actions는 UTC가 기본이라 0 9 * * *가 한국 시각 18:00에 돕니다. 한국 09:00은 UTC로 전날이 아닌 같은 날 00:00이므로 0 0 * * *이고, 한국 03:00은 전날 UTC 18:00이라 0 18 * * *입니다. 요일이 붙으면 요일도 하루 당겨야 해서 한국 월요일 03:00은 0 18 * * 0(UTC 일요일)이 됩니다. 한국 매월 1일 00:00은 UTC로 전달 말일 15:00이라 표현할 수 없고, 09:00 이후로 옮기거나 서버 시간대를 KST로 두어야 합니다. GitHub Actions는 여기에 더해 예약 시각보다 몇 분에서 수십 분 늦게 시작할 수 있고 정각(0분)에 몰린 작업은 더 밀리므로, 분 칸을 17이나 43처럼 어긋나게 두는 것이 공식 권고입니다.
crontab에 넣을 때 자주 틀리는 것
표현식이 맞아도 실행이 안 되는 원인은 대개 환경입니다. crontab은 로그인 셸의 설정 파일을 읽지 않아 PATH가 극히 짧고 홈 디렉터리의 별칭이나 nvm으로 설치한 node를 찾지 못하므로, 명령은 절대 경로로 쓰거나 crontab 맨 위에 PATH를 직접 선언합니다. 표준 출력과 오류는 기본적으로 메일로 가거나 버려지므로 >> /var/log/job.log 2>&1처럼 파일로 남겨야 실패를 알 수 있습니다. 퍼센트 기호는 crontab에서 줄바꿈으로 해석되어 date +%Y가 깨지니 \%로 이스케이프하고, 스크립트에 실행 권한이 있는지, 마지막 줄이 줄바꿈으로 끝나는지도 확인합니다. 편집은 파일을 직접 고치지 말고 crontab -e로 해야 문법 검사와 반영이 함께 이루어집니다.
크론이 못 하는 것
초 단위, "90분마다"처럼 60의 약수가 아닌 간격, 말일과 마지막 금요일, 공휴일 제외, 한 번만 실행, 이전 실행이 끝난 뒤 n분 후 같은 일정은 표준 다섯 칸으로 쓸 수 없습니다. 90분은 0 0,3,6,9,12,15,18,21 * * *와 30 1,4,7,10,13,16,19,22 * * * 두 줄로 나누면 되지만, 그 밖의 것은 애플리케이션 스케줄러(Quartz, node-cron의 6칸 확장, systemd 타이머의 OnCalendar)나 스크립트 안의 조건문으로 해결합니다. 동시에 두 번 도는 것을 막는 잠금(flock, 분산 락)도 크론이 아니라 스크립트의 책임입니다.
함께 확인하면 좋은 것
표현식을 넣어 한국어 설명과 다음 실행 시각 다섯 개를 확인하려면 크론 표현식 해석기를 쓰세요. 로그에 찍힌 실행 시각을 한국 시각으로 바꿔 예약 시각과 대조할 때는 타임스탬프 변환기가, 다른 나라 서버의 현재 시각은 세계 시계가 도움이 됩니다.
이 글에서 다룬 도구
더 읽을 글
- 2026년 4대보험 요율 총정리
국민연금 9.5%, 건강보험 7.19%, 장기요양 13.14%, 고용보험 1.8%. 근로자·사업주 부담과 월 보수별 보험료, 국민연금 인상 로드맵을 정리했습니다.
- 2026년 연봉 실수령액표
연봉 2,000만 원부터 1억 원까지 500만 원 단위로 월 실수령액과 공제율을 정리했습니다. 부양가족·비과세·퇴직금 포함 여부에 따른 차이도 함께 봅니다.
- 2026년 최저임금 월급·주휴수당 계산법
시급 10,320원, 월 2,156,880원. 209시간의 정체, 주 근로시간별 알바 주급·월급, 야간·연장 가산, 수습 감액 조건과 위반 대응을 정리했습니다.
- 퇴직금 지급 조건과 평균임금 계산 방법
1년 이상·주 15시간 이상이면 아르바이트도 받습니다. 평균임금에 들어가는 것과 빠지는 것, 상여금 3/12, 통상임금 보장, DB·DC형 차이, 지급 기한을 정리했습니다.