「〇日後っていつ?」「この日から何日経った?」
日常でも仕事でも、日付の計算って意外と面倒ですよね。
この記事では、JavaScriptで「〇日後/〇日前」「日数差」「営業日」まで自動で計算できるWebツールを、初心者の方でも作れるように丁寧に解説します。
- HTMLとJavaScriptで動くシンプルなツール
- 土日を除いた営業日にも対応
- 「初日を含む」計算や「月・年単位」の日付操作もできる!
コピーしてそのまま使えるコード付きで紹介するので、環境構築や難しい設定は不要です。
「自分でもWebツールが作れるかも!」と思っていただけるよう、サンプルも交えて、わかりやすくお届けします。
ぜひ最後まで読んで、あなたの便利な日付計算ツールを作ってみてください!
このツールで何ができるのか?主な機能を紹介
今回作る日付計算ツールは、次のような便利な機能を備えています。
①「〇日後」「〇日前」の日付をすぐに計算できる
指定した日付から「5日後はいつ?」「10日前は何日?」といった未来や過去の日付を瞬時に表示します。
また、月単位・年単位でも計算可能なので、「2ヶ月後」や「1年前」なども扱えます。
② 2つの日付の「差(日数)」を計算できる
開始日と終了日を入力することで、日数の差分を自動で計算します。
「イベントまであと何日?」「プロジェクト期間は何日間?」など、実務にも役立ちます。
③ 土日を除いた営業日での計算にも対応
ビジネス利用では欠かせない「営業日計算」にも対応。
土日をカウントしない営業日ベースの〇日後/〇日前計算ができます。
④ 「初日を含む/含まない」を選べる
日数差を求める際に、「初日を含めるかどうか」で結果が変わることがあります。
このツールでは初日を含む・含まないの切り替えが可能なので、シーンに応じた柔軟な使い方ができます。
【実際の日付計算ツールの動作を試してみたい方はこちらからどうぞ】▼
開発に必要な準備とファイル構成
JavaScriptで日付計算ツールを作るにあたって、準備すべきものは意外とシンプルです。初心者でもすぐに取りかかれるように、必要な環境やファイル構成を確認しておきましょう。
必要なものはたったこれだけ!
- テキストエディタ(例:メモ帳、Visual Studio Code)
VS Code (Visual Studio Code) とは:
Microsoftが開発している、プログラミングコードを書くための高機能な無料テキストエディタです。
たくさんの便利な機能があり、世界中の開発者に愛用されています。 - Webブラウザ(例:Google Chrome、Microsoft Edge、Firefoxなど)
これだけあれば、今すぐ開発を始められます!
サーバー不要で、ローカル環境で完結するのがHTML×JavaScriptツールの魅力です。
ファイル構成(シンプルな構成)
作業ディレクトリの中身は以下のように整理しておきましょう。
date_calculator/
├── index.html … ツール本体(HTML構造)
├── style.css … 見た目を整えるCSS
└── script.js … 日付計算のロジックを記述するJavaScript
1つのHTMLファイルにまとめることもできますが、保守性と読みやすさを重視して、今回は3ファイル構成をおすすめします。
メモ帳とブラウザがあればOK!開発準備はとてもシンプルです!

HTMLで日付計算ツールの骨組みを作ろう(UI設計)
まずは、ツールの見た目となる「画面の骨組み」をHTMLで作成していきましょう。
ここでは、2つの主要機能をタブで切り替えられるレイアウトを構築します。index.html
に以下のコードをコピー&ペーストしてください。これはツールの基本的な構造を作ります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 |
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>自作 日数計算ツール</title> <link rel="stylesheet" href="style.css"> </head> <body> <header> <h1>日数計算ツール</h1> </header> <main> <!-- タブの切り替えボタン --> <nav class="tabs"> <button class="tab-button active" data-tab="day-calculation">日数計算</button> <button class="tab-button" data-tab="date-difference">日付差計算</button> </nav> <!-- タブ1: ○日後/○日前 --> <div id="day-calculation" class="tab-content active"> <h2>〇日後 / 〇日前を計算</h2> <div class="input-group"> <label for="calcDayBaseDate">基準日:</label> <input type="date" id="calcDayBaseDate"> </div> <div class="input-group"> <label for="calcAmount">期間:</label> <input type="number" id="calcAmount" value="0"> <select id="calcUnit"> <option value="day">日</option> <option value="month">ヶ月</option> <option value="year">年</option> </select> <select id="calcOffsetType"> <option value="after">後</option> <option value="before">前</option> </select> </div> <div class="input-group checkbox-group"> <input type="checkbox" id="includeStartDate"> <label for="includeStartDate">初日を含む</label> </div> <div class="input-group checkbox-group"> <input type="checkbox" id="skipWeekends"> <label for="skipWeekends">土日を除いて計算</label> </div> <button id="calculateDay">計算</button> <div class="result-area"> <p>結果: <span id="resultDayCalculation"></span></p> <p id="skippedDaysInfo" style="font-size: 0.8em; margin-top: 5px; color: #666;"></p> <button class="share-button" data-target="resultDayCalculationWithSkipped">結果をコピー</button> </div> <div id="resultDayCalculationWithSkipped" style="display: none;"></div> </div> <!-- タブ2: 日付差の計算 --> <div id="date-difference" class="tab-content"> <h2>2つの日付の差を計算</h2> <div class="input-group"> <label for="startDateDiff">開始日:</label> <input type="date" id="startDateDiff"> </div> <div class="input-group"> <label for="endDateDiff">終了日:</label> <input type="date" id="endDateDiff"> </div> <div class="input-group checkbox-group"> <input type="checkbox" id="includeStartDateDiff"> <label for="includeStartDateDiff">初日を含む</label> </div> <div class="input-group checkbox-group"> <input type="checkbox" id="skipWeekendsDiff"> <label for="skipWeekendsDiff">土日を除いて計算</label> </div> <button id="calculateDateDiff">計算</button> <div class="result-area"> <p>日付差: <span id="resultDateDifference"></span></p> <p id="skippedDaysInfoDiff" style="font-size: 0.8em; margin-top: 5px; color: #666;"></p> <button class="share-button" data-target="resultDateDifferenceWithSkipped">結果をコピー</button> </div> <div id="resultDateDifferenceWithSkipped" style="display: none;"></div> </div> </main> <script src="script.js"></script> </body> </html> |
補足ポイント
- input type="date" を使うことで、カレンダー形式の入力が可能に。
- チェックボックス や ラジオボタン を使って、柔軟に条件指定が可能。
- タブ切り替え には、後ほどJavaScriptを使って表示制御を行います。
CSSで日付計算ツールのデザインを整えよう
ツールのHTML構造ができたら、次はCSSで見た目を整えます。
シンプルで見やすく、ユーザーが迷わず使えるようなレイアウトを意識しましょう。
作成したHTMLを美しく見せるためのCSSをstyle.css
に記述します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 |
body { font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; margin: 0; padding: 0; background-color: #f4f7f6; color: #333; line-height: 1.6; display: flex; flex-direction: column; min-height: 100vh; } header { background-color: #007bff; color: white; padding: 20px 0; text-align: center; box-shadow: 0 2px 4px rgba(0,0,0,0.1); } main { max-width: 750px; width: 90%; margin: 20px auto; background-color: #fff; padding: 30px; border-radius: 8px; box-shadow: 0 0 15px rgba(0,0,0,0.1); flex-grow: 1; } .tabs { display: flex; justify-content: center; margin-bottom: 20px; border-bottom: 2px solid #eee; flex-wrap: wrap; } .tab-button { background-color: #f0f0f0; border: none; padding: 12px 25px; cursor: pointer; font-size: 16px; color: #555; transition: background-color 0.3s ease, color 0.3s ease; border-radius: 5px 5px 0 0; margin: 0 5px; flex-grow: 1; text-align: center; white-space: nowrap; max-width: 250px; } .tab-button.active { background-color: #007bff; color: white; font-weight: bold; border-bottom: 2px solid #007bff; } .tab-button:hover:not(.active) { background-color: #e0e0e0; } .tab-content { display: none; padding-top: 20px; } .tab-content.active { display: block; } h2 { color: #007bff; border-bottom: 2px solid #f0f0f0; padding-bottom: 10px; margin-bottom: 25px; font-size: 1.8em; text-align: center; } .input-group { margin-bottom: 15px; display: flex; align-items: center; padding-left: 135px; } .input-group label { width: 120px; text-align: right; padding-right: 15px; box-sizing: border-box; flex-shrink: 0; margin-left: -135px; font-weight: bold; } .input-group input[type="date"] { flex: 0 0 180px; padding: 10px; border: 1px solid #ccc; border-radius: 4px; font-size: 16px; box-sizing: border-box; } .input-group input[type="number"] { flex: 0 0 50px; padding: 10px; border: 1px solid #ccc; border-radius: 4px; font-size: 16px; box-sizing: border-box; text-align: center; } .input-group select { flex: 0 0 100px; padding: 10px; border: 1px solid #ccc; border-radius: 4px; font-size: 16px; box-sizing: border-box; } .input-group.checkbox-group { padding-left: 135px; margin-bottom: 5px; } .input-group.checkbox-group label { width: auto; text-align: left; padding-right: 0; margin-left: 5px; font-weight: normal; cursor: pointer; } .input-group.checkbox-group input[type="checkbox"] { width: auto; margin-right: 0; transform: scale(1.2); cursor: pointer; } button { background-color: #28a745; color: white; padding: 12px 25px; border: none; border-radius: 5px; cursor: pointer; font-size: 17px; transition: background-color 0.3s ease; margin-top: 20px; display: block; margin-left: auto; margin-right: auto; } button:hover { background-color: #218838; } .result-area { margin-top: 30px; padding: 20px; background-color: #e9f5ff; border: 1px solid #cce5ff; border-radius: 5px; font-size: 20px; font-weight: bold; text-align: center; display: flex; flex-direction: column; align-items: center; } .result-area p { margin: 0; margin-bottom: 15px; } .share-button { background-color: #6c757d; padding: 8px 15px; font-size: 14px; margin-top: 0; } .share-button:hover { background-color: #5a6268; } footer { text-align: center; margin-top: 40px; padding: 20px; color: #777; font-size: 14px; background-color: #f0f0f0; box-shadow: 0 -2px 4px rgba(0,0,0,0.05); margin-top: auto; } /* --- モバイル対応 --- */ @media (max-width: 768px) { .tabs { flex-direction: column; align-items: stretch; } .tab-button { margin: 0 0 5px 0; border-radius: 5px; font-size: 15px; padding: 10px 15px; max-width: unset; } main { margin: 10px; padding: 15px; width: auto; } .input-group { flex-direction: column; align-items: flex-start; gap: 5px; padding-left: 0; } .input-group label { width: 100%; text-align: left; margin-bottom: 0; padding-right: 0; margin-left: 0; } .input-group input, .input-group select { width: 100%; min-width: unset; flex: unset; } .input-group.checkbox-group { padding-left: 0; } .result-area { padding: 15px; font-size: 18px; } .result-area p { margin-bottom: 10px; } } |
コードの確認方法
index.html
ファイルをブラウザで開いてみましょう。- 見た目は整っているでしょうか?
- まだボタンを押しても何も変化がないはずです。次はJavaScriptで動きをつけます。
CSSで整えるだけで、ツールの使いやすさ・信頼感が一気にアップしますよ!

JavaScriptで日付計算機能を実装しよう
ここからは、このツールの心臓部である「日付の計算処理」をJavaScriptで実装していきます。
日付操作には Date
オブジェクトを活用し、加算・減算・差分計算を行います。script.js
ファイルに以下のコードを記述してください。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 |
document.addEventListener('DOMContentLoaded', () => { // === グローバル変数 === const dayNames = ['日', '月', '火', '水', '木', '金', '土']; // === UI制御: タブ切り替え === const tabButtons = document.querySelectorAll('.tab-button'); const tabContents = document.querySelectorAll('.tab-content'); tabButtons.forEach(button => { button.addEventListener('click', () => { const tabId = button.dataset.tab; tabButtons.forEach(btn => btn.classList.remove('active')); tabContents.forEach(content => content.classList.remove('active')); button.classList.add('active'); document.getElementById(tabId).classList.add('active'); }); }); // 初期表示:今日の日付を設定し、デフォルトタブをアクティブにする const today = new Date(); const todayISO = today.toISOString().split('T')[0]; document.getElementById('calcDayBaseDate').value = todayISO; document.getElementById('startDateDiff').value = todayISO; document.getElementById('endDateDiff').value = todayISO; document.querySelector('.tab-button.active').click(); // === 日数計算(〇日後 / 〇日前) === const calcDayBaseDateInput = document.getElementById('calcDayBaseDate'); const calcAmountInput = document.getElementById('calcAmount'); const calcUnitSelect = document.getElementById('calcUnit'); const calcOffsetTypeSelect = document.getElementById('calcOffsetType'); const includeStartDateCheckbox = document.getElementById('includeStartDate'); const skipWeekendsCheckbox = document.getElementById('skipWeekends'); const calculateDayButton = document.getElementById('calculateDay'); const resultDayCalculationSpan = document.getElementById('resultDayCalculation'); const skippedDaysInfoSpan = document.getElementById('skippedDaysInfo'); const resultDayCalculationWithSkippedDiv = document.getElementById('resultDayCalculationWithSkipped'); calculateDayButton.addEventListener('click', () => { // ボタンがクリックされたら実行 let baseDate = new Date(calcDayBaseDateInput.value); // 基準日を取得 let amount = parseInt(calcAmountInput.value, 10); // 期間の数値を取得 const unit = calcUnitSelect.value; // 単位(日、月、年)を取得 const offsetType = calcOffsetTypeSelect.value; // 後、前を取得 const includeStartDate = includeStartDateCheckbox.checked; // 初日を含むかを取得 const skipWeekends = skipWeekendsCheckbox.checked; // 土日を除くかを取得 // 入力値のバリデーション if (isNaN(baseDate.getTime())) { alert('有効な基準日を入力してください。'); return; } if (isNaN(amount)) { alert('有効な期間を入力してください。'); return; } // 「前」の場合は数値を負にする if (offsetType === 'before') { amount *= -1; } let resultDate = new Date(baseDate); // 結果を格納する日付 let skippedDays = 0; // スキップされた土日の日数 // 土日スキップかつ日単位の場合の特殊な計算ロジック if (skipWeekends && unit === 'day') { let daysToCount = Math.abs(amount); // 目標の営業日数 const direction = amount > 0 ? 1 : -1; // 日付を進める方向 (1:後, -1:前) let currentDate = new Date(baseDate); // 現在処理中の日付 let currentWorkingDaysCounted = 0; // カウントされた営業日数 if (amount === 0) { // 0日後/前の場合、基準日自体が結果 if (includeStartDate && isWeekend(currentDate)) { skippedDays = 1; // 基準日が土日ならスキップ対象としてカウント } // resultDateはbaseDateのまま } else { // 初日を含む場合の初期処理 if (includeStartDate) { if (!isWeekend(currentDate)) { currentWorkingDaysCounted = 1; // 基準日が営業日なら1日目としてカウント } else { skippedDays++; // 基準日が土日ならスキップ } } // 目標の営業日数に達するまで日付を進める while (currentWorkingDaysCounted < daysToCount) { currentDate.setDate(currentDate.getDate() + direction); // まず日付を進める if (isWeekend(currentDate)) { skippedDays++; } else { currentWorkingDaysCounted++; } } resultDate = currentDate; // 目標の営業日が見つかった日付 // 最終結果が土日の場合、次の営業日まで進める(念のため) while (isWeekend(resultDate)) { resultDate.setDate(resultDate.getDate() + direction); skippedDays++; } } } else { // 土日スキップなし、または月/年単位の場合の計算ロジック let daysToAdd = amount; if (includeStartDate && amount !== 0) { // 初日を含む場合、N日後/前は (N-1) 日の加減算になる daysToAdd = amount > 0 ? amount - 1 : amount + 1; } else if (amount === 0) { daysToAdd = 0; // 0日後/前は常に基準日 } // 単位に応じた日付の加減算 if (unit === 'day') { resultDate.setDate(baseDate.getDate() + daysToAdd); } else if (unit === 'month') { resultDate.setMonth(baseDate.getMonth() + daysToAdd); } else if (unit === 'year') { resultDate.setFullYear(baseDate.getFullYear() + daysToAdd); } } // 結果の表示 resultDayCalculationSpan.textContent = formatToJapaneseDateWithWeekday(resultDate); if (skipWeekends && unit === 'day') { skippedDaysInfoSpan.textContent = `(土日を${skippedDays}日スキップしました)`; } else { skippedDaysInfoSpan.textContent = ''; } // コピー用テキストの設定 resultDayCalculationWithSkippedDiv.textContent = resultDayCalculationSpan.textContent; if (skippedDaysInfoSpan.textContent) { resultDayCalculationWithSkippedDiv.textContent += ' ' + skippedDaysInfoSpan.textContent; } }); // === 日付差計算 === const startDateDiffInput = document.getElementById('startDateDiff'); const endDateDiffInput = document.getElementById('endDateDiff'); const includeStartDateDiffCheckbox = document.getElementById('includeStartDateDiff'); const skipWeekendsDiffCheckbox = document.getElementById('skipWeekendsDiff'); const calculateDateDiffButton = document.getElementById('calculateDateDiff'); const resultDateDifferenceSpan = document.getElementById('resultDateDifference'); const skippedDaysInfoDiffSpan = document.getElementById('skippedDaysInfoDiff'); const resultDateDifferenceWithSkippedDiv = document.getElementById('resultDateDifferenceWithSkipped'); calculateDateDiffButton.addEventListener('click', () => { let startDate = new Date(startDateDiffInput.value); let endDate = new Date(endDateDiffInput.value); const includeStartDate = includeStartDateDiffCheckbox.checked; const skipWeekends = skipWeekendsDiffCheckbox.checked; // 入力値のバリデーション if (isNaN(startDate.getTime()) || isNaN(endDate.getTime())) { alert('有効な開始日と終了日を入力してください。'); return; } // 日付のみの差を正確に計算するため、時刻部分を無視する startDate.setHours(0, 0, 0, 0); endDate.setHours(0, 0, 0, 0); let diffDays = 0; let skippedDays = 0; // 期間の開始日と終了日を正規化(常に開始日が終了日より前か同じになるように) const actualStartDate = new Date(Math.min(startDate.getTime(), endDate.getTime())); const actualEndDate = new Date(Math.max(startDate.getTime(), endDate.getTime())); if (actualStartDate.getTime() === actualEndDate.getTime()) { // 開始日と終了日が同じ場合 if (includeStartDate) { diffDays = 1; // 初日を含むので1日 if (skipWeekends && isWeekend(actualStartDate)) { skippedDays = 1; // 土日スキップの場合、その日は営業日としてカウントしない diffDays = 0; } } else { diffDays = 0; // 初日を含まない場合、同じ日なら0日 } } else { // 異なる日付の場合 let currentDate = new Date(actualStartDate); while (currentDate <= actualEndDate) { if (skipWeekends) { if (!isWeekend(currentDate)) { diffDays++; } else { skippedDays++; } } else { diffDays++; } currentDate.setDate(currentDate.getDate() + 1); } if (!includeStartDate) { // 初日を含まない場合、開始日をカウントから除外 if (skipWeekends) { if (!isWeekend(actualStartDate)) { // 開始日が営業日なら1日減らす diffDays--; } } else { diffDays--; // 無条件に1日減らす } } } let message = `${diffDays} 日間`; if (diffDays === 0) { message = `0 日間`; } resultDateDifferenceSpan.textContent = message; if (skipWeekends) { skippedDaysInfoDiffSpan.textContent = `(土日を${skippedDays}日スキップしました)`; } else { skippedDaysInfoDiffSpan.textContent = ''; } // コピー用テキストの設定 resultDateDifferenceWithSkippedDiv.textContent = resultDateDifferenceSpan.textContent; if (skippedDaysInfoDiffSpan.textContent) { resultDateDifferenceWithSkippedDiv.textContent += ' ' + skippedDaysInfoDiffSpan.textContent; } }); // === 共有(コピー)機能 === document.querySelectorAll('.share-button').forEach(button => { button.addEventListener('click', (e) => { const targetId = e.target.dataset.target; const textToCopy = document.getElementById(targetId).textContent.trim(); if (textToCopy) { navigator.clipboard.writeText(textToCopy) .then(() => { alert('結果がクリップボードにコピーされました!'); }) .catch(err => { console.error('クリップボードへのコピーに失敗しました:', err); alert('コピーに失敗しました。お手数ですが手動でコピーしてください。\n\n' + textToCopy); }); } else { alert('コピーする結果がありません。'); } }); }); // === ヘルパー関数 === // 日付を「YYYY年M月D日(曜日)」形式にフォーマット function formatToJapaneseDateWithWeekday(date) { const year = date.getFullYear(); const month = date.getMonth() + 1; // getMonth()は0から始まる const day = date.getDate(); const weekday = dayNames[date.getDay()]; return `${year}年${month}月${day}日(${weekday})`; } // 指定されたDateオブジェクトが土日であるかを判定 function isWeekend(date) { const dayOfWeek = date.getDay(); // 0:日曜日, 6:土曜日 return dayOfWeek === 0 || dayOfWeek === 6; } }); |
コードのポイント解説
この長いコードも、一つずつ分解すれば理解できます。重要な部分をピックアップして見ていきましょう。
document.addEventListener('DOMContentLoaded', () => { ... });
- これは「ウェブページの中身(HTML)が全部読み込まれたら、この中のコードを実行してね」というお約束の記述です。JavaScriptはHTML要素が存在しないと操作できないので、この書き方がよく使われます。
- 要素の取得(例:
document.getElementById('calcDayBaseDate')
)- HTMLファイルで付けた
id
(例:calcDayBaseDate
)を使って、JavaScriptからHTMLの部品(入力欄やボタンなど)を「これは、この部品のことだよ!」と指定し、操作できるようにしています。 - 部品は変数(
const
やlet
で宣言するもの)に入れておくと、後で使いやすくなります。
- HTMLファイルで付けた
- イベントリスナーの設定(例:
calculateDayButton.addEventListener('click', () => { ... });
)- イベントリスナーとは?
特定の「イベント」(例:ボタンのクリック、キーボードの入力、ページの読み込み完了など)が発生したときに、指定したJavaScriptのコードを実行するための仕組みです。 - ここでは、「
calculateDayButton
(計算ボタン)がclick
(クリック)されたら、その後の{ ... }
の中の処理を実行してください」という指示をしています。
- イベントリスナーとは?
- 日付の取得と数値への変換
- 入力された日付(例:
'2025-07-20'
)は、new Date(入力値)
のようにすることで、JavaScriptのDateオブジェクトに変換されます。 - 数値(日数など)は、
parseInt(入力値, 10)
を使って、文字列から正確な整数(10進数)に変換しています。
- 入力された日付(例:
- 【機能1】〇日後・〇日前の計算ロジック
- 日付の加減算:
- JavaScriptのDateオブジェクトには、日付を操作する便利なメソッドがあります。
resultDate.setDate(resultDate.getDate() + 10);
- これは「
resultDate
の日を現在の日の値に10を足した値に設定する」という意味です。
例えば、7月20日に10を足せば7月30日になります。 - JavaScriptは賢いので、7月32日になった場合は自動的に8月1日などに調整してくれます。
- これは「
- 月や年も同様に、
setMonth()
やsetFullYear()
を使います。
- 「前」の場合の処理:
if (offsetType === 'before') { amount *= -1; }
- 「〇日前」を選んだ場合は、入力された数値に-1を掛けて負の数にすることで、日付を「進める」のではなく「戻す」計算に対応させています。
- 日付の加減算:
- 【機能2】2つの日付差の計算ロジック
- 日付の引き算は「ミリ秒」:
- JavaScriptでDateオブジェクト同士を直接引き算すると、ミリ秒(1000分の1秒)単位での差が計算されます。
- 例:
endDate.getTime() - startDate.getTime()
getTime()
メソッドは、Dateオブジェクトが「1970年1月1日 00:00:00 UTC」からどれだけミリ秒が経過したか、という数値を返します。この数値同士を引き算することで、正確な時間差が得られます。
- ミリ秒から日数へ:
- 1日 = 24時間 × 60分 × 60秒 × 1000ミリ秒 = 86,400,000ミリ秒です。
- 計算されたミリ秒の差をこの数値で割ることで、日数を算出します。
- 日付の引き算は「ミリ秒」:
- 【機能3】土日を除く営業日計算ロジック
- この機能は少し複雑です。
isWeekend(date)
関数:- Dateオブジェクトの
getDay()
メソッドは、曜日を数値(日曜日が0、土曜日が6)で返します。 - この関数は、受け取った日付が土曜日(6)か日曜日(0)なら
true
(土日である)、それ以外ならfalse
を返します。
- Dateオブジェクトの
- ループ処理とスキップ:
while
文という「条件が真である限り繰り返す」処理を使って、日付を1日ずつ進めたり戻したりします。if (isWeekend(currentDate)) { ... } else { ... }
のように条件分岐を使い、土日であれば日数をスキップし、営業日であればカウントを進めます。- これにより、指定された営業日数に到達するまで、土日を避けて日付を計算することができます。
- 「初日を含む/含まない」の調整
- 「〇日後/前」計算では、
if (includeStartDate && amount !== 0)
の条件で、初日を含める場合に日数を1日調整しています。 - 「日付差計算」では、ループで全期間を数えた後、
if (!includeStartDate)
の条件で初日を含まない場合に最終的な日数から1日引いています。
- 「〇日後/前」計算では、
- 結果の表示とフォーマット
- 計算された結果のDateオブジェクトを、
formatToJapaneseDateWithWeekday
関数を使って「YYYY年M月D日(曜日)」という見やすい形式に変換しています。 textContent
を使って、HTMLの<span>
タグの中に結果を書き込んでいます。
- 計算された結果のDateオブジェクトを、
- コピー機能
navigator.clipboard.writeText(テキスト)
というAPIを使うと、指定したテキストをクリップボードにコピーできます。ユーザーが結果を簡単に利用できるようにするための便利な機能です。
JavaScriptなら、日付の足し引きや差分計算も意外とシンプルにできますよ!

さらにツールを使いやすくする応用テクニック
ここまでで基本的な日付計算ツールは完成ですが、さらに使いやすくするための応用テクニックをいくつかご紹介します。
コピー機能の実装
今回のコードにはすでに含まれていますが、計算結果をワンクリックでコピーできる機能は非常に便利です。navigator.clipboard.writeText()
というJavaScriptのAPI(アプリケーション・プログラミング・インターフェース)を使うことで、簡単に実装できます。
入力値のバリデーション
ユーザーが日付を正しく入力しなかった場合や、無効な数値を入力した場合に、適切なメッセージを表示する「バリデーション(入力値検証)」機能を追加すると、より親切なツールになります。
- 例えば、日付が空の場合は「日付を入力してください」とアラートを出す
- 入力された数値が数字ではない場合は「半角数字を入力してください」と促す
UI/UX改善のヒント
ユーザーインターフェース(UI)やユーザーエクスペリエンス(UX)を向上させることで、ツールの使いやすさが格段に上がります。
- エラーメッセージの表示:
アラートではなく、入力フィールドの近くに赤い文字でエラーメッセージを表示する - 入力リセットボタン:
全ての入力内容をクリアするボタンを追加する - 計算中のローディング表示:
計算に時間がかかる場合に「計算中…」などのメッセージを表示する(今回のツールでは不要かもしれませんが、大規模な計算では有効です)
これらの機能を追加することで、よりプロフェッショナルなツールへと進化させることができますよ。
ツール作りに役立つおすすめの学習リソース
「日付計算ツールを自分で作れた!」という達成感を得たあなた。
さらにスキルを伸ばして、もっと便利なWebツールを作ってみませんか?
ここでは、HTML・CSS・JavaScriptの基礎から応用まで学べるリソースを厳選してご紹介します。
書籍でじっくり学びたい人に
『確かな力が身につくJavaScript超入門』
JavaScriptの基本文法から実践的な活用まで、図解で丁寧に解説。初心者にとって理想的な一冊です。
『スラスラわかるHTML&CSSのきほん』
Webページの基礎を体系的に学びたい方へ。見やすいレイアウトと丁寧な説明で「初めてでも迷わない」構成です。
動画で学びたい人におすすめの講座
Udemy講座:【HTML,CSS,JS,PHP,Git,Docker】プログラミング初心者OK! ゼロからわかるWebシステム開発
【HTML,CSS,JS,PHP,Git,Docker】プログラミング初心者OK! ゼロからわかるWebシステム開発
→ HTMLとJavaScriptの基本操作を体系的に学べる人気講座。
ツール作成のためのHTML構造の作り方やJavaScriptの使い方がしっかり学べます。
「これからWEBツール作りにも挑戦したい」初心者の方にピッタリ。
他にも講座を探したい方はこちら → UdemyのWeb開発カテゴリー講座
まとめ|自分だけの便利ツールを作ろう!
今回は、JavaScriptで作る「日付計算ツール」の作り方をご紹介しました。
この記事では、Webブラウザで動く多機能な日付計算ツールをJavaScriptで自作する方法を解説しました。
- HTMLでウェブページの骨組みを作り
- CSSで見た目を整え
- JavaScriptで「〇日後・〇日前」「日付差」「土日を除く営業日計算」「初日含む/含まない」「月・年単位計算」といった複雑な計算ロジックを実装しました。
今回学んだJavaScriptのDateオブジェクトの操作や、イベントリスナーの使い方、条件分岐やループ処理といった基本的なプログラミングの概念は、他のWeb開発にも応用できる非常に重要なスキルです。
ぜひ、この知識を活かして、あなた自身のアイデアで新たなWebツール開発に挑戦してみてください。
ちょっとしたツールでも、作ってみると大きな自信になります。

【実際の日付計算ツールの動作を試してみたい方はこちらからどうぞ】▼