DATEDIF 完全ガイド:隠し関数の落とし穴と安全な年齢・勤続計算
― MDバグの正体・終了日+1の是非・パワークエリの罠まで ―
📖 この記事の内容
1 やりたいこと
生年月日から現在の「満年齢」を計算したい。あるいは、入社日から現在までの「勤続年数」を「◯年◯ヶ月」というフォーマットで表示させたい。Excelで日付の差を「年・月・日」の単位で分解する定番がDATEDIF関数ですが、この関数には見過ごせない落とし穴があります。
2 DATEDIF関数の基本構文と全6単位
開始日と終了日の間の期間を、指定した単位で返す。開始日 ≦ 終了日でなければ #NUM! エラー。
全6単位の一覧
| 単位 | 意味 | 例(2000/8/10 → 2026/4/5) | 安全性 |
|---|---|---|---|
| "Y" | 満年数 | 25 | ✅ 安全 |
| "M" | 満月数(トータル) | 307 | ✅ 安全 |
| "D" | 日数(トータル) | 9370 | ✅ 安全 |
| "YM" | 1年に満たない月数(端数の月) | 7 | ✅ 安全 |
| "YD" | 1年に満たない日数(端数の日) | 238 | ❌ 使用禁止 |
| "MD" | 1月に満たない日数(端数の日) | バグあり | ❌ 使用禁止 |
基本例:満年齢の計算
A1 に生年月日がある場合、今日時点の満年齢を返す。誕生日にカウントアップされます。
基本例:◯年◯ヶ月のフォーマット
→ "25年7ヶ月" のように表示される。
4 致命的な「MD」「YD」単位のバグ ― 実例で検証
"MD"(1月に満たない日数)と "YD"(1年に満たない日数)には、うるう年を挟む計算でマイナス値や明らかに間違った値が返るバグが存在します。Microsoftの公式ドキュメントでも「誤った計算結果を返すことがある」と明記されています。+1 でも回避できないため、使用そのものを禁止すべきです。
"MD" のバグ実例
| A(開始日) | B(終了日) | C(DATEDIF "MD") | D(正しい日数) | |
| 1 | 2026/1/31 | 2026/3/1 | -2 | 1 |
| 2 | 2026/3/31 | 2026/5/1 | -2 | 1 |
| 3 | 2025/5/31 | 2025/7/1 | 0 | 1 |
| 4 | 2026/1/29 | 2026/3/1 | -1 | 1 |
"YD" のバグ実例
| A(開始日) | B(終了日) | C(DATEDIF "YD") | D(正しい日数) | |
| 1 | 2015/1/1 | 2016/2/29 | 59 | 59(OK) |
| 2 | 2015/1/1 | 2016/3/1 | 59 | 60 |
うるう年の3月1日以降、1日のズレがその年中ずっと続く。
"MD" の内部計算は「終了日の日 - 開始日の日」に近い単純な引き算をしているとされています。しかし月によって日数が異なる(28日、30日、31日)ため、月末を跨ぐと辻褄が合わなくなります。"YD" も同様にうるう年の366日目を正しく処理できません。これらのバグは初期バージョンから存在し、互換性のために修正されないまま現在に至っています。
5 DATEDIFを使わない年齢計算(安全版)
DATEDIFの "Y" 単位は安全に使えますが、「隠し関数に頼りたくない」「他の人が見たときに関数名がわからない」という場合は、以下のTEXT関数を使った方法が定番です。
例えば今日が「2026年4月5日(20260405)」、生年月日が「2000年8月10日(20000810)」だとしたら、引き算をします。
20260405 - 20000810 = 259595これを 10000 で割って小数点以下を切り捨てる(INT)と
25 になります。誕生日がまだ来ていない場合(例:今日が2026/4/5、生年月日が2000/12/25)は
20260405 - 20001225 = 259180 → INT(25.918) → 25 と、きちんと「まだ26歳になっていない」状態を正しく返します。この方法はうるう年の2月29日生まれでも正しく動作します。日付を8桁の数値に変換して比較するだけなので、月の日数に依存しません。
DATEDIF版との比較
DATEDIF版
=DATEDIF(A1, TODAY(), "Y")
・短くて読みやすい
・入力補完が効かない
・知らない人が見ると「何この関数?」
・2/29生まれの判定が業務ルールと合うか確認が必要
TEXT版(安全版)
=INT((TEXT(TODAY(),"yyyymmdd")-TEXT(A1,"yyyymmdd"))/10000)
・隠し関数に依存しない
・+1 なども不要でそのまま安全
・数式の長さがやや長い
・アルゴリズムが明快で説明しやすい
6 安全な「◯年◯ヶ月◯日」の出し方
「◯年◯ヶ月◯日」を出したい場合に "MD" は使えません。「日」の部分だけ安全な方法で計算する必要があります。
方法① DATEDIFの "Y" と "YM" は使い、"日" だけ手計算する
方法② LET で読みやすく整理する
7 「終了日+1」の判断基準 ― 年齢 vs 期間計算
DATEDIFで最も間違いやすいのが「終了日に +1 するかどうか」の判断です。計算の目的によって正解が変わります。
① 満年齢・勤続年数計算の場合
一般的な年齢計算では、原則として +1 は行わず TODAY() をそのまま使います。
例えば、生年月日が「2000/4/27」、今日が「2026/4/26」の場合、この人はまだ25歳です。しかし
TODAY()+1 を使うと、内部的な基準日が「2026/4/27」となり、誕生日前日なのに26歳と判定されてしまいます。
② 契約期間・プロジェクト期間(両端含み)の場合
一方で、「開始日から終了日まで当日を含めてカウントする」業務では、終了日に +1 を検討します。
Excelの日付は内部的に「その日の0時0分」を指しています。そのため「1/1から1/1」をDATEDIFで計算すると 0日 になります。当日を含めて「1日間」としたい場合は 終了日+1 または 結果に+1 が必要です。
・満年齢・勤続年数:原則
TODAY()。誕生日にカウントアップ。・契約期間・工数計算:
終了日+1。最終日当日を期間に含める場合。・法的な年齢計算:誕生日前日の24時に加齢するため、実務上あえて
+1 を使うケースもありますが、一般的な表示では不要です。
8 開始日 > 終了日のエラー処理
DATEDIFは開始日が終了日より未来の場合、#NUM! エラーを返します。未来の日付が混在するリストを処理する場合にはエラー処理が必要です。
9 実務パターン集
パターン① 社員名簿の年齢列
A列に生年月日があれば、誕生日当日にカウントアップされる一般的な満年齢を表示します。
パターン② 勤続年数を「◯年◯ヶ月」で表示
パターン③ 契約期間の残月数(◯ヶ月残り)
B列に契約終了日。当日を含めて数えるため B2+1 としています。
パターン④ 特定の日付時点での年齢(基準日指定)
年度初め(4月1日)時点での年齢一覧表作成などに。
10 パワークエリで年齢計算する場合の注意
パワークエリの「列の追加 → 日付 → 期間」で求めた日数を 365 で割る方法は、うるう年の影響でズレが累積します。
日数を単純に 365 で割ると、4年に1度のうるう年(+1日)が考慮されません。40年間の期間計算では、誕生日の10日も前に歳をとってしまうという致命的な誤差が生じます。
正確な年齢が必要な場合は、パワークエリ内で M言語のカスタム関数(年の差を出し、月日で判定するロジック)を実装するか、読み込んだ後のワークシート上で DATEDIF / TEXT版関数を使うのが安全です。
11 方式比較表
| 比較項目 | DATEDIF "Y" | TEXT版(INT÷10000) | パワークエリ(÷365) |
|---|---|---|---|
| 数式の長さ | 短い | やや長い | GUI操作 |
| 安全性 | ✅ 正しく使えば安全 | ✅ 完全に安全 | ❌ うるう年でズレる |
| 他人への説明 | 隠し関数という説明が必要 | アルゴリズムが明快 | 直感的だが罠あり |
| おすすめ用途 | 年齢・勤続(年/月) | 年齢のみ(共有用) | 大雑把な傾向分析のみ |
12 まとめ
① DATEDIFは入力補完に出ない「隠し関数」。スペルは DATEDIF(Fは1つ)。
② "MD" と "YD" はバグがあるため絶対に使わない。日は手計算で回避する。
③ 満年齢計算は原則 TODAY()。誕生日前日に加齢させないよう注意する。
④ 契約期間など、終了日当日を数に含めたい業務のみ
終了日+1 を検討する。⑤ パワークエリの ÷365 方式は不正確。法定書類など正確さが求められる場面では避ける。