MOD、INDEX、IFだけで完全再現!日付関数ゼロで作る万年カレンダー

数学・アルゴリズム実験室

はじめに:日付関数を使わずにカレンダーを作る!?

当ブログ「Excelで暇つぶし」へようこそ!

Excelで「万年カレンダー」を作ろうと思ったとき、皆さんはどうしますか?

Excelの説明画像

おそらく、ほとんどの人はDATE関数やWEEKDAY関数を組み合わせるでしょう。

あるいは、月末を求めるEOMONTH関数などを利用して作るはずです。
もちろん、実務であればそれが大正解です。

しかし、普通のやり方を紹介するだけでは、わざわざ当ブログを読んでいただく意味がありません。
今回は、「日付・曜日系関数を一切使用禁止」という過酷な縛りプレイに挑戦します!

カレンダーを「日付」として扱うのはやめましょう。

「巨大な数列のパズル」として捉え直すのです。

そうすることで、

  • Excelの内部ロジックや配列の面白さが手に取るようにわかります
  • 誰もが知っているMODIFINDEXの3つの基本関数を使います

これらだけで万年カレンダーを錬成するのが今回のゴールです。

最初はSEQUENCE関数も使って段階的に進めますが、最終形態はこの3つの関数(MOD,IF,INDEX)に集約されます。

初心者の方にも理解できるよう、数式をバラバラに分解して丁寧に解説します。

ぜひ最後までついてきてください!

本記事では、無料のWeb版Excelを使用して検証を行っています。
Windowsはもちろん、MacやLinuxの方もブラウザさえあれば挑戦できます!


ステップ1:万年カレンダーの「巨大な土台」を作る

関数の詳細な仕様については、Microsoft公式のヘルプも参考にしてください。

今回は「月曜始まり」のカレンダーを制作します。

まずは、カレンダーのベースとなる「巨大な数列の土台」をワークシート上に作ってしまいましょう。

C2セルに、以下の数式を入力してみてください。

=SEQUENCE(, 13, -5) + SEQUENCE(6, , 0, 7)

すると、マイナスの数字から始まる、縦6行・横13列の巨大な表(配列)が出現したはずです。

Excelの説明画像

【数学的解説:なぜ「縦6×横13」なのか?】

カレンダーは1週間(7日)単位で改行されますよね。

この巨大な土台は、「どんな曜日に月が始まっても、必ず1日から月末まですっぽり切り出せるボード」なのです。

1. 横が13列の理由: 曜日は7つ(月〜日)あります。

カレンダーの1日が「月曜」なら一番左端から始まります。

Excelの説明画像

もし「日曜」始まりだった場合、1日の位置は右へ最大6マスずれることになります。

Excelの説明画像

つまり、どの曜日にずれても7日分の枠(1週間分)を確保できるようにします。

「基本の7列 + ズレしろの6列 = 13列」が必要になるのです。

2. 縦が6行の理由: 例えば2026年3月のように、「1日が日曜日(一番右)」で「31日まである」月を考えます。

この場合、行数が押し出されて6週目に突入します。
そのため、縦は最大サイズの6行を用意しておく必要があります。

Excelの説明画像

イメージとしては上の図のような感じです。

この巨大なボードの上に「6行×7列の窓枠」を乗せます。
そして1日の曜日に合わせて横にスライド(切り出し)させるのが、今回の最大のロジックです。

SEQUENCE関数を使わない配列定数の裏技

この土台は「決して変動しない静的な数値の並び」です。

そのため、もっと関数を減らしたい方や古いExcelを使っている方に朗報です。

数式内に直接「配列定数」として以下のように書くことも可能です。

={-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7} + {0;1;2;3;4;5} * 7

Excelの説明画像

この参照表は未来永劫変わらないため、配列定数を使うのは非常に理にかなったスマートな選択肢です。


ステップ2:「横移動」の量と「月の日数」を計算する

次に、どの位置を切り出すか(スライドさせるか)を計算するための入力欄を作ります。

※例として、2026年3月のカレンダーを作ります。

A9セルに「年」、B9セルに「2026」と入力。
A10セルに「月」、B10セルに「3」と入力してください。

さらに、A12セルに「横移動」、A13セルに「日数」と見出しを作ります。

Excelの説明画像

「横移動」を計算する

切り出す範囲は、I2:O7を基準(一番右側)として、そこから左(マイナス方向)へスライドしていく形を取ります。

そのほうが、月→火→水…という並びの計算が直感的に行いやすいからです。

B12セルに以下の数式を入力します。

=MOD((B9 & "/" & B10 & "/1") * 1 - 2 + (B9=1900) * (B10<=2), 7)

【数式の解説】

(B9 & "/" & B10 & "/1") * 1:年と月を結合して「2026/3/1」という文字列を作ります。

そこに *1 を掛けることで、Excelに型変換をさせます。

Excelの説明画像

「これは単なる文字ではなく日付データ(シリアル値)ですよ」と認識させているのです。

- 2MOD(..., 7):Excelのシリアル値は、1900年1月1日(日曜日)を「1」としてカウントが始まります。

このシリアル値をそのまま7で割った余り(MOD)を求めると、土曜=0、日曜=1、月曜=2…という数字が返ってきます。

Excelの説明画像

しかし今回は「月曜始まり(月曜=0、火曜=1…日曜=6)」というスライド量(オフセット値)を求めたいのです。

そこで、シリアル値から「2」を引き算してから7で割ります。

そうすることで、曜日と余りの関係を月曜=0になるように意図的にズラしているというわけです。

Excelの説明画像

【重要】1900年うるう年問題への対応

+(B9=1900)*(B10<=2) の部分:実はExcelには有名なシリアル値のバグがあります(1900年うるう年問題)。

「1900年はうるう年ではないのに、1900年2月29日が存在すると思い込んでいる」というものです。

Excelの説明画像

かつて表計算ソフトの覇権を握っていた「Lotus 1-2-3」というソフトに存在したバグでした。

Excelが互換性を重視するあまり意図的に引き継いだという歴史的背景があります。

「1900年のカレンダーなんて作らないからいいや」と無視するのは簡単です。

しかしExcelというプラットフォームで遊ぶ以上、この仕様の穴まで完璧に塞ぐのが筆者のこだわりです。この部分は、そのバグによる曜日のズレを補正するための処理です。

Excelの説明画像

「月の日数」を計算する

続いて、その月が何日まであるのか(28〜31日)を求めます。
B13セルに以下の数式を入力します。

=(B9 + (B10=12) & "/" & MOD(B10, 12) + 1 & "/" & 1) * 1
-(B9 & "/" & B10 & "/" & 1) * 1 - (B9=1900) * (B10=2)

【数式の解説】

基本ロジックは「翌月の1日のシリアル値から、当月の1日のシリアル値を引き算する」というものです。

ここでも文字列に *1 を掛けてシリアル値に変換し、引き算を行うことでその月の日数を算出しています。

B9 + (B10=12) MOD(B10, 12) + 1:もし月が「12月」だった場合、翌月は「13月」になってしまいます。

そのため、年を+1して、月を1月にリセットする処理を施しています。

Excelの説明画像

-(B9=1900)*(B10=2):ここでも1900年うるう年問題への対応です。

Excelは1900年2月が29日まであると信じ込んでいるため、強制的に-1して正しい「28日」に修正しています。

Excelの説明画像

ステップ3:OFFSET関数でカレンダーを切り出す!

スライドする量(横移動)と、月の日数が求まりました。
いよいよカレンダーを画面に表示させます。

【重要なテクニック】

E9セルに「月」と入力し、そのままK9セルまで右にオートフィル(ドラッグしてコピー)してください。

Excelの説明画像

「月、火、水…」と1セルずつ手打ちするよりも、圧倒的に早く入力できます。

では、曜日の下であるE10セルに、以下の数式を入力しましょう。

=IF((OFFSET(I2, , -B12, 6, 7) >= 1) * (OFFSET(I2, , -B12, 6, 7) <= B13), OFFSET(I2, , -B12, 6, 7), "")

切り出しのメカニズム

【数式の解説】

OFFSET関数は、基準となるセルから指定した分だけ移動し、好きな大きさの範囲を切り取ってくる関数です。

ここでは、I2セル(土台の右側)を基準にします。
そして、-B12(横移動分だけ左へ)スライドさせ、高さ6行・幅7列の「窓枠」を切り出しています。

Excelの説明画像

そしてIF関数を使い、「1以上」かつ「B13(月の日数)以下」の数値だけを残します。
それ以外のマイナスの数値や32などの存在しない日付は「空白(””)」にして隠しているのです。

Excelの説明画像

試しに、B9とB10の年・月を色々と変えてみてください。
見事に正しいカレンダーが切り替わりますね!1900年の2月を表示しても、バッチリ28日までになっています。

見栄えの調整と注意点

【見栄えのワンポイント】
条件付き書式等を使って、お好みで文字色を指定すると良いでしょう。
例えば土曜日の列は青色、日曜日の列は赤色などです。

さらにカレンダーらしく見やすくなりますのでぜひ試してみてください!

Excelの説明画像

【注意】OFFSETは「揮発性関数」
OFFSET関数は非常に便利で、スライドする感覚が直感的にわかりやすいのがメリットです。

しかしこれは、シート上のどこかのセルが更新されるたびに毎回再計算が行われる「揮発性関数」です。

そのため、大量に使用するとExcelの動作が重くなる原因になります。


ステップ4:INDEX関数に置き換えて高速化する

揮発性関数を避けるために、OFFSETINDEX関数に置き換えてみましょう。

E10セルの数式を以下のように書き換えます。

=IF((INDEX(C2#, SEQUENCE(6), 7 - B12 + SEQUENCE(, 7, 0)) >= 1) * (INDEX(C2#, SEQUENCE(6), 7 - B12 + SEQUENCE(, 7, 0)) <= B13), INDEX(C2#, SEQUENCE(6), 7 - B12 + SEQUENCE(, 7, 0)), "")

少し長くなりましたが、これなら揮発性関数を使用していないため動作が非常に高速です。

Excelの説明画像

INDEX関数の高度な配列渡し

【数式の解説】
INDEX関数の第2引数(行番号)や第3引数(列番号)に、単一の数値ではなく SEQUENCE(6)SEQUENCE(, 7, 0) のような「配列」を渡している点に注目してください。

初心者の方には少し難しく感じるかもしれません。

これは「1行目から6行目まで全部」「特定の列から7列分全部」を同時に指定しているという意味です。

すなわち、巨大な土台の中から指定したサイズのブロック(窓枠)をごっそりと一気に切り出して表示することができるのです。

詳しくは以下の記事で解説しています。

また、INDEXの第1引数には直接「配列」を渡すことができます。

そのため、実はわざわざC2セルに土台を作る必要はありません。

数式の中に土台ごと組み込んでしまうことが可能なのです。


ステップ5:究極の1セル完結・レガシー関数版カレンダー

最後に、作業セル(巨大な土台)を一切作らない方法をご紹介します。
SEQUENCE関数も使わない「究極の1セル完結数式」です。

動的に変化しない連番などはすべて「配列定数」で直書きします。
これにより、Excel 2019以前のバージョンでも動くように設計しました。

※Excel 2019以前のバージョンをお使いのユーザーへ:
この数式を使用する場合は、E10:K15の6行7列の範囲をあらかじめ選択してから数式バーに入力します。
最後に Ctrl + Shift + Enter (CSE) で配列数式として確定してください。

=IF(
(INDEX({-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7}+{0;1;2;3;4;5}7, {1;2;3;4;5;6}, 7-MOD((B9&"/"&B10&"/1")1-2+(B9=1900)*(B10<=2),7)+{0,1,2,3,4,5,6}) >= 1) *
(INDEX({-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7}+{0;1;2;3;4;5}7, {1;2;3;4;5;6}, 7-MOD((B9&"/"&B10&"/1")1-2+(B9=1900)(B10<=2),7)+{0,1,2,3,4,5,6}) <= (B9+(B10=12)&"/"&MOD(B10,12)+1&"/"&1)1-(B9&"/"&B10&"/"&1)1-(B9=1900)(B10=2)),
INDEX({-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7}+{0;1;2;3;4;5}7, {1;2;3;4;5;6}, 7-MOD((B9&"/"&B10&"/1")1-2+(B9=1900)*(B10<=2),7)+{0,1,2,3,4,5,6}),
""
)

究極の数式の正体

とてつもなく長い数式に見えますが、アレルギー反応を起こす必要はありません。

今までステップごとに別々のセルで計算していた『土台』『横移動』『日数』の数式を、そのまま1つに合体(ネスト)させただけのものです。

中身はIFINDEXMODという、誰もが知っているであろう超基本的な3つの関数だけで構成されています。

これらの関数は、約30年前の「Excel 3.0」という大変古いバージョンから存在し続けているものです。
その気になれば昔から万年カレンダーは錬成できたのです。

変動しない連番や固定の数値であれば、わざわざ関数で呼び出さずに「配列定数」を使います。
これが、パフォーマンス面において最善の選択肢と言えるでしょう。

Excelの説明画像

おわりに:この「縛りプレイ」がもたらす圧倒的な恩恵

今回はDATEWEEKDAYといった専用関数を一切使わずにカレンダーを錬成しました。

「普通にカレンダーを作るだけなら無駄な努力だ」と思うかもしれません。

しかし、この配列パズルを理解できると実務で役立ちます。
以下のような圧倒的な能力が身につきます。

1. 「シリアル値」の真の理解と制御力:
日付の正体が単なる数値(1900年1月1日を「1」とした連番)であるという本質に気づけます。
四則演算とMOD関数だけで自在に曜日や日数を操作できるのです。
これにより、複雑な営業日計算や、独自のカレンダーシステム構築に迷いがなくなります。

2. 2次元配列の自由な抽出スキル(INDEXの極意):
巨大なマスター表から、特定の条件に合わせて任意のサイズのブロック(窓枠)を切り出します。
この技術は、ダッシュボードの作成や動的なデータ分析において最強の武器になります。

3. システムとしての例外処理(デバッグ)能力:
1900年バグのような「システムの仕様の穴」を数式内で論理的に塞ぐアプローチをとりました。
これは、エラーに強く壊れにくい関数を設計するプログラミング的思考そのものです。

用意された便利機能(関数)を使うだけでなく、その裏側にあるロジックを自分で再現してみる。

そこには、Excelを極めるための無限の面白さが詰まっています。
ぜひご自身のシートでも試してみてください!

タイトルとURLをコピーしました