週番号を日付範囲に変換する方法 — 完全ガイド

誰かからスケジュールが届く。「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 WeekYearMondaySunday
W12025December 30, 2024January 5, 2025
W12026December 29, 2025January 4, 2026
W12027January 4, 2027January 10, 2027
W12028January 3, 2028January 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)を使ってください。

任意の週番号の「日付範囲」

月曜日さえ分かれば、残りは簡単です:

DayOffset 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 WeekYearMondaySunday
W12026Dec 29, 2025Jan 4, 2026
W22026Jan 5, 2026Jan 11, 2026
W32026Jan 12, 2026Jan 18, 2026
W42026Jan 19, 2026Jan 25, 2026
W52026Jan 26, 2026Feb 1, 2026
W62026Feb 2, 2026Feb 8, 2026
W72026Feb 9, 2026Feb 15, 2026
W82026Feb 16, 2026Feb 22, 2026
W92026Feb 23, 2026Mar 1, 2026
W102026Mar 2, 2026Mar 8, 2026
...
W482026Nov 23, 2026Nov 29, 2026
W492026Nov 30, 2026Dec 6, 2026
W502026Dec 7, 2026Dec 13, 2026
W512026Dec 14, 2026Dec 20, 2026
W522026Dec 21, 2026Dec 27, 2026
W532026Dec 28, 2026Jan 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週の日付範囲も確認できます。