Cron 표현식 파서 & 빌더

5필드 cron 표현식을 검증하고 다음 N회의 실행 시각을 미리 봅니다. 또는 빈도 선택기(분/시/일/주/월/년)로 표현식을 만들 수 있습니다.

Loading…

모든 처리는 브라우저 내부에서 실행됩니다 — 파일·입력은 서버로 전송되지 않습니다.

5개 필드와 유효 범위

고전 cron 표현식은 공백으로 구분된 5개 필드입니다. 순서는 분·시· 일·월·요일이며 왼쪽에서 오른쪽으로 갈수록 세밀한 단위에서 큰 단위로 가다가 마지막 요일만 월 오른쪽에 자리합니다. 각 필드는 범위·리스트·별표를 받아들입니다. 아래 표가 유효 범위입니다.

#필드범위이름형
10–59
20–23
3일(DOM)1–31
41–12JAN–DEC
5요일(DOW)0–6SUN–SAT

고전 방언에서 인식되는 연산자

연산자의미
*해당 필드의 모든 유효값.* * * * * → every minute
,값의 리스트.0 9,12,18 * * * → 09:00, 12:00, 18:00 daily
-양끝 포함 범위.0 9 * * 1-5 → 09:00 Mon–Fri
/스텝. */n은 n마다. a-b/n은 범위 a-b 안에서 n마다.*/15 * * * * → :00, :15, :30, :45 every hour
name월·요일의 3글자 별칭(대·소문자 구분 없음).0 0 * JAN MON → midnight every Monday in January

실무에서 자주 쓰는 패턴

실무에서 작성하게 되는 cron 작업 대부분은 몇 가지 형태로 수렴합니다. 아래 중 하나를 복사해 조정하는 게 빠릅니다.

*/5 * * * *5분마다.
0 * * * *매시 정각.
0 3 * * *매일 03:00 — 백업의 단골 시각.
0 9 * * MON매주 월요일 09:00 — 주간 회의 알림.
0 18 * * 1-5평일 18:00 — 업무 종료 시점의 정리 작업.
0 0 1 * *매월 1일 00:00 — 청구 배치.
15 2 * * 0매주 일요일 02:15 — 트래픽이 적은 시간대의 무거운 배치.
0 0 1 1 *1월 1일 00:00 — 연간 리셋.
*/10 9-17 * * 1-5평일 9~17시에 10분마다.

cron 방언 — 어디서 규칙이 갈리는가

"cron"은 단일 사양이 아닙니다. POSIX는 위의 5필드 구문을 정의합니다. Vixie cron(BSD 계열에서 출발해 Linux의 사실상 표준이 된 구현)은 요일 이름·@reboot / @daily / @hourly 단축·DOM과 DOW를 둘 다 제한했을 때의 "암묵적 OR"을 추가합니다. 이 분기점은 누구든 처음 마주칠 때 놀라게 됩니다. Quartz(Spring·Hangfire·Quartz.NET이 채택한 Java 스케줄러)는 초 필드를 맨 앞에, 선택적 연도 필드를 맨 뒤에 두고 ? L W #를 "미지정·월말·가장 가까운 평일·n번째 요일"로 추가합니다. 0 15 10 ? * MON-FRI는 Quartz에서는 유효 하지만 POSIX에서는 잘못된 식입니다.

systemd 타이머는 cron 식을 폐기하고 자체 OnCalendar 구문 (예: Mon..Fri 18:00)을 사용합니다. AWS EventBridge는 Quartz에 가까운 6필드 형식(초 없음·연도 있음)을 씁니다. Cloudflare Workers의 cron 트리거는 고전 5필드 POSIX 방언을 UTC로 해석합니다. 서로 다른 시스템 간에 식을 복사·붙여 넣을 때는 양쪽이 어느 방언을 쓰는지 반드시 확인하세요. 위 도구는 POSIX 5필드를 채택 하며 DOM과 DOW는 AND로 처리합니다.

발등을 찍는 함정 3가지

첫째, 시간대입니다. crond를 비롯한 다수의 스케줄러는 cron 식을 서버 로컬 타임으로 해석하므로 일광 절약 시간 전환에서 연 2회 조용히 깨지고, 데이터센터 간 실행 일정이 어긋납니다. 클라우드 스케줄러(Cloudflare Workers·GitHub Actions·AWS EventBridge)는 UTC를 기본으로 합니다. 어느 쪽 영역을 쓸지 먼저 명시적으로 정한 뒤 식을 작성하세요. 시스템이 본인과 같은 전제로 동작하리라 가정하지 않습니다.

둘째, DOM과 DOW의 함정입니다. Vixie cron에서 0 0 1 * MON은 매월 1일 00:00과 매주 월요일 00:00의 합집합으로 실행되어, 의도한 빈도의 약 6배가 됩니다. POSIX와 이 도구에서는 두 조건을 동시에 만족하는 경우(1일에 떨어지는 월요일, 연 1회 정도)에만 실행됩니다. "둘 중 하나라도"가 필요하다면 모호한 1행이 아니라 2행으로 나눠 쓰세요.

셋째, "5분마다"는 */5가 항상 의미하는 것이 아닙니다. 시 필드의 */5는 0시부터 5씩 진행해 0·5·10·15·20이 되며 4·9·14·19가 되지 않습니다. 오프셋이 필요하면 명시적 리스트를 쓰거나 범위를 옮겨 4-23/5로 적습니다. 슬래시는 항상 범위의 하한을 기점으로 하며 현재 시각이 아닙니다.

사용법

**Parser** 탭에 5필드 cron 표현식을 붙여 넣으면 각 필드 — 분(0–59), 시(0–23), 일(1–31), 월(1–12 또는 `JAN-DEC`), 요일(0–6 또는 `SUN-SAT`, 일요일이 0) — 을 검증하고 다음 N회의 실행 시각을 출력합니다. 지원 구문: `*`(모두), 범위 `a-b`, 리스트 `a,b,c`, 스텝 `*/n`과 `a-b/n`, 대소문자 무시 월·요일 이름. 일과 요일을 모두 제한했을 때 본 파서는 Vixie cron의 OR가 아닌 **AND**(POSIX 동작)를 채택합니다. 트레이드오프는 FAQ를 참고하세요.

**Builder** 탭에서는 빈도 선택기로 표현식을 조립할 수 있습니다. *매분·매시·매일·매주·매월·매년*을 고르고 조건을 좁히면 됩니다. 예를 들어 "15분마다, 평일만, 09:00–17:00"은 `*/15 9-17 * * 1-5`를 생성합니다. 다음 실행 미리보기는 호스트 브라우저의 로컬 타임존을 사용하므로 같은 타임존의 서버에서 `/etc/crontab`이 동작하는 결과와 일치합니다. 운영 cron이 UTC로 동작한다면 배포 전에 오프셋을 머릿속으로 조정하세요. 파서는 자체 완결적이며 — 네트워크 요청이나 외부 cron 라이브러리 없음 — 표현식과 기기의 벽시계 시각은 페이지 밖으로 나가지 않습니다.

예제

매시 정각 유지보수 훅

입력
expression:  0 * * * *
starting:    Mon 2026-05-18 14:00 local time
preview:     next 5 runs
출력
Mon 2026-05-18 15:00
Mon 2026-05-18 16:00
Mon 2026-05-18 17:00
Mon 2026-05-18 18:00
Mon 2026-05-18 19:00

`0 * * * *`는 "매시 정각"의 표준 표현입니다 — 분을 0으로 고정하고 다른 필드는 모두 `*`입니다. 흔한 실수는 "매시" 의도로 `* * * * *`를 쓰는 것으로, 실제로는 매분 실행됩니다(60배 잦음). 진짜 매시 실행을 원한다면 분 필드를 고정하세요. 1시간보다 짧은 주기에는 `*/15`나 `0,15,30,45`를 씁니다. 정각 정렬 일정에서는 둘이 동등하지만 Vixie cron에서는 `0,15,30,45`가 HUP·재시작 타이밍을 가로질러 정확하게 남고, `*/15`는 crontab 파싱 시점에 한 번만 읽힙니다.

평일 영업시간 폴링

입력
expression:  */15 9-17 * * 1-5
interpret:   every 15 minutes, 09:00–17:45, Monday–Friday
preview:     next 4 runs after Fri 2026-05-15 17:45
출력
Mon 2026-05-18 09:00
Mon 2026-05-18 09:15
Mon 2026-05-18 09:30
Mon 2026-05-18 09:45

# Note: 17:00–17:45 inclusive on Friday, then the cron sleeps the entire
# weekend and resumes Monday 09:00. The 4× /hour cadence × 9 active hours
# × 5 weekdays = 180 fires per week.

영업시간 헬스체크의 전형적인 예입니다. 시간 범위 `9-17`은 *양 끝을 포함*하므로 17:45도 실행됩니다. 요일 `1-5`는 월요일부터 금요일을 의미합니다(일요일=0, 토요일=6). `*/15 9-17`의 조합은 시간당 4회 × 9시간 = 평일 1일 36회, 주 180회입니다. 야간 유휴 전에 18:00 정각에 마지막 실행이 필요하다면 OR로 추가합니다. `0,15,30,45 9-17 * * 1-5`로 바꾸고 `0 18 * * 1-5`를 별도 줄로 추가하세요. 하나의 표현식으로 서로 다른 시 패턴을 OR로 묶을 수는 없습니다.

월말 보고서 — 일/요일 함정

입력
expression:  0 9 28-31 * 1
interpret:   POSIX (AND) — only when the 28th-31st is also a Monday
             Vixie (OR) — every day 28-31 OR every Monday
출력
POSIX behavior (this parser):
  Mon 2026-12-28 09:00     # 28th is a Monday
  Mon 2027-03-29 09:00     # next 28-31 + Monday match
  ...

Vixie crond behavior (most Linux distros):
  Every day 28-31 of any month
  PLUS every Monday
  ≈ 4 + 4 = 8 fires per month on average

가장 많이 언급되는 cron 함정입니다. POSIX 표준은 일과 요일이 모두 제한되면 AND(교집합)로 처리하지만, 대부분의 Linux 배포판에 포함되는 Vixie cron(`cronie` / `cron`)은 OR(합집합)로 처리합니다. 동일한 표현식이 로컬 테스트와 운영 서버에서 5배 잦게 실행될 수 있습니다. 두 필드를 모두 제한한 표현식은 본 파서로 한 번 점검하세요. 진짜 월말 작업이 필요하다면 `0 9 28-31 * *`처럼 요일을 `*`로 두고 작업 본체에 날짜 확인을 넣으세요. `[ "$(date -d tomorrow +%d)" = "01" ] && run.sh`는 *진짜 마지막 날*에만 실행합니다.

자주 묻는 질문

여기는 5필드인데 다른 곳에서 6필드나 7필드 표현식을 보는 이유는?

표준 Unix cron — Linux·BSD·macOS의 `/etc/crontab`이 파싱하는 형식 — 은 5필드(분·시·일·월·요일)를 사용합니다. 6필드 버전은 앞에 **초** 필드를 추가한 것으로 Quartz Scheduler(Java)와 다수의 AWS·Spring 스케줄러가 받습니다. 7필드 버전은 뒤에 **년** 필드를 추가한 Quartz 전용입니다. 앞에 초를 두는 형식은 `WithSeconds` 옵션을 켠 robfig/cron 같은 일부 Go 라이브러리도 사용합니다. 6필드 표현식을 여기에 붙이면 "필드 과다" 오류가 납니다. 초(또는 년)를 빼고 분 이후 가운데 5필드만 파싱하세요. 표준 `crond`는 어떤 방언이든 분당 1회보다 빠르게 실행할 수 없습니다.

cron은 `@daily`, `@reboot` 같은 단축 표기를 지원하나요?

Vixie cron은 7개의 별칭을 지원합니다. `@yearly` / `@annually`(= `0 0 1 1 *`), `@monthly`(= `0 0 1 * *`), `@weekly`(= `0 0 * * 0`), `@daily` / `@midnight`(= `0 0 * * *`), `@hourly`(= `0 * * * *`), `@reboot`(시스템 부팅 시 1회). 별칭은 Vixie 확장이며 POSIX에는 없으므로 일부 Docker 베이스 이미지에 들어 있는 최소 busybox-cron에서는 동작하지 않을 수 있습니다. 본 파서는 별칭을 받지 **않습니다**. 펼친 5필드 형식으로 붙여 넣으세요. `@reboot`은 등가 표현식이 없으며 시간 트리거가 아닌 이벤트 트리거(부팅)입니다. 같은 "부팅 시 1회" 의미는 `OnBootSec`을 사용하는 systemd timer가 현대적 대안입니다.

이 파서는 어떤 타임존을 사용하나요? 운영 cron은 UTC로 동작합니다.

다음 실행 미리보기는 브라우저의 로컬 타임존(`Intl.DateTimeFormat().resolvedOptions().timeZone`에서 가져옴)을 사용합니다. 서버가 UTC로 동작하고 브라우저가 JST나 KST라면 미리보기는 실제 서버 실행보다 9시간 뒤를 표시합니다. 대부분의 현대 cron은 환경 변수 `CRON_TZ=...`이나 `TZ=...`을 인식합니다. `/etc/crontab`에서 줄별 또는 전체로 설정할 수 있습니다. systemd timer에서는 `OnCalendar=` 지시자가 `OnCalendar=Mon..Fri 09:00 Asia/Tokyo`처럼 명시적 타임존을 받습니다. 일광 절약 시간(DST)이 문제를 더 어렵게 합니다. DST를 채택하는 지역에서 로컬 02:30로 예약된 작업은 봄철 시계 전진일에는 건너뛰고 가을철 시계 복귀일에는 2회 실행됩니다(소박한 cron 기준). 운영 작업을 UTC로 돌리는 것이 표준 권장인 이유입니다.

`*/5`는 `0/5`나 `0,5,10,15,...`과 어떻게 다른가요?

분 필드에서는 세 형식 모두 POSIX/Vixie cron에서 동등합니다. 0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55분에 실행됩니다. 차이는 시작점이 0이 아니거나 비표준 범위에서 나타납니다. `5/15`(Quartz)는 "5에서 시작해 15마다" → 5, 20, 35, 50을 의미하며 `*/15`는 이걸 *생성하지 않습니다*. `1-30/5`는 "1–30 사이에서 5분마다" → 1, 6, 11, 16, 21, 26입니다. POSIX/Vixie cron은 `a-b/n` 형식을 지원하지만 `a/n`(시작 + 스텝) 형식은 지원하지 않습니다. 그것은 Quartz 확장입니다. 의심스러우면 명시적 리스트 `0,5,10,...`로 펼쳐 최대 이식성을 확보하세요. 분을 건너뛰고 싶을 때도 리스트가 유용합니다 — `0,3,6,9`는 불규칙 간격으로 시간당 4회 실행됩니다.

Linux의 cron이 파서 예측과 다른 날에 실행되는 이유는?

거의 확실히 예시 3에서 다룬 DOM/DOW 불일치입니다. 본 파서는 POSIX 표준(AND)을 따르지만 대부분의 Linux 배포판에 포함된 cron 데몬은 Vixie 관습(OR)을 따릅니다. 서버에서 확인하려면 `man 5 crontab`을 실행하고 "day-of-week"를 검색하세요. 매뉴얼 페이지에 로컬 동작이 명시되어 있습니다. 다른 원인 가능성: 편집 환경과 서버의 타임존 불일치(위 UTC FAQ 참고), `cron`이 실행 중이 아님(`systemctl status cron`), 메일이 설정되지 않아 `MAILTO=`가 조용히 실패, 사용자의 `PATH`에 `/usr/local/bin`이 없어 스크립트의 셔뱅은 해결되지만 첫 명령이 실패 등. 표현식 의미를 디버그하기 전에 먼저 `* * * * * date >> /tmp/cron.log`를 테스트 crontab에 추가해 cron 자체가 동작하는지 확인하세요.

cron 대 systemd timer 대 Kubernetes CronJob은 어떻게 선택하나요?

**cron**은 `/etc/crontab`과 가동시간을 직접 관리하는 단일 Linux 호스트에서 셸 스크립트 스타일의 자동화(로그 회전, 백업, 단순 폴링, 취미 프로젝트)에 적합합니다. **systemd timer**는 이미 서비스를 systemd로 관리 중이고 `journalctl`로 통합 로깅, 의존 순서(`network-online.target` *이후*), 동시 실행을 피하기 위한 랜덤 지연, 재부팅을 가로지른 미실행 작업의 영속화(`Persistent=true`)가 필요할 때 씁니다. **Kubernetes CronJob**은 워크로드가 클러스터에서 동작할 때 — Pod 단위 리소스 격리, 자동 재시작·재시도, 평소의 k8s 도구를 통한 가시성이 장점이지만 작은 작업에도 10~30초의 콜드 스타트 지연이 비용입니다. 클러스터 없이 클라우드 네이티브한 단발 작업에는 **AWS EventBridge Scheduler**, **Cloud Scheduler**, **Azure Logic Apps** 모두 cron 형식 표현식을 받으며 작업이 유휴인 동안에는 컴퓨팅을 돌리지 않아도 됩니다.

관련 개념

cron은 AT&T 벨 연구소에서 7판 Unix(1979년)의 일부로 탄생했으며 Brian Kernighan이 작성한 것으로 전해집니다. 원조는 `/usr/lib/crontab`을 분당 1회 스캔해 일치하는 항목을 exec하는 데몬이었습니다. **Paul Vixie의 재작성**(1987년)이 사용자별 crontab, 월·요일 명명 별칭, `@daily` / `@reboot` 닉네임, 그리고 다음 해 발표된 POSIX 표준에서 어긋난 **DOM + DOW의 OR 의미**를 도입했습니다. Vixie cron은 Linux와 BSD의 사실상 표준이 되었으며 현대 파생으로 `cronie`(Red Hat / Fedora), `bcron`(Debian), `dcron`(Alpine, Slackware)이 있습니다. POSIX 엄격 구현은 주로 상용 Unix와 임베디드 busybox-cron에 있습니다. DOM/DOW 불일치는 가장 많이 인용되는 cron 함정이며 POSIX 자체보다 7년 정도 앞섭니다.

**형식 자체에도 방언**이 필드 수를 넘어 존재합니다. `JAN-DEC`과 `SUN-SAT` 별칭은 Vixie 확장으로 POSIX에는 없고, Quartz Scheduler는 초 필드, 연도 필드, 특수 문자 `L`(마지막), `W`(평일), `#`(월의 N번째 요일), `?`(DOM/DOW에 값 미지정)을 추가합니다. AWS EventBridge는 Quartz 의미를 따르면서 `?` 요구사항을 추가합니다. Spring의 `@Scheduled`는 또 다른 변형입니다. cron 표현식을 시스템 간 복사할 때는 필드 수, DOM/DOW 의미, 명명 별칭 지원 여부를 확인하세요. 한 시스템에서 동작하는 표현식이 다른 시스템에서는 조용히 오작동하거나 파싱을 거부할 수 있습니다.

세 가지 **현대 대안**이 서로 다른 영역에서 cron의 자리를 잠식하고 있습니다. **systemd timer**는 systemd로 관리되는 Linux 서버(2015년 이후 대부분의 배포판)에서 cron을 대체합니다. unit 시스템과 통합되고 journald로 로깅하며 무작위화와 영속화를 지원하고 더 읽기 쉬운 `OnCalendar=Mon..Fri 09:00` 구문을 받습니다. **Kubernetes CronJob**은 컨테이너화된 워크로드에 Pod 격리와 재시도 정책을 갖춘 cron 의미를 가져옵니다. **클라우드 매니지드 스케줄러**(AWS EventBridge Scheduler, Google Cloud Scheduler, Azure Logic Apps Scheduler)는 cron 표현식을 받으면서 매니지드 인프라에서 실행되어 상시 가동 호스트를 없앱니다. 애플리케이션 내부 작업 스케줄링에는 Java의 Quartz, Python의 APScheduler, Go의 robfig/cron, Node의 node-cron 같은 라이브러리가 cron 의미를 직접 내장합니다. 이런 대안이 있어도 소박한 crontab은 모든 Unix 계열 머신에서 계속 살아 있습니다. 작은 표면적과 `/etc/crontab`의 단순함이 대부분의 대체재보다 오래 살아남게 할 것입니다.

관련 글

관련 도구