</>DevTools

CRNCron 표현식 해석기

Cron 표현식 해석 및 설명

Every 5 minutes
*/5
Minute
*
Hour
*
Day (month)
*
Month
*
Day (week)

Presets

크론 표현식 읽고 쓰기: 필드 구조부터 타임존 함정까지

크론 표현식은 다섯 개(또는 여섯 개) 필드로 반복 일정을 적는 형식입니다. 형식 자체는 단순하지만, 표현식이 틀렸을 때 나타나는 증상이 '아무 일도 일어나지 않음'이거나 '의도보다 훨씬 자주 실행됨'이어서 배포 후에야 발견되는 일이 많습니다. 이 도구는 표현식을 사람이 읽을 수 있는 문장으로 바꿔 그 오해를 미리 잡아 줍니다.

필드 구조

Quartz(Java)나 AWS EventBridge처럼 초 필드나 연 필드를 추가로 쓰는 구현도 있습니다. 6필드 표현식을 5필드 크론에 넣으면 필드가 한 칸씩 밀려 전혀 다른 일정이 되므로, 쓰는 곳의 규격을 먼저 확인해야 합니다.

표준 5필드 크론
┌───────────── 분 (0-59)
│ ┌─────────── 시 (0-23)
│ │ ┌───────── 일 (1-31)
│ │ │ ┌─────── 월 (1-12 또는 JAN-DEC)
│ │ │ │ ┌───── 요일 (0-6 또는 SUN-SAT, 0=일요일)
│ │ │ │ │
* * * * *

특수 문자

기호의미
*모든 값* * * * * → 매 분
,값 목록0 9,18 * * * → 매일 9시와 18시
-범위0 9-18 * * * → 9시부터 18시까지 매시
/간격(step)*/15 * * * * → 15분마다
범위+간격범위 안에서 간격0 9-18/2 * * * → 9,11,13,15,17시
L마지막 (일부 구현)0 0 L * * → 매월 마지막 날
W가장 가까운 평일 (일부 구현)0 0 15W * * → 15일에 가장 가까운 평일
#n번째 요일 (일부 구현)0 0 * * 1#2 → 둘째 주 월요일

사용 방법

  1. 크론 표현식을 입력하면 사람이 읽을 수 있는 설명이 표시됩니다.
  2. 설명을 읽고 의도한 주기와 같은지 확인합니다. 특히 '매 분'이나 '매시 0분마다'로 해석되는지 주의해서 보세요.
  3. 여러 후보 표현식을 번갈아 넣어 비교하면 원하는 형태를 빠르게 찾을 수 있습니다.
  4. 확정한 표현식을 crontab이나 CI 설정 파일에 옮깁니다.

자주 쓰는 표현식

표현식의미
*/5 * * * *5분마다
0 * * * *매시 정각
0 */2 * * *2시간마다 정각
0 3 * * *매일 새벽 3시
30 2 * * 1-5평일 새벽 2시 30분
0 0 * * 0매주 일요일 자정
0 0 1 * *매월 1일 자정
0 0 1 1 *매년 1월 1일 자정
0 9 * * 1매주 월요일 오전 9시
*/30 9-18 * * 1-5평일 9시~18시 사이 30분마다

일과 요일을 함께 쓰면 OR가 된다

가장 많이 오해하는 규칙입니다. 일(3번째) 필드와 요일(5번째) 필드에 모두 * 이 아닌 값을 넣으면, 표준 크론은 두 조건을 AND가 아니라 OR로 해석합니다. 즉 0 0 13 * 5 는 '13일이면서 금요일'이 아니라 '13일이거나 금요일'이므로, 매월 13일과 매주 금요일 모두 실행됩니다.

'13일의 금요일에만 실행'을 크론 표현식 하나로 쓰는 것은 표준 문법으로는 불가능합니다. 실무에서는 매일 실행하는 크론을 두고, 스크립트 안에서 날짜 조건을 확인해 조기 종료하는 방식을 씁니다. 이 방법은 조건이 복잡해질 때도 확장하기 쉽습니다.

타임존과 서머타임

크론은 실행되는 환경의 시간대를 따릅니다. 컨테이너 이미지 대부분이 UTC를 기본으로 하므로, 로컬에서 새벽 3시로 맞춘 배치가 운영에서는 낮 12시에 도는 일이 생깁니다. 한국 시간 기준 새벽 3시를 UTC로 표현하려면 9시간을 빼서 전날 18시(0 18 * * *)로 써야 합니다.

서머타임을 쓰는 지역에서는 더 미묘한 문제가 생깁니다. 시계를 앞으로 돌리는 날에는 존재하지 않는 시각이 생겨 그 시각의 작업이 건너뛰어지고, 뒤로 돌리는 날에는 같은 시각이 두 번 지나가 작업이 두 번 실행될 수 있습니다. 한국은 서머타임을 쓰지 않지만, 미국이나 유럽 리전에 배치를 두면 겪게 됩니다. 새벽 2~3시 구간을 피해 일정을 잡는 것이 실용적인 회피책입니다.

크론 작업을 안전하게 만들기

  • 중복 실행 방지: 이전 실행이 끝나지 않았는데 다음 주기가 오면 동시에 두 개가 돕니다. flock 같은 잠금이나 애플리케이션 레벨의 락을 두세요.
  • PATH 문제: 크론의 환경변수는 로그인 셸과 다릅니다. 명령을 절대 경로로 쓰거나 스크립트 안에서 PATH를 설정하세요. '로컬에서는 되는데 크론에서만 안 되는' 문제의 대부분이 이것입니다.
  • 출력 처리: 표준 출력이 남으면 시스템 메일로 쌓입니다. >> /var/log/job.log 2>&1 처럼 로그로 보내세요.
  • % 이스케이프: crontab에서 %는 개행으로 해석되므로, date +%Y 같은 명령은 \%로 이스케이프해야 합니다.
  • 실패 알림: 크론은 실패해도 조용합니다. 종료 코드를 확인해 알림을 보내거나, 헬스체크 서비스에 완료 신호를 보내는 방식(dead man's switch)을 두세요.
  • 멱등성: 같은 작업이 두 번 실행되어도 결과가 같도록 설계하면 재시도와 중복 실행 문제가 훨씬 단순해집니다.

자주 묻는 질문

*/7 * * * * 는 정확히 7분마다 실행되나요?
아닙니다. step은 필드 범위(0~59) 안에서 계산되므로 0, 7, 14, 21, 28, 35, 42, 49, 56분에 실행되고, 56분 다음은 다음 시간의 0분이므로 그 간격만 4분입니다. 60의 약수(5, 10, 15, 20, 30)가 아니면 시간 경계에서 간격이 어긋납니다. 정확한 간격이 필요하면 크론 대신 큐나 스케줄러의 interval 기능을 쓰세요.
요일에서 0과 7 중 무엇이 일요일인가요?
표준은 0이 일요일입니다. Vixie cron 등 다수 구현이 호환성을 위해 7도 일요일로 받아들이지만, 모든 구현이 그렇지는 않습니다. SUN, MON 같은 이름을 쓰면 모호함이 없어 안전합니다.
@daily 같은 표기는 뭔가요?
일부 크론 구현이 제공하는 축약 표기입니다. @yearly(0 0 1 1 *), @monthly(0 0 1 * *), @weekly(0 0 * * 0), @daily(0 0 * * *), @hourly(0 * * * *)가 있고, @reboot은 시스템 부팅 시 한 번 실행합니다. 읽기 쉽지만 모든 플랫폼이 지원하지는 않으니 확인이 필요합니다.
31일로 설정하면 2월에는 어떻게 되나요?
그 달에 존재하지 않는 날짜는 그냥 건너뜁니다. 0 0 31 * * 는 31일이 있는 달에만 실행되므로 2월, 4월, 6월, 9월, 11월에는 실행되지 않습니다. '매월 마지막 날'이 목적이라면 L을 지원하는 구현에서 0 0 L * * 를 쓰거나, 매일 실행하며 스크립트에서 다음 날이 1일인지 확인하는 방법을 씁니다.
서버가 꺼져 있던 동안의 작업은 나중에 실행되나요?
표준 cron은 실행하지 않고 그냥 놓칩니다. anacron이나 systemd timer의 Persistent=true 옵션은 놓친 작업을 부팅 후 실행해 주므로, 노트북처럼 항상 켜져 있지 않은 환경에서는 이쪽이 적합합니다.
초 단위 실행이 필요하면?
표준 크론의 최소 단위는 1분입니다. 더 짧은 주기가 필요하면 Quartz처럼 초 필드를 지원하는 스케줄러를 쓰거나, 1분마다 실행되는 작업 안에서 짧은 루프를 돌리거나, 애초에 크론이 아니라 상주 프로세스와 큐를 쓰는 구조를 검토하세요.

💡 참고: 표현식을 배포하기 전에 이 도구의 설명을 소리 내어 읽어 보세요. '매 분 실행'처럼 의도와 크게 다른 해석은 그 순간 바로 드러납니다.

🔗관련 도구💻 정규식/코드