週番号を日付範囲に変換する方法 — 完全ガイド
誰かからスケジュールが届く。「W23に納品」。カレンダーを開いて固まる。結局それって、何月何日から何日まで?
週番号はプロジェクト計画、製造、流通、小売、物流などで広く使われていますが、多くの人はラベルとしてしか見ていません。週番号を実際のカレンダーの日付に戻すのは直感的ではなく、年境界のケースは経験豊富な開発者でもつまずきがちです。
このガイドでは、週番号→月曜、週番号→日付範囲(月〜日)、そして逆変換(日付→週番号)までを網羅します。Python、JavaScript、Excel、SQLのコードも載せています。
週番号が実際に示しているもの
計算の前に、その週番号がどの「週番号システム」由来なのかを把握する必要があります。
ISO 8601(国際標準): 週1は「その年の最初の木曜日を含む週」です。週は月曜始まりで日曜終わり。1年はISO週が52または53あります。重要なのは、ISOの「週年」が暦年と一致しないことがある点です。12月末の数日が、翌年の週1に入ることがあります。
米国式: 週1は1月1日を含みます。週の開始はツールによって日曜始まり(〜土曜)だったり月曜始まり(〜日曜)だったりします。1月1日は常に週1に入ります(例外なし)。
このガイドの残りでは、特に断りがない限り「週番号」はISO 8601を意味します。USベースのツール(例:既定のExcel WEEKNUM)から渡された週番号の場合は変換式が違います — 後半のセクションを参照してください。
年も必要です。 「週23」だけでは意味がありません。週番号は必ず (year, week) のペアとして扱ってください。2025年の週23は6月2日から始まります。2026年の週23は6月1日から始まります。2026年の週1は、2025年12月29日から始まります(2025年の日付です)。
基本式:ISO週番号 → 月曜日
すべてのISO週は月曜日に始まります。年YのISO週Wの「月曜日」を求めるには:
Monday = Y年の1月4日 + (W - 1) × 7日 - weekday(Y年の1月4日) + 1
考え方:1月4日は定義上必ずISO週1に含まれます(年の最初の4日以内に入るため、週に木曜日が含まれることが保証される)。まず1月4日を含む週の月曜日を求め、そこから (W - 1) 週ぶん前進します。
同値で、より分かりやすい形:
Week1の月曜 = Y年の1月4日 - weekday(Y年の1月4日) + 1
W週の月曜 = Week1の月曜 + (W - 1) × 7
ここで weekday は、月曜=1〜日曜=7(ISOの曜日番号)を返すものとします。
例:2026年の週23
- 2026年1月4日は日曜日。ISO weekday = 7。
- 週1の月曜:1月4日 − 7 + 1 = 2025年12月29日。
- 週23の月曜:2025年12月29日 + 22 × 7 = 154日後 = 2026年6月1日。
- 週23の日曜:6月1日 + 6 = 6月7日。
2026年の週23は、6月1日(月)〜6月7日(日)です。
年またぎの落とし穴
最もよくあるミスは、「年Yの週1は必ず年Yの中で始まる」と思い込むことです。
そうではありません。
週1は「最初の木曜日を含む週」です。その木曜日が1月上旬にある場合、週1の月曜日は前年の12月に落ちることがあります。
例:
| ISO Week | Year | Monday | Sunday |
|---|---|---|---|
| W1 | 2025 | December 30, 2024 | January 5, 2025 |
| W1 | 2026 | December 29, 2025 | January 4, 2026 |
| W1 | 2027 | January 4, 2027 | January 10, 2027 |
| W1 | 2028 | January 3, 2028 | January 9, 2028 |
2025年の週1は2024年12月に始まり、2026年の週1は2025年12月に始まります。
つまり:
- 2025年12月29〜31日は、ISO週では2025年ではなく 2026年の週1 です。
- 誰かが「2026年のW1までに納品」と言った場合、期限は 2025年12月29日から始まる週 になります。
逆方向の罠もあります。年によっては、12月末の数日が「その年の最終週」ではなく翌年の週1に入ります。週のラベル付けには、暦年ではなくISO週年(Pythonの%G、PostgreSQLのisoyear)を使ってください。
任意の週番号の「日付範囲」
月曜日さえ分かれば、残りは簡単です:
| Day | Offset from Monday |
|---|---|
| Monday | +0 |
| Tuesday | +1 |
| Wednesday | +2 |
| Thursday | +3 |
| Friday | +4 |
| Saturday | +5 |
| Sunday | +6 |
週Wの日付範囲は [Monday, Monday + 6日] です。
平日(Mon–Fri)の範囲だけが必要なら [Monday, Monday + 4日] です。
Python
from datetime import date, timedelta
def iso_week_to_monday(year: int, week: int) -> date:
# 1月4日は必ずISO週1に入る
jan4 = date(year, 1, 4)
# その週の月曜日まで戻す
week1_monday = jan4 - timedelta(days=jan4.weekday())
# 目的の週まで進める
return week1_monday + timedelta(weeks=week - 1)
def iso_week_to_range(year: int, week: int) -> tuple[date, date]:
monday = iso_week_to_monday(year, week)
sunday = monday + timedelta(days=6)
return monday, sunday
# 例
monday, sunday = iso_week_to_range(2026, 23)
print(monday) # 2026-06-01
print(sunday) # 2026-06-07
monday, sunday = iso_week_to_range(2026, 1)
print(monday) # 2025-12-29 ← 注意:2025年に始まる
print(sunday) # 2026-01-04
Pythonには逆変換(日付→ISO週)用の組み込みもあります:
d = date(2026, 6, 4)
iso_year, iso_week, iso_weekday = d.isocalendar()
print(iso_year, iso_week) # 2026 23
ISO年が必要な場合は d.year ではなく d.isocalendar().year を使ってください(年境界で一致しません)。
fromisocalendar(Python 3.8+)を使った逆引き:
# ISO週23(2026年)の月曜日を直接取得
monday = date.fromisocalendar(2026, 23, 1) # weekday 1 = Monday
print(monday) # 2026-06-01
Python 3.8以降なら、date.fromisocalendar(year, week, weekday) が最もクリーンです。
JavaScript
JavaScriptにはISO週のネイティブサポートがありません。手動実装:
function isoWeekToMonday(year, week) {
// 1月4日は必ずISO週1に入る
const jan4 = new Date(year, 0, 4)
const dayOfWeek = jan4.getDay() || 7 // Sun=0 を 7 に変換
const week1Monday = new Date(jan4)
week1Monday.setDate(jan4.getDate() - dayOfWeek + 1)
const monday = new Date(week1Monday)
monday.setDate(week1Monday.getDate() + (week - 1) * 7)
return monday
}
function isoWeekToRange(year, week) {
const monday = isoWeekToMonday(year, week)
const sunday = new Date(monday)
sunday.setDate(monday.getDate() + 6)
return { monday, sunday }
}
// 例
const { monday, sunday } = isoWeekToRange(2026, 23)
console.log(monday.toISOString().slice(0, 10)) // 2026-06-01
console.log(sunday.toISOString().slice(0, 10)) // 2026-06-07
const w1 = isoWeekToRange(2026, 1)
console.log(w1.monday.toISOString().slice(0, 10)) // 2025-12-29
date-fns を使う場合:
import { setISOWeek, setISOWeekYear, startOfISOWeek, endOfISOWeek } from 'date-fns'
function isoWeekToRange(year, week) {
let d = new Date(year, 0, 4) // 対象年の任意の日付
d = setISOWeekYear(d, year)
d = setISOWeek(d, week)
return {
monday: startOfISOWeek(d),
sunday: endOfISOWeek(d)
}
}
date-fns は年境界などのエッジケースを正しく処理するため、本番用途では推奨です。
Excel と Google Sheets
Excelには「週番号→日付」の直接関数はありませんが、式を組み立てれば求められます。
年YのISO週Wの月曜日:
=DATE(Y,1,4) - WEEKDAY(DATE(Y,1,4),2) + 1 + (W-1)*7
内訳:
DATE(Y,1,4)— その年の1月4日WEEKDAY(DATE(Y,1,4),2)— 月曜=1、日曜=7の曜日番号- 引き算で週1の月曜日が出る
(W-1)*7を足して目的の週へ移動する
範囲を出すなら、日曜日は単純に:
=Monday_formula + 6
シートでの例(A1=年、B1=週番号):
Monday: =DATE(A1,1,4) - WEEKDAY(DATE(A1,1,4),2) + 1 + (B1-1)*7
Sunday: =Monday_cell + 6
両セルを日付形式にします。2026年の週1なら、月曜日は2025年12月29日になり、これは正解です。
逆変換(日付→ISO週番号): ISOWEEKNUM(date) を使います。ISO年はExcelにネイティブ関数がないため、ISOWEEKNUMの解説記事にある回避策を使ってください。
SQL
PostgreSQL はISOサポートが最も充実しています:
-- 年YのISO週Wの月曜日
SELECT
make_date(2026, 1, 4)
+ (23 - 1) * 7 -- 週23まで進める
- EXTRACT(isodow FROM make_date(2026, 1, 4))::int + 1
AS week_monday;
-- 2026-06-01
-- generate_series を使って範囲で探す(例)
SELECT
d::date AS week_monday,
(d + 6)::date AS week_sunday,
EXTRACT(isoyear FROM d) AS iso_year,
EXTRACT(week FROM d) AS iso_week
FROM generate_series(
DATE '2026-01-01',
DATE '2026-12-31',
INTERVAL '7 days'
) d
WHERE EXTRACT(week FROM d) = 23
AND EXTRACT(isoyear FROM d) = 2026;
PostgreSQLのISOフォーマットコードを使う、よりクリーンな方法:
-- ISO年 + 週 → 月曜日
SELECT to_date('2026' || '23' || '1', 'IYYYIWid') AS monday;
-- 2026-06-01
-- IYYY=ISO年、IW=ISO週、id=ISO曜日(1=月曜)
これは最もシンプルです。YYYYWWD の文字列を作ってISOフォーマットでパースします。
MySQL:
-- ISO週23(2026年)の月曜日
SELECT STR_TO_DATE('202623 Monday', '%X%V %W');
-- 2026-06-01
-- あるいはステップ式:
SELECT DATE_ADD(
DATE_ADD(STR_TO_DATE('2026-01-04', '%Y-%m-%d'),
INTERVAL (-(WEEKDAY(STR_TO_DATE('2026-01-04', '%Y-%m-%d')))) DAY),
INTERVAL (23 - 1) * 7 DAY
) AS week_monday;
SQL Server:
-- ISO週23(2026年)の月曜日
DECLARE @year INT = 2026, @week INT = 23
SELECT DATEADD(
DAY,
(@week - 1) * 7
- (DATEPART(WEEKDAY, DATEFROMPARTS(@year, 1, 4)) + 5) % 7,
DATEFROMPARTS(@year, 1, 4)
) AS week_monday;
-- 2026-06-01
US式の週番号 → 日付
週番号がUS式(週1=1月1日を含む、週の開始は日曜または月曜)由来なら、年またぎ問題がないため式は単純です:
週の開始(Sunday始まり):
Week_start = DATE(Y, 1, 1) + (W - 1) × 7 - WEEKDAY(DATE(Y, 1, 1), 1)
ここで WEEKDAY は日曜=1〜土曜=7を返す想定です。
ただし、スケジュールや物流ではUS式よりISOのほうが一般的です。週番号だけ渡されてシステムが不明なら、特に国際・欧州系の文脈ではISOを前提にするのが安全です。
2026年のクイックリファレンス:ISO週 1–10 と 48–53
| ISO Week | Year | Monday | Sunday |
|---|---|---|---|
| W1 | 2026 | Dec 29, 2025 | Jan 4, 2026 |
| W2 | 2026 | Jan 5, 2026 | Jan 11, 2026 |
| W3 | 2026 | Jan 12, 2026 | Jan 18, 2026 |
| W4 | 2026 | Jan 19, 2026 | Jan 25, 2026 |
| W5 | 2026 | Jan 26, 2026 | Feb 1, 2026 |
| W6 | 2026 | Feb 2, 2026 | Feb 8, 2026 |
| W7 | 2026 | Feb 9, 2026 | Feb 15, 2026 |
| W8 | 2026 | Feb 16, 2026 | Feb 22, 2026 |
| W9 | 2026 | Feb 23, 2026 | Mar 1, 2026 |
| W10 | 2026 | Mar 2, 2026 | Mar 8, 2026 |
| ... | |||
| W48 | 2026 | Nov 23, 2026 | Nov 29, 2026 |
| W49 | 2026 | Nov 30, 2026 | Dec 6, 2026 |
| W50 | 2026 | Dec 7, 2026 | Dec 13, 2026 |
| W51 | 2026 | Dec 14, 2026 | Dec 20, 2026 |
| W52 | 2026 | Dec 21, 2026 | Dec 27, 2026 |
| W53 | 2026 | Dec 28, 2026 | Jan 3, 2027 |
2026年の週1は2025年12月29日に始まります。週53は2027年1月3日に終わり、2026年は53週の年です。
よくあるミス(まとめ)
年を含めない。 「週8」では曖昧です。2026-W08 のような形式を常に使いましょう。
暦年を使ってしまう。 2025年12月29日はISOでは2026年の週1です。2025年として保存するとバケツがずれます。
週1が1月1日から始まると思い込む。 多くの年で週1は12月29/30/31に始まります。1月1日が必ず週1に入る必要があるなら、それはISOではなくUS式です。
月曜日の式でオフバイワン。 Jan 4 を基準にするのが重要です(Jan 1は前年の最終週に入ることがある)。Jan 1を基準にすると、年によっては確実にずれます。
年境界でテストしない。 日付処理のコードは、12月28〜31日と1月1〜4日で必ずテストしてください。ほとんどのエッジケースはこの数日に集中します。
ISO週番号計算機 で任意の週番号の日付範囲を確認できます。また、現在の週番号 と「今日」のISO週の日付範囲も確認できます。