Excelの空いたセルに、こう打ってみてほしい。
=DATE(1900,2,29)
「1900/2/29」と返ってくる。
1900年は閏年ではない。2月は28日で終わっている。それなのに、Excelはこの日を持っている。
バグではある。ただしMicrosoftはそれを知っていて、意図的に直さないと公式に書いている。理由をたどると、1983年のライバル製品にぶつかった。
この記事は育ちます。公開後も、会話パート・トーク・補足を足していきます。
公開 2026-09-29 / 最終更新 2026-09-29(公開)
水深 — 日付は、ただの数字だった
前提から。Excelの日付は、内部ではただの整数だ。
セルに「2026/9/29」と入れて、書式を「標準」に戻すと 46295 のような5桁の数字が出てくる。あれが正体だ。
- 1900年1月1日 = 1
- そこから1日ごとに1ずつ増える
これをシリアル値という。時刻は小数部分で、0.5が正午。「2026/9/29 12:00」は 46295.5 になる。
日付を数字にしておくと、引き算がそのまま日数になる。請求日と入金日を引けば滞留日数が出る。これは便利な設計だ。
59、60、61 — ここで一段ずれる
問題はここからだ。1900年の前半を、シリアル値で並べてみる。
| シリアル値 | Excelの表示 | 実際の暦 |
|---|---|---|
| 59 | 1900/2/28 | 1900年2月28日 |
| 60 | 1900/2/29 | 存在しない |
| 61 | 1900/3/1 | 1900年3月1日 |
60番が、存在しない日に割り当てられている。
そのぶん、1900年3月1日以降のシリアル値は、本来より1つ大きい。ずっと1つずれたまま、今日まで来ている。
なぜ1900年が閏年でないのか、念のため書いておく。グレゴリオ暦の閏年のルールは3段構えだ。
- 4で割り切れる年は閏年
- ただし100で割り切れる年は閏年にしない
- ただし400で割り切れる年は閏年にする
1900年は100で割り切れて400で割り切れないので、閏年ではない。逆に2000年は400で割り切れるので閏年だった。
だから「4で割り切れたら閏年」とだけ実装したプログラムは、2000年には正解してしまう。ぼろが出るのは1900年だけだった。

犯人は、1983年のLotus 1-2-3
Microsoftのサポート文書「Excel では、1900 年が閏年であると誤って想定しています」に、経緯がそのまま書いてある。
要点はこうだ。
- Lotus 1-2-3が最初にリリースされたとき、1900年を閏年と誤って想定した
- それは実装を簡略化するためで、ほとんどの日付計算には悪影響がなかった
- MultiplanとExcelがリリースされた時点で、Lotus 1-2-3と同じシリアル日付システムを使うことにした
- 目的は互換性。ユーザーがワークシートをプログラム間で移せるようにするため
Lotus 1-2-3は1983年のソフトだ。当時の表計算の標準で、IBM PCを売った製品と言われた。後発のExcelは、そこに合わせるしかなかった。
間違いを引き継ぐことが、当時は正しい設計判断だった。
Microsoftは、直さない理由を明記している
面白いのはその先だ。同じ文書に、直さない理由が書いてある。
要約するとこうなる。
直した場合に起きること
- 既存のワークシートの日付が、ほぼ全部1日ずつずれる
- WEEKDAY関数などが違う値を返し、数式が壊れる
- 他のプログラムとのシリアル値の互換性が失われる
直さない場合に起きること
- WEEKDAY関数が、1900年3月1日より前の日付に対して正しくない値を返す
それだけだ。
1900年2月以前の曜日を計算する人はほとんどいない。だから欠点が利点を上回るという判断で、40年そのままになっている。
ソフトウェアの「互換性のために残した仕様」の、たぶん一番有名な例だと思う。
実害が出るのは、どこか
では実務で困るか。ほとんど困らない。理由はずれ方が一定だからだ。
1900年3月1日より後の日付どうしなら、両方が同じだけずれているので、引き算の結果は正しい。日数計算も、期間計算も、合っている。
狂うのは次の2つだけだ。
- 1900年2月29日をまたぐ期間の日数
- 1900年3月1日より前の日付の曜日
明治33年の話をExcelで計算する機会は、まずない。
ただし、別のシステムから移したときに1日ずれることはある。Excel以外のソフトは1900年2月29日を持っていないので、シリアル値をそのまま渡すと食い違う。日付は数値でなく文字列(YYYY-MM-DD)で受け渡すのが安全だ。
1900年1月0日、というものもある
ついでにもうひとつ。
シリアル値 0 は、Excelでは「1900/1/0」と表示される。
0日という日はない。これは「1900年1月1日の前日」を置いておくための席だ。負の日付を扱わない設計にしたので、0が余った。
つまりExcelには、存在しない日が2つある。1900年1月0日と、1900年2月29日だ。
そして1900年1月1日より前の日付は、そもそもシリアル値にできない。「1899/12/31」と打つと、日付ではなく文字列として左寄せで入る。明治の日付を扱う台帳をExcelで作ると、ここで止まる。

Macには、別の暦が用意されている
もうひとつ、日付がずれる有名な落とし穴がある。1904年日付システムだ。
初期のMacintoshは、1904年1月1日を起点にしていた。1900年が閏年でないという例外処理を避けるための選択だったとされる。その名残で、Mac版Excelには「1904年から計算する」オプションが残っている。
- 1900年日付システム 1900/1/1 = 1
- 1904年日付システム 1904/1/1 = 0
差は1,462日。
この設定が違うブック同士でセルをコピーすると、日付が4年と1日ずれる。原因が分からないまま「なぜか4年ずれる」と悩む事故が、これだ。
設定はブック単位で保存される。Excelのオプションの「このブックを計算するとき」に「1904年から計算する」というチェックがあり、それが入っているかどうかで変わる。
2桁の年を打ったときに何が起きるか
日付まわりでもうひとつ。年を2桁で打ったときの解釈だ。
Excel(正確にはWindows)の既定では、こうなっている。
- 00〜29 → 2000年〜2029年
- 30〜99 → 1930年〜1999年
「25/4/1」は2025年4月1日。「45/4/1」は1945年4月1日になる。
昭和45年のつもりで打つと1945年になり、令和45年のつもりで打っても1945年になる。和暦を2桁で打つ癖がある現場では、これが地味に効く。
そして境目は29と30のあいだにある。いまは2026年なので「30」と打てば1930年だが、この区切り自体はWindowsの設定で変えられる。年を4桁で打つのが唯一の予防策になる。
日付が突然5桁の数字になる、あれ
実務でいちばん遭遇するのは、たぶんこれだ。
セルをコピーしたら、日付が「46295」になった。
これはシリアル値が見えているだけで、データは壊れていない。書式が「標準」に戻っただけだ。セルの表示形式を「短い日付形式」に変えれば戻る。
逆のパターンもある。日付を入れたつもりのセルが左寄せになっていたら、それは文字列だ。計算に使えない。この場合はシリアル値になっていないので、書式を変えても日付にはならない。0を足すか、区切り位置機能で日付として読み直す必要がある。
見分け方は単純で、右寄せなら数値(=日付)、左寄せなら文字列。セルの中身を疑うときは、まずこれを見る。
CSVで日付が壊れる理由
CSVをExcelで開くと日付が変わってしまう、という話もここにつながる。
CSVはただのテキストだ。日付かどうかの情報は入っていない。Excelは開くときに「これは日付っぽい」と推測して、シリアル値に変換する。
だから起きる。
- 「2026-09-29」→ 日付として解釈される(たいてい正しい)
- 「9/29」→ その年の9月29日として解釈される(年が勝手に補われる)
- 商品コードの「3-1」→ 3月1日になる
- 「1-2-3」のような型番も日付候補になる
これを止めるには、ダブルクリックで開かずに、データタブの「テキストまたはCSVから」で読み込んで、列ごとに「文字列」を指定する。ここを癖にしておくと、事故が半分くらい減る。

他のソフトは、どうしているか
この「1900年2月29日」を、他の表計算ソフトも持っている。
Excelファイルを読み書きする以上、同じシリアル値を返さないと計算が合わないからだ。互換性のための間違いが、さらに横へ広がった形になる。
一方、プログラミング言語の側は別の起点を使っている。UNIX系の多くは1970年1月1日を0とする。こちらは1900年問題とは無関係だ。
システム間で日付を渡すときは、シリアル値のまま渡さないこと。YYYY-MM-DD の文字列にしておけば、どの環境でも同じ日を指す。
航路 — 間違いを直さないという判断
整理する。
- Excelの日付は1900年1月1日を1とした整数。時刻は小数
- シリアル値60が、存在しない1900年2月29日に割り当てられている
- 発端はLotus 1-2-3。Excelは互換性のために同じ間違いを採用した
- Microsoftは公式に、直すと既存の全ファイルがずれるので直さないと書いている
- 実害は「1900年3月1日より前の曜日」だけ
- 1904年日付システムと混ざると4年と1日ずれる
- 2桁の年は 00〜29が2000年台、30〜99が1900年台
- 日付が5桁の数字に見えるのは、書式が標準に戻っただけ
いちばん面白かったのは、Microsoftの文書のトーンだった。
「間違っています」と認めたうえで、「直すほうが害が大きいので直しません」と、淡々と書いてある。謝ってもいないし、隠してもいない。
40年前の互換性のために、存在しない日が今日も残っている。毎日開いているソフトの中に、そういう地層がある。
シリアル値が分かると、できるようになること
ここまで欠陥の話をしてきたが、シリアル値という仕組み自体はよくできている。日付が数字だと分かっていると、手作業が一気に減る。
月末を出す
請求書の支払期日を「翌月末」にしたい、というのは経理の定番だ。
- =EOMONTH(A1,0) → A1の月の末日
- =EOMONTH(A1,1) → 翌月の末日
EOMONTHを知らなくても出せる。=DATE(YEAR(A1),MONTH(A1)+1,0) でいい。「0日」は「前月の末日」として解釈されるからだ。存在しない0日が、ここで役に立つ。
月をまたぐときも、13月と書けば勝手に翌年1月になる。シリアル値が連続した数字だから、はみ出した分が自動で繰り上がる。
営業日を数える
- =NETWORKDAYS(開始,終了,祝日リスト) → 土日と祝日を除いた日数
- =WORKDAY(開始,日数,祝日リスト) → 何営業日後か
祝日リストは自分で作る必要がある。内閣府が「国民の祝日について」のページでCSVを公開しているので、それを1列貼っておけばいい。
支払サイトの計算、締日から入金日までの日数、どちらもこれで出る。
期首からの経過日数
=A1-DATE(YEAR(A1),4,1) のように書けば、4月1日からの日数が出る。月次の進捗を日数按分したいときに使う。
引き算がそのまま日数になるのは、日付が数字だからだ。
時刻は「1日=1」なので、24時間で一周する
日付の話をしたので、時刻にも触れておく。
時刻はシリアル値の小数部分だ。1日が1なので、こうなる。
| 時刻 | 小数 |
|---|---|
| 0:00 | 0 |
| 6:00 | 0.25 |
| 12:00 | 0.5 |
| 18:00 | 0.75 |
ここから、実務でよく詰まる2つが出てくる。
① 合計が24時間で戻ってしまう
勤務時間を足していったら、合計が「4:30」になった。本当は28時間30分なのに。
原因は書式だ。「h:mm」は24時間で一周するように作られている。24時間を超える時間を表示したいときは、書式を[h]:mm にする。角括弧が「一周させるな」という指示になる。
給与計算のシートでこれを踏むと、残業代が丸ごと消える。
② 時間を数値にしたい
「7:30」を「7.5」として計算したいことがある。時給を掛けるときなどだ。
=A1*24 でいい。1日が1なので、24を掛ければ時間数になる。逆に、7.5時間を時刻表示にしたいなら =A1/24 で、書式を [h]:mm にする。
分にしたければ *1440(24×60)、秒なら *86400 を掛ける。
③ マイナスになると ##### が出る
終了時刻から開始時刻を引いて、日をまたいだ。結果がマイナスになって、セルが ##### で埋まる。
1900年日付システムは負の時刻を表示できない。これも「1900年1月1日より前がない」ことの副作用だ。
回避策は2つ。=MOD(終了-開始,1) とすると日またぎでも正しく出る。あるいは1904年日付システムに切り替えると負の時刻が扱えるようになるが、他の日付が全部ずれるのでおすすめしない。
和暦を出したいとき
日本の実務では和暦が要る場面がある。シリアル値は西暦も和暦も同じなので、書式だけで切り替えられる。
セルの書式設定でユーザー定義に、こう入れる。
- [$-ja-JP]ggge”年”m”月”d”日” → 令和8年9月29日
- [$-ja-JP]ge.m.d → R8.9.29
- [$-ja-JP]ggge”年” → 令和8年
g が1つだと「R」、2つだと「令」、3つだと「令和」になる。e が年。
注意点をひとつ。改元に対応するにはOSの更新が必要だった。令和への改元のとき、更新していないWindowsでは令和1年が「平成31年」のまま表示される現象があった。いまはほぼ解消しているが、古い端末が残っている現場では確認したほうがいい。
TEXT関数でも同じことができる。=TEXT(A1,”[$-ja-JP]ggge年m月d日”) で文字列として取り出せる。帳票に差し込むときはこちらが早い。
1900年より前を扱いたいとき
社史をまとめる、古い契約を台帳にする——そういうときに1900年より前の日付が出てくる。Excelの日付型では持てない。
やり方は3つある。
① 文字列として持つ
「1889-02-11」のようにテキストで入れる。並べ替えは、YYYY-MM-DD の形にしておけば文字列のままでも正しい順に並ぶ。桁を揃えるのがコツで、「1889-2-11」だと崩れる。
② 年・月・日を別の列に分ける
数値3列にしておけば、並べ替えも絞り込みもできる。表示用に文字列を組み立てる列を足す。集計や期間計算をしたいならこれがいちばん確実だ。
③ オフセットを足す
全部の日付に一定の年数(たとえば200年)を足してExcelの日付として扱い、表示のときだけ引く。日数計算はできるが、やっていることが分かりにくくなるので、自分以外が触るファイルには向かない。
いずれにしても、Excelの日付型は1900年からの道具だと割り切るのが早い。
ついでに — 2月29日は、そもそも扱いが難しい
1900年の話から離れるが、閏日そのものが業務で厄介になることがある。
=DATE(2027,2,29) と打つと、Excelは 2027/3/1 を返す。2027年は閏年ではないので、はみ出した1日が3月に繰り越される。エラーにはならない。
これが困るのは、契約の「1年後」を計算するときだ。2024年2月29日の1年後を =DATE(YEAR(A1)+1,MONTH(A1),DAY(A1)) で出すと、2025年3月1日になる。民法の考え方では2025年2月28日の満了とされるので、ずれる。
=EDATE(A1,12) を使うと2025年2月28日が返る。EDATEは月末を月末に合わせてくれる。契約期間の計算では、DATEよりEDATEのほうが実務に合う。
閏日生まれの人の誕生日をシステムがどう扱うか、という話にもつながっていく。ここは会社によって運用が分かれるところだ。
この記事は、まだ書きかけです
この記事は、公開してから足していく形にしています。調べたことを書いた本文がまず先にあって、あとから「聞き手と話し手の会話」「あとで思い出したこと」「読んだ人から教わった補足」が積もっていきます。
だから、同じURLでも半年後には別のものになっているはずです。もし一度読んだことがある記事なら、下の更新ログだけ見てください。増えたところが分かります。
更新ログ
- 2026-09-29 公開(本文のみ。会話パートはこれから足します)

