
요약 — 마감과 정산처럼 달의 경계에 맞춰 반복되는 업무는 규칙이 단순하지만 실행은 자주 흔들립니다. EOMONTH와 EDATE를 표준 도구로 삼아 월말 기준일과 특정 일자를 자동 계산해 두면, 달력이 바뀌어도 스케줄이 스스로 업데이트되고 리마인더까지 함께 굴러갑니다. 이 글은 월말 오프셋과 월중 특정일 두 축을 중심으로 스케줄을 설계하고, 주말 보정과 알림일 산정까지 포함한 끝단까지의 공식을 제공합니다.
다운로드
- 샘플 작업 목록 CSV: D3_eomonth_sample_tasks.csv
- 확장 스케줄 결과 CSV: D3_eomonth_result_schedule.csv
샘플 데이터 설명
샘플은 반복 업무를 최소 단위로 정의한 작업 테이블입니다. 각 행은 주기와 마감 규칙을 담습니다. 결과 파일은 6개월 범위로 작업이 전개된 스케줄 테이블입니다.
작업 테이블 D3_eomonth_sample_tasks.csv
| 컬럼 | 의미 | 예시 | 설명 |
|---|---|---|---|
task_id |
작업 식별자 | T01 | 행 고유 키 |
task_name |
작업명 | VAT 보고서 마감 | 사내 용어 그대로 |
anchor_date |
기준 시작월 | 2025-07-01 | 이 달부터 주기 전개 |
cycle_months |
반복 주기 | 1 | 1은 매월, 3은 분기 |
rule_type |
마감 규칙 종류 | M_END_OFFSET | 월말 기준 또는 월중 특정일 |
offset_days |
월말 기준 오프셋 | -2 | 월말 전후 일수. 월말 이틀 전은 -2 |
day_in_month |
월중 일자 | 15 | rule_type이 DAY_OF_MONTH일 때 사용 |
shift_weekend |
주말 보정 | YES | 마감일이 토일이면 전 영업일로 당김 |
lead_days_before_due |
알림 리드일 | 3 | 마감 며칠 전 알림일 산정 |
notes |
비고 | 월말 이틀 전 마감 | 설명 기록 |
스케줄 테이블 D3_eomonth_result_schedule.csv
| 컬럼 | 의미 | 예시 | 계산 개념 |
|---|---|---|---|
period_month |
대상 월의 첫날 | 2025-09-01 | anchor에서 주기만큼 EDATE |
due_date |
해당 월의 마감일 | 2025-09-28 | 월말 오프셋 또는 지정 일자, 주말 보정 포함 |
reminder_date |
알림일 | 2025-09-23 | due_date에서 리드일 차감 |
rule_type |
적용 규칙 | M_END_OFFSET | 월말 기준 |
offset_days |
오프셋 | -2 | EOMONTH 결과에 더함 |
day_in_month |
월중 일자 | 15 | 해당 일자 또는 말일로 보정 |
shift_weekend |
주말 보정 | YES | 토일이면 이전 영업일 |
설계의 핵심 사고방식
- 월 시퀀스를 먼저 만든다 — 기준월의 첫날 하나만 있으면
EDATE로 원하는 개수만큼 월을 펼칠 수 있습니다. - 마감일을 두 가지 규칙으로 통합한다 — 월말 오프셋과 월중 특정일을 하나의 수식 블록에서 분기합니다.
- 주말 보정은 마지막에 한 번 — 보정 전 날짜가 확정된 다음에만
WORKDAY.INTL로 전 영업일 보정을 적용합니다. - 알림일은 마감일의 파생값 — 마감일에서 리드일만큼 뺀 값을 별도 열로 둡니다.
Excel 365 공식
기준월의 첫날이 B2라면 6개월 시퀀스는 다음처럼 만듭니다.
=EDATE(EOMONTH($B$2,-1)+1, SEQUENCE(6,1,0,1))
스케줄 표에서 행별로 마감일을 계산하는 일반형입니다. 표 구조 참조를 사용합니다.
=LET(
p, [@period_month],
rule, [@rule_type],
off, [@offset_days],
dim, [@day_in_month],
base, IF(rule="M_END_OFFSET",
EOMONTH(p,0)+off,
MIN(DATE(YEAR(p),MONTH(p),dim), EOMONTH(p,0))
),
adj, IF(AND([@shift_weekend]="YES", WEEKDAY(base,2)>5),
WORKDAY.INTL(base,-1),
base
),
adj
)
알림일은 아주 간단합니다.
=[@due_date] - [@lead_days_before_due]
Google Sheets 공식
기준월의 첫날이 B2라면 다음으로 6개월 시퀀스를 만듭니다.
=EDATE(EOMONTH($B$2,-1)+1, SEQUENCE(6))
행별 마감일 일반형입니다. 참조 열 주소만 시트에 맞게 조정하십시오.
=LET(
p, C2,
rule, D2,
off, E2,
dim, F2,
base, IF(rule="M_END_OFFSET",
EOMONTH(p,0)+off,
MIN(DATE(YEAR(p),MONTH(p),dim), EOMONTH(p,0))
),
adj, IF(AND(G2="YES", WEEKDAY(base,2)>5), WORKDAY.INTL(base,-1), base),
adj
)
알림일은 다음과 같습니다.
=H2 - I2
규칙 검증 체크리스트
-- 분기 작업이 매 3번째 달에만 나타나는지
=COUNTIF(FILTER(스케줄[task_id], 스케줄[task_id]="T05"), "T05") = 2 -- 6개월 전개라면 2번
-- 월말 오프셋 결과가 해당 월 범위를 벗어나지 않는지
=AND(
스케줄[due_date] >= 스케줄[period_month],
스케줄[due_date] <= EOMONTH(스케줄[period_month],0) + MAX(0, 스케줄[offset_days])
)
-- 주말 보정이 제대로 동작하는지
=COUNTIF(스케줄[due_date], "=토" ) + COUNTIF(스케줄[due_date], "=일") = 0 -- 요일 표시 형식에서 확인
실무 팁과 주의점
- DAY_OF_MONTH는 말일을 넘지 않게 — 31일 같은 값이 짧은 달에서 문제를 일으키지 않도록
MIN(DATE(...), EOMONTH(...))로 안전장치를 넣으세요. - 주말 보정 방향을 정책으로 고정 — 본문은 이전 영업일로 당기는 방식을 썼습니다. 조직에 따라 다음 영업일로 미는 방식이라면
WORKDAY.INTL(base,1)로 바꾸면 됩니다. - 휴일 달력과 결합 — 법정 공휴일까지 고려하려면
WORKDAY.INTL의 네 번째 인자로 휴일 범위를 넘기면 됩니다. - 리드일은 숫자 열로 유지 — 알림일 수식이 텍스트에 걸리지 않도록 반드시 숫자 열로 관리합니다.
재현 가이드
- 작업 테이블 CSV를 불러오고 표 이름을 Tasks로 지정합니다.
- 첫 행의
anchor_date를 기준으로 기준월 첫날을 구해 옆 열에 배치합니다.=EOMONTH([@anchor_date],-1)+1 - 시퀀스 열을 만들어 6개월을 펼치고,
cycle_months에 맞지 않는 달은 숨기거나 필터링합니다. rule_type분기에 따라 마감일을 계산하고, 필요하면 주말 보정과 알림일을 추가합니다.
마무리
마감 규칙은 두 가지뿐입니다. 월말 기준 오프셋과 월중 지정일. EOMONTH는 말일을 정확하게 잡아 주고, EDATE는 달을 흔들림 없이 이동시킵니다. 이 두 축을 중심으로 수식을 모듈화하면 스케줄은 사람이 아닌 규칙이 운영하게 됩니다. 위 CSV를 내려받아 본문 공식을 그대로 적용해 보십시오. 기준월만 바뀌어도 리포트 달력 전체가 자동으로 따라오는 경험을 바로 얻을 수 있습니다.