4月1日生まれが早生まれになる理由 — 民法143条をJSで計算

満年齢は誕生日に1つ増える、というのは日常の感覚としては正しい。ところが法律上の「満6歳に達した日」は誕生日の前日である。この1日のずれのせいで、4月1日生まれの子は3月生まれと同じ学年に入る。「早生まれ = 1〜3月生まれ」と覚えて month < 4 で判定するコードを書くと、4月1日生まれだけ1学年ずれる。

この記事では、ハシトシステムの年齢計算ツール の実装を題材に、条文(e-Gov 法令検索の法令 API で取得)を読み、「達した日」と入学年度を Node.js で計算して確かめる。

条文: 出生日から起算し、応当日の前日に満了する

年齢の数え方を決めているのは、明治35年法律第50号「年齢計算ニ関スル法律」である。本文は次の2項だけで、残り1項は旧布告の廃止規定になっている。

  • 年齢ハ出生ノ日ヨリ之ヲ起算ス
  • 民法第百四十三条ノ規定ハ年齢ノ計算ニ之ヲ準用ス

民法の期間計算は、原則として初日を算入しない(民法140条)。年齢はこの原則の例外で、生まれた日そのものを1日目として数える。そのうえで準用される民法143条2項は、期間の満了日を次のように決めている。

週、月又は年の初めから期間を起算しないときは、その期間は、最後の週、月又は年においてその起算日に応当する日の前日に満了する。ただし、月又は年によって期間を定めた場合において、最後の月に応当する日がないときは、その月の末日に満了する。

2020年4月1日生まれなら、起算日は2020年4月1日で、6年後の応当日は2026年4月1日。その前日の2026年3月31日が終わった時点で6年が満了し、満6歳に達する。誕生日当日の朝にはもう6歳になっているので、日常の「誕生日に1つ増える」と、その日の年齢としては食い違わない。食い違うのは「達した日はいつか」を問われたときだけである。

学年の境目は「達した日の翌日以後」

小学校への就学は学校教育法17条1項が決めている。

保護者は、子の満六歳に達した日の翌日以後における最初の学年の初めから、満十二歳に達した日の属する学年の終わりまで、これを小学校(略)に就学させる義務を負う。

学年の初めは学校教育法施行規則59条で4月1日と決まっている(「小学校の学年は、四月一日に始まり、翌年三月三十一日に終わる」)。これを組み合わせると次のようになる。

生年月日 満6歳に達した日 達した日の翌日 入学
2020-03-31 2026-03-30 2026-03-31 2026-04-01
2020-04-01 2026-03-31 2026-04-01 2026-04-01
2020-04-02 2026-04-01 2026-04-02 2027-04-01

4月1日生まれは「翌日」がちょうど4月1日に当たるので、その日に始まる学年に入る。4月2日生まれは「翌日」が4月2日になり、最初の学年の初めは翌年の4月1日まで待つことになる。同じ学年になるのは4月2日から翌年4月1日までに生まれた子、という区切りはここから出てくる。

2月29日生まれは2月28日に達する

143条2項のただし書は、2月29日生まれで効いてくる。平年には応当日の2月29日が無いので、その月の末日である2月28日に満了する。うるう年なら応当日2月29日の前日、つまりやはり2月28日である。どちらの年でも、2月29日生まれが年齢に達する日は2月28日になる。国立天文台暦計算室の暦Wiki「1年とは?/年齢」も、うるう年以外は2月28日の終わりに年をとると説明している。

一方、JavaScript の Date は存在しない日付を黙って繰り上げる。年齢計算ツールは次の誕生日を new Date(年, 誕生月, 誕生日) で作っているので、2月29日生まれの平年の「次の誕生日」は3月1日になる。

1
new Date(2027, 1, 29); // 2027-03-01(2月29日が無いので3月1日に繰り上がる)

ツールが表示するのは「その日時点の満年齢」と「次の誕生日まで」なので、2027年2月28日には18歳、3月1日には19歳と出る。日常の誕生日祝いとしてはこれでよいが、「満19歳に達した日」を書類に書く用途では2月28日が正しい。両者は別の問いとして扱う必要がある。

実際に試す

Node.js 24.11.1(Windows 11)で実行した。依存パッケージは要らない。日付はすべて UTC の暦日として扱い、時差や夏時間に左右されないようにしている。次の内容を age-law.mjs として保存する。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
// age-law.mjs : 満年齢・「満n歳に達した日」・小学校の入学年度を計算する
// 日付は UTC の暦日として扱い、時差や夏時間の影響を受けないようにする
const D = (y, m, d) => new Date(Date.UTC(y, m - 1, d));
const fmt = (dt) => dt.toISOString().slice(0, 10);
const addDays = (dt, n) => new Date(dt.getTime() + n * 86400000);

// 誕生日の当日に1つ増える満年齢(日常の数え方。基準日のその日の年齢)
export function ageOn(birth, ref) {
let age = ref.getUTCFullYear() - birth.getUTCFullYear();
const m = ref.getUTCMonth() - birth.getUTCMonth();
if (m < 0 || (m === 0 && ref.getUTCDate() < birth.getUTCDate())) age--;
return age;
}

// 満n歳に「達した日」: 民法143条2項(年齢計算ニ関スル法律で準用)
// 起算日(出生日)に応当する日の前日に満了。応当日が無ければその月の末日に満了
export function reachDay(birth, n) {
const y = birth.getUTCFullYear() + n;
const m = birth.getUTCMonth();
const d = birth.getUTCDate();
const lastDay = new Date(Date.UTC(y, m + 1, 0)).getUTCDate();
if (d > lastDay) return new Date(Date.UTC(y, m, lastDay)); // 応当日なし → 月末
return addDays(new Date(Date.UTC(y, m, d)), -1); // 応当日の前日
}

// 学校教育法17条: 満6歳に達した日の翌日以後における最初の学年の初め(4月1日)
export function schoolEntry(birth) {
const next = addDays(reachDay(birth, 6), 1);
let y = next.getUTCFullYear();
if (next > D(y, 4, 1)) y++;
return D(y, 4, 1);
}

// よくある実装: 1〜3月生まれを「早生まれ」として前の年度に入れる
function naiveEntry(birth) {
const fy = birth.getUTCFullYear() - (birth.getUTCMonth() < 3 ? 1 : 0);
return D(fy + 7, 4, 1);
}

// 同じ判定を「生年月日の前日」に対して行う(法の結果と一致する)
function shiftedEntry(birth) {
return naiveEntry(addDays(birth, -1));
}

const births = [D(2020, 3, 31), D(2020, 4, 1), D(2020, 4, 2), D(2020, 2, 29), D(2020, 1, 1)];
console.log('生年月日 6歳に達した日 入学(法) 1-3月判定 前日で判定');
for (const b of births) {
console.log(`${fmt(b)} ${fmt(reachDay(b, 6))} ${fmt(schoolEntry(b))} ${fmt(naiveEntry(b))} ${fmt(shiftedEntry(b))}`);
}

// 2月29日生まれ: 平年とうるう年で「達した日」と、Date の繰り上がり
const leap = D(2008, 2, 29);
for (const n of [18, 19, 20]) {
console.log(`2008-02-29 生まれが満${n}歳に達した日: ${fmt(reachDay(leap, n))}`);
}
console.log('2027-02-28 の満年齢:', ageOn(leap, D(2027, 2, 28)));
console.log('2027-03-01 の満年齢:', ageOn(leap, D(2027, 3, 1)));
console.log('new Date(2027, 1, 29) ->', fmt(new Date(Date.UTC(2027, 1, 29))));
1
node age-law.mjs

出力:

1
2
3
4
5
6
7
8
9
10
11
12
生年月日    6歳に達した日 入学(法)   1-3月判定  前日で判定
2020-03-31 2026-03-30 2026-04-01 2026-04-01 2026-04-01
2020-04-01 2026-03-31 2026-04-01 2027-04-01 2026-04-01
2020-04-02 2026-04-01 2027-04-01 2027-04-01 2027-04-01
2020-02-29 2026-02-28 2026-04-01 2026-04-01 2026-04-01
2020-01-01 2025-12-31 2026-04-01 2026-04-01 2026-04-01
2008-02-29 生まれが満18歳に達した日: 2026-02-28
2008-02-29 生まれが満19歳に達した日: 2027-02-28
2008-02-29 生まれが満20歳に達した日: 2028-02-28
2027-02-28 の満年齢: 18
2027-03-01 の満年齢: 19
new Date(2027, 1, 29) -> 2027-03-01

「1-3月判定」の列だけ、2020年4月1日生まれが2027年入学になっている。条文どおりの計算(入学(法))では2026年で、1年ずれる。生年月日を1日戻してから1〜3月判定をかける「前日で判定」は、5件とも条文どおりの結果と一致した。学年を出すだけなら、この1日戻す処理を足すのが最小の修正になる。

2020年1月1日生まれの「達した日」が2025年12月31日になっているのも、前日満了の結果である。年をまたぐので、年だけを比べる実装では見落としやすい。

実装するときの注意

  • 「その日の満年齢」と「達した日」を分ける。前者は誕生日当日に増えるとしてよく、後者は誕生日の前日(2月29日生まれは2月28日)になる。
  • 学年の判定に month < 4 を使わない。4月1日生まれが後ろの学年に入ってしまう。生年月日を1日戻してから判定するか、条文どおり「達した日の翌日以後の最初の4月1日」を計算する。
  • Date の繰り上がりに頼らない。new Date(2027, 1, 29) は例外を出さずに3月1日を返す。応当日の有無は月末日(new Date(年, 月 + 1, 0))と比べて明示的に判定する。
  • 日付は UTC の暦日で扱う。ローカル時刻の Date 同士の差を86400000で割ると、夏時間のある地域では1日の長さが23時間や25時間になり、日数がずれることがある。

まとめ

  • 年齢計算ニ関スル法律は、年齢を出生日から起算し、民法143条を準用すると定める。満了は応当日の前日で、応当日が無ければその月の末日になる。
  • 学校教育法17条は「満6歳に達した日の翌日以後における最初の学年の初め」から就学させるとしている。4月1日生まれは3月31日に6歳に達し、翌日の4月1日に始まる学年に入る。
  • 2020年4月1日生まれを month < 4 で判定すると2027年入学になり、条文どおりの2026年と1年ずれる。生年月日を1日戻してから判定すれば一致する。

条文は e-Gov 法令検索で確認できる: 年齢計算ニ関スル法律 / 民法 / 学校教育法 / 学校教育法施行規則。和暦の扱いは「Node 24のIntlは明治元年を1868年9月8日から始める」も参照。

ツール: 年齢計算(ハシトシステム)。生年月日と基準日から、その日時点の満年齢・数え年・生後日数・次の誕生日までの日数を出す。生年を和暦で確かめるときは 和暦・西暦 変換 が使える。