잔업수당 계산법 완전 정리 — 시급 150% 원리부터 PWA 계산기 만들기까지

잔업수당은 어떻게 계산할까? 시급(기본급÷209시간)의 150%가 기본 구조입니다. 이 글에서는 계산 원리와 실제 예시, 그리고 기본급만 넣으면 월별·연간 정산이 자동으로 되는 PWA 계산기를 직접 만드는 방법까지 정리합니다.

매달 급여명세서를 받을 때마다 "이번 달 잔업수당이 제대로 계산된 건가?"라는 의문이 듭니다. 급여명세서에는 최종 금액만 적혀 있을 뿐, 이 숫자가 어떤 기준으로 나왔는지는 알 수 없습니다. 이 글에서는 ① 잔업수당의 계산 원리를 이해하고, ② 실제 숫자로 직접 계산해 보고, ③ 매일 잔업시간만 기록하면 월별·연간 정산을 자동으로 해주는 계산기(PWA)를 직접 만들어 봅니다.

1. 잔업수당 계산법 — 3줄 공식

잔업수당 계산은 생각보다 단순합니다. 세 가지만 알면 됩니다.

시급     = 기본급 ÷ 209시간
잔업단가 = 시급 × 1.5
월 잔업수당 = 일별 잔업시간 합 × 잔업단가

왜 209시간인가. 한 달 소정근로시간은 주 40시간 기준 약 174시간입니다. 여기에 주휴수당에 해당하는 시간(약 35시간)을 더하면 209시간이 됩니다. 즉 "기본급 ÷ 209"는 주휴가 이미 포함된 시급을 구하는 공식입니다.

💡 포인트
왜 150%인가: 근로기준법 제56조에 따라 연장근로에는 통상임금의 50%를 가산해 지급해야 합니다. 그래서 시급의 150%가 연장근로 단가입니다.
⚠ 주의
정확한 통상임금 기준은 회사 규정에 따라 다를 수 있습니다. 이 공식은 일반적인 법정 최소 기준이며, 회사 계산과 다르다면 인사팀에 기준을 확인해 보세요.

2. 실제 숫자로 계산해 보기

기본급 250만 원, 이번 달 잔업 10시간이라고 가정합니다.

시급     = 2,500,000 ÷ 209 = 11,962원
잔업단가 = 11,962 × 1.5    = 17,943원
잔업수당 = 17,943 × 10     = 179,430원

이 계산 결과와 급여명세서의 잔업수당 항목을 대조하면 회사 계산이 맞는지 바로 확인할 수 있습니다. 매달 이걸 엑셀로 반복하는 게 번거롭다면, 다음 섹션처럼 웹앱으로 자동화할 수 있습니다.

3. PWA 계산기 직접 만들기

순수 HTML/CSS/JavaScript로 만듭니다. 서버가 필요 없고, 데이터는 브라우저에 저장됩니다.

3-1. 계산 로직

const MONTHLY_HOURS = 209; // 월 소정근로시간 (주휴 포함)
const OVERTIME_RATE = 1.5; // 연장근로 가산 50%

function calcRates(baseSalary) {
  const hourly = baseSalary / MONTHLY_HOURS;
  return { hourly, overtime: hourly * OVERTIME_RATE };
}

// 일별 잔업 기록을 받아 월 정산금액을 계산
function monthlySettlement(logs, baseSalary) {
  const { overtime } = calcRates(baseSalary);
  const totalHours = logs.reduce((sum, l) => sum + l.hours, 0);
  return { totalHours, amount: Math.round(totalHours * overtime) };
}

3-2. 날짜별 기록 — 캘린더 UI

정산의 정확성은 결국 정확한 잔업시간 기록에서 나옵니다. 그래서 계산기보다 "기록 도구"에 가깝게 설계했습니다. 달력 셀을 탭하면 30분씩 추가되고, 다시 탭하면 초기화되는 방식입니다. 모바일에서 가장 많이 쓸 것을 예상해 430px 기준 앱형 레이아웃으로 만들었습니다.

// 날짜별 잔업시간 상태. 예: { '2026-07-15': 2.5 }
const logs = JSON.parse(localStorage.getItem('overtime-logs') || '{}');

function addLog(date) {
  logs[date] = (logs[date] || 0) + 0.5;
  save();
  render();
}

function save() {
  localStorage.setItem('overtime-logs', JSON.stringify(logs));
}

3-3. 월별·연간 정산 — 한눈에 보는 표

캘린더에 기록된 잔업시간을 월별로 모아 월 정산 요약과 연간 정산 표를 자동으로 그려줍니다. 1~12월 각 행에 잔업시간·수당·총 수령액이 나오고, 하단에 연간 합계가 정리됩니다. 월마다 기본급이 다르면(승급·이직) 해당 월 값을 따로 입력할 수 있게 설계했습니다.

// 월별 잔업시간 합 → 연간 정산 표 생성
function renderAnnual() {
  let tH = 0, tOt = 0, tFin = 0;
  for (let m = 1; m <= 12; m++) {
    const hourly = getSalary(m) / 209;
    const h = getMonthHours(m);                 // 해당 월 잔업시간 합
    const ot = Math.floor(h * hourly * 1.5);
    const fin = getSalary(m) + ot;
    tH += h; tOt += ot; tFin += fin;
    // tbody에 "m월 | h | ot | fin" 행 추가
  }
  // 합계 행 갱신
}

급여명세서와 대조할 때도 유용합니다. 예를 들어 4월에 잔업 18시간이라면 표에는 18h → 322,966원으로 표시되고, 명세서의 잔업수당 항목과 바로 비교할 수 있습니다.

3-4. 데이터 보존 — LocalStorage + 백업

잔업 기록·기본급·연차 데이터는 별도 서버 없이 브라우저 LocalStorage에 저장됩니다. 리로드해도, 다음 날 다시 열어도 그대로 유지되죠. 다만 LocalStorage는 브라우저를 지우면 사라지기 때문에, 기기 변경·초기화에 대비한 백업 기능을 넣었습니다. 하단의 💾 데이터 버튼을 누르면 내보내기 / 불러오기 / 초기화 3가지가 있는 데이터 관리 화면이 열립니다.

내보내기는 잔업·연차 전체 데이터를 JSON 파일(잔업정산_데이터_20260814.json 형식)로 다운로드하고, 불러오기는 그 파일을 다시 읽어 복원합니다. 파일 형식을 검증한 뒤에만 덮어쓰도록 안전장치도 있습니다.

// 내보내기: 전체 데이터를 JSON 파일로 저장
function exportData() {
  const exportObj = {
    version: '1.0',
    exportedAt: new Date().toISOString(),
    common: { salary, joinDate, leaveUses },
    hours: hourData,
  };
  const blob = new Blob([JSON.stringify(exportObj, null, 2)],
    { type: 'application/json' });
  const a = document.createElement('a');
  a.href = URL.createObjectURL(blob);
  a.download = `잔업정산_데이터_${dateStr}.json`;
  a.click();
}

// 불러오기: 파일을 읽어 데이터 복원
function importData(e) {
  const file = e.target.files[0];
  const reader = new FileReader();
  reader.onload = (ev) => {
    const data = JSON.parse(ev.target.result);
    if (!data.common || !data.hours) throw new Error('형식 오류');
    // common(기본급·입사일·연차)과 hours(잔업기록) 복원
    Object.assign(hourData, data.hours);
    localStorage.setItem('ot3-hours', JSON.stringify(hourData));
    buildAll();   // 화면 전체 다시 그리기
  };
  reader.readAsText(file);
}

3-5. 연차 관리 — 입사일만 넣으면 자동 계산

잔업과 함께 챙겨야 할 게 연차입니다. 입사일만 입력하면 근속 기간에 따른 발생 연차를 자동으로 계산하고, 사용한 날을 기록해서 남은 연차를 실시간으로 보여줍니다. 입사 1년 미만은 월 만근 시 1일씩(최대 11일), 1년 이상은 15일이 발생하는 법정 기준을 반영했습니다.

// 입사일 기준 발생 연차 계산 (법정 최소 기준)
function calcLeave(joinDate, now = new Date()) {
  const months = diffMonths(joinDate, now);
  const accrued = months < 12
    ? Math.min(months, 11)       // 1년 미만: 월 1일, 최대 11일
    : 15;                        // 1년 이상: 15일
  const used = leaveLogs.reduce((s, l) => s + l.days, 0);
  return { accrued, used, remaining: accrued - used };
}

연차 사용 기록도 날짜·메모와 함께 저장하고, 목록을 내려서 전체 내역을 확인할 수 있습니다. 급여명세서의 연차 항목과 대조하면 잔여 연차가 정확한지 바로 알 수 있습니다.

3-6. 설치형 앱 만들기 — PWA

manifest.json과 service worker를 추가하면 홈 화면에 설치해서 앱처럼 쓸 수 있습니다. 설치가 끝나면 홈 화면 아이콘을 누르는 것만으로 주소창 없이 바로 열리고, 한 번 열린 뒤에는 캐시된 파일로 오프라인에서도 사용할 수 있습니다.

{
  "name": "잔업 정산기",
  "short_name": "잔업정산기",
  "description": "기본급만 넣으면 잔업수당이 자동 계산되는 PWA",
  "start_url": "/",
  "display": "standalone",
  "background_color": "#0b1020",
  "theme_color": "#0b1020",
  "icons": [
    { "src": "/icon-192.png", "sizes": "192x192", "type": "image/png" },
    { "src": "/icon-512.png", "sizes": "512x512", "type": "image/png" }
  ]
}
// service-worker.js — 설치 시 파일을 캐시에 저장하고, 이후엔 캐시부터 응답
const CACHE = 'janyeop-v1';
const ASSETS = ['/', '/index.html', '/icon-192.png', '/icon-512.png'];

self.addEventListener('install', (e) => {
  e.waitUntil(caches.open(CACHE).then((c) => c.addAll(ASSETS)));
  self.skipWaiting();
});

self.addEventListener('activate', (e) => {
  e.waitUntil(
    caches.keys().then((keys) =>
      Promise.all(keys.filter((k) => k !== CACHE).map((k) => caches.delete(k)))
    )
  );
  self.clients.claim();
});

self.addEventListener('fetch', (e) => {
  if (e.request.method !== 'GET') return;
  e.respondWith(caches.match(e.request).then((hit) => hit || fetch(e.request)));
});
// 등록 코드 — 기준을 충족하면 브라우저가 설치 아이콘을 자동으로 보여줍니다
if ('serviceWorker' in navigator) {
  navigator.serviceWorker.register('/service-worker.js');
}
기능구현 방식
시급·잔업단가기본급 ÷ 209시간, ×1.5 자동 산출
잔업 기록캘린더 UI에서 날짜별 입력
월별·연간 정산시간·수당·총 수령액 테이블
데이터 보존LocalStorage + 내보내기/가져오기
연차 관리입사일 기준 발생 연차 자동 계산 + 사용 기록
설치PWA — 홈 화면 설치 지원

4. 만들면서 막혔던 부분

처음부터 완벽하게 계산되지는 않았습니다. 실제로 만들면서 부딪힌 부분을 공유합니다.

209시간의 함정. 처음에는 주 40시간 × 4.345주 = 약 174시간만 적용했습니다. 그런데 이 값은 주휴수당이 빠진 기준이라 시급이 커져 수당이 과대계상됩니다. 주휴를 포함한 209시간이 표준이며, 이 차이를 놓치면 매달 수만 원씩 다르게 계산됩니다.

회사마다 다른 규정. 연차 발생 규정이 회사마다 달라 법정 최소 기준으로 계산하되, 사용자가 직접 조정할 수 있게 열어뒀습니다. "정답"을 강제하지 않는 게 오히려 실제 사용률을 높였습니다.

계산기보다 기록 도구. 처음에는 "기본급 넣고 잔업시간 넣으면 끝"인 계산기부터 만들었습니다. 하지만 잔업시간을 기억해서 넣는 일이 오히려 더 어려웠고, 캘린더에 매일 탭 한 번으로 기록하는 형태로 바꾼 뒤에야 실제로 쓰기 시작했습니다.

5. 급여명세서 검증 방법

만든 뒤 가장 큰 변화는 잔업에 대한 인식이었습니다. 숫자로 매달 쌓이는 걸 보니 "적당히 하자"던 태도가 "이 시간은 내 시간"이라는 생각으로 바뀌었습니다. 그리고 급여명세서의 잔업수당을 계산 결과와 대조하다 보니 실제로 회사 계산과 다른 부분을 발견해 정정 요청한 적도 있었습니다.

매달 1분만 투자해서 직접 계산해 보세요. 기본급과 잔업시간 두 가지만 있으면 됩니다.
📋 핵심 요약
  1. 잔업수당은 시급(기본급÷209시간)의 150%가 기본 구조입니다.
  2. 계산기보다 기록 도구로 만드는 게 실제 사용률이 높았습니다.
  3. 모바일 앱형 레이아웃 + PWA로 설치형 앱처럼 쓸 수 있게 했습니다.
  4. 데이터는 서버 없이 LocalStorage로 충분했습니다.
Q
잔업수당 계산법이 궁금합니다. 공식이 뭔가요?
A
시급 = 기본급 ÷ 209시간, 잔업단가 = 시급 × 1.5, 월 잔업수당 = 잔업시간 합 × 잔업단가입니다. 기본급과 잔업시간 두 가지만 알면 됩니다. → 시급 × 1.5 × 잔업시간
Q
왜 월 소정근로시간이 209시간인가요?
A
주 40시간 기준 한 달 근로시간(약 174시간)에 주휴수당 시간(약 35시간)을 더한 값입니다. 기본급에 주휴가 포함되어 있으므로 209로 나눠야 실제 시급이 나옵니다. → 174시간 + 주휴 35시간
Q
연장근로는 왜 150%인가요?
A
근로기준법 제56조가 연장근로에 통상임금의 50% 가산을 규정하기 때문입니다. 야간근로는 50%가 추가로 가산되어 최대 200%가 됩니다. → 법정 가산 50%
Q
급여명세서의 잔업수당이 맞는지 어떻게 확인하나요?
A
기본급과 해당 월 잔업시간을 위 공식에 대입해 직접 계산한 값과 명세서를 비교하면 됩니다. 차이가 있다면 인사팀에 계산 기준을 문의해 보세요. → 직접 계산 후 명세서와 대조

잔업수당 계산, 이제 직접 해보세요. 기본급과 잔업시간만 기록하면 자동으로 정산됩니다.

잔업수당 계산법 잔업수당 PWA JavaScript LocalStorage 연차계산