環境・前提条件
- TypeScript: 5.4.5
- Node.js: 20.12.2
- Wrangler: 3.53.1
- Cloudflare D1(SQLite互換エンジン)
- date-fns: 3.6.0
この記事の要点
- 法定期限の起算点は「事実が起きた日」ではなく「知った日」です。死亡日から計算すると全期限がずれます。
- 起算点は期限ごとに違います。3か月と10か月は相続開始を知った日、3年は所有権の取得を知った日が起点です。
- 施行前にさかのぼる経過措置は相対計算で表せません。日付定数として持ち、根拠を併記します。
相続手続きの複数の法定期限を、D1でどうデータモデル化するか?
起算日となる日付を物理保持し、各法定期限はクエリまたは関数側で導出します。ただし起算日は1つではありません。ここを1本にまとめると、全期限が同じ幅だけずれます。
最初に作ったスキーマは date_of_death(死亡日)だけを持ち、3か月・10か月・3年をすべてそこから計算していました。動作はしますが、法律上は誤りです。
- 相続放棄の熟慮期間(3か月)… 自己のために相続の開始があったことを知った時から(民法915条1項)
- 相続税の申告・納付(10か月)… 相続の開始があったことを知った日の翌日から(相続税法27条1項)
- 相続登記の申請義務(3年)… 所有権を取得したことを知った日から(不動産登記法76条の2第1項)
疎遠な親族の相続では、死亡から数か月後に通知で知ることが珍しくありません。死亡日を起点にすると、実際にはまだ数か月残っている案件を「期限切れ」と表示します。逆に、遺産分割の成立で初めて所有権を取得した不動産では、死亡日起点は期限を早く見積もりすぎます。
CREATE TABLE inheritance_cases (
id TEXT PRIMARY KEY,
deceased_name TEXT NOT NULL,
date_of_death TEXT NOT NULL, -- 相続開始日。事実の記録であり、期限の起算日ではない
date_known TEXT NOT NULL, -- 自己のために相続の開始があったことを知った日
created_at TEXT DEFAULT (DATETIME('now'))
);
CREATE TABLE inheritance_properties (
id TEXT PRIMARY KEY,
case_id TEXT NOT NULL REFERENCES inheritance_cases(id),
property_type TEXT NOT NULL CHECK (property_type IN ('land', 'building', 'condo')),
address TEXT NOT NULL,
-- 所有権の取得を知った日。遺産分割で確定する場合、date_known より後になる
date_acquisition_known TEXT NOT NULL,
registration_status TEXT DEFAULT 'pending'
CHECK (registration_status IN ('pending', 'completed')),
registered_at TEXT
);
date_known を NOT NULL にしているのは、値が無いときに死亡日で代用させないためです。NULL 許容にすると COALESCE(date_known, date_of_death) を書きたくなり、そこから誤りが戻ります。分からない場合は入力の時点で確認する、という運用に倒します。
SQLiteの日付関数仕様は公式ドキュメント( https://www.sqlite.org/lang_datefunc.html )を参照しています。
月末日や閏年が絡む相対日付計算を、TypeScriptでどう安全に行うか?
date-fns の addMonths / addYears を使い、月ごとの日数差と閏年による繰り上がりを解決します。
民法143条1項は「週、月又は年によって期間を定めたときは、その期間は、暦に従って計算する」と定めます。応当する日が無い月の扱いは同条2項ただし書で、「月又は年によって期間を定めた場合において、最後の月に応当する日がないときは、その月の末日に満了する」とされています。JavaScript標準の Date で setMonth(getMonth() + 3) を実行すると、1月31日は3月3日(閏年なら3月2日)へ繰り越されます。date-fns は末日へ丸めるため、この規定と一致します。
import { addMonths, addYears, format, isBefore, max, parseISO } from 'date-fns';
/** 相続登記義務化の施行日(改正不動産登記法)。 */
const ENFORCEMENT_DATE = parseISO('2024-04-01');
/**
* 施行前に開始した相続の登記期限。
*
* 施行日から3年という経過措置だが、法務省の案内では2027年3月31日とされている。
* addYears(施行日, 3) は 2027-04-01 を返すため、計算結果とは1日ずれる。
* 初日不算入(民法140条)の扱いによる差なので、**計算せず公表値を定数で持つ**。
* 出典: 法務省「相続登記の申請義務化について」
*/
const TRANSITION_DEADLINE = '2027-03-31';
export interface DeadlineInput {
/** 自己のために相続の開始があったことを知った日 */
dateKnown: string;
/** 所有権を取得したことを知った日(物件ごと) */
dateAcquisitionKnown: string;
}
export interface InheritanceDeadlines {
renunciationDeadline: string; // 相続放棄・限定承認(3か月)
taxFilingDeadline: string; // 相続税の申告・納付(10か月)
registrationDeadline: string; // 相続登記(3年/経過措置あり)
}
export function calculateDeadlines(input: DeadlineInput): InheritanceDeadlines {
const known = parseISO(input.dateKnown);
const acquired = parseISO(input.dateAcquisitionKnown);
// 施行前に取得を知った場合は経過措置。施行後なら知った日から3年。
const registration = isBefore(acquired, ENFORCEMENT_DATE)
? TRANSITION_DEADLINE
: format(addYears(acquired, 3), 'yyyy-MM-dd');
return {
// 「知った時から3か月」。初日不算入と応当日前日満了が相殺し、知った日+3か月に一致する
renunciationDeadline: format(addMonths(known, 3), 'yyyy-MM-dd'),
// 「知った日の翌日から10か月」。翌日起算が明示されているため、知った日+10か月に一致する
taxFilingDeadline: format(addMonths(known, 10), 'yyyy-MM-dd'),
registrationDeadline: registration,
};
}
経過措置を max(施行日, 取得を知った日) の相対計算で表そうとして、公表値と1日ずれました。制度側が日付を名指ししている場合は、計算で再現しようとせず定数で持つのが安全です。ずれても例外は出ず、期限表示が1日長くなるだけなので、テストが無ければ気づけません。
関数仕様の詳細は date-fns 公式ドキュメント( https://date-fns.org/docs/addMonths )に準拠しています。
登記が未完了のレコードを、D1で高速に抽出するには?
未登記ステータスと起算日の複合インデックスを定義し、期限が近い案件を絞り込みます。経過措置があるため、期限はCASE式で分岐させます。
CREATE INDEX idx_properties_status
ON inheritance_properties(registration_status, date_acquisition_known);
-- 登記期限まで90日を切った未登記物件
SELECT
p.id AS property_id,
p.address,
CASE
WHEN p.date_acquisition_known < '2024-04-01' THEN '2027-03-31'
ELSE date(p.date_acquisition_known, '+3 years')
END AS registration_deadline
FROM inheritance_properties p
WHERE p.registration_status = 'pending'
AND CASE
WHEN p.date_acquisition_known < '2024-04-01' THEN '2027-03-31'
ELSE date(p.date_acquisition_known, '+3 years')
END <= date('now', '+90 days')
ORDER BY registration_deadline ASC;
CASE式をWHERE句に書くとインデックスが効きません。件数が増えたら、期限を生成列(GENERATED ALWAYS AS ... STORED)として保持し、そこにインデックスを張る形へ移します。派生値を持たない原則より、誤りなく速く引けることを優先する判断です。ただし生成列にすると経過措置の定数がスキーマに焼き付くため、制度改正時の移行手順を残しておく必要があります。
Cloudflare D1のインデックス設計は公式ドキュメント( https://developers.cloudflare.com/d1/platform/client-api/ )に基づきます。
法定期間の根拠
相続放棄(3か月)は民法915条1項、相続税の申告・納付(10か月)は相続税法27条1項および国税庁「No.4205 相続税の申告と納税」、相続登記の申請義務(3年・2024年4月1日施行)は不動産登記法76条の2第1項、施行前の相続に関する経過措置(2027年3月31日)は法務省「相続登記の申請義務化について」に基づきます。
本記事のコードは実装例であり、個別の期限判断は司法書士・税理士にご確認ください。
この記事は株式会社HY(横浜・湘南/不動産・相続)の社内システム開発の記録です。
訂正(2026-09-03): 公開時、期間計算の根拠を「民法143条2項」と書いていましたが、「暦に従って計算する」は同条1項です。2項は応当日・末日の規定でした。該当箇所を条文の原文に差し替えています。ご指摘をいただく前の自主点検で見つけたものです。