経過日数のゴールイメージ
「申込日から何日経った?」「納期まであと何日?」「プロジェクト開始からの経過日数は?」
業務システムだと、“2つの日付の差”=経過日数を出す場面が本当に多いです。
ここでまず押さえてほしいのは、
「経過日数は“カレンダー上で何日分進んだか”であって、“年・月・日をバラして計算するものではない” ということです。
Java では ChronoUnit.DAYS.between や LocalDate の差分を使うことで、
安全かつシンプルに「経過日数」を扱えます。
LocalDate 同士の経過日数を求める基本
ChronoUnit.DAYS.between(開始日, 終了日)
一番よく使うのがこれです。
import java.time.LocalDate;
import java.time.temporal.ChronoUnit;
public class ElapsedDaysBasic {
public static void main(String[] args) {
LocalDate start = LocalDate.of(2025, 3, 1);
LocalDate end = LocalDate.of(2025, 3, 10);
long days = ChronoUnit.DAYS.between(start, end);
System.out.println("開始日 : " + start); // 2025-03-01
System.out.println("終了日 : " + end); // 2025-03-10
System.out.println("経過日数 : " + days); // 9
}
}
Javaここで重要なのは、between(start, end) は「start から end までに“何日分進んだか”」を返す という点です。
3/1 の翌日は 3/2 なので 1 日経過、
3/10 の前日は 3/9 なので、3/1→3/10 は 9 日分進んでいる、という考え方です。
「開始日と終了日を両方含めた日数(=10 日)」が欲しい場合は、days + 1 のように自分で調整します。
ここは業務仕様とセットで決めるポイントなので、
「経過日数」と「日数(両端含む)」を混同しないように意識してください。
マイナスになるケースと順序の意味
開始日と終了日の順番を間違えるとどうなるか
between は「第1引数 → 第2引数」の差を取ります。
順番を逆にすると、符号も逆になります。
import java.time.LocalDate;
import java.time.temporal.ChronoUnit;
public class ElapsedDaysOrder {
public static void main(String[] args) {
LocalDate d1 = LocalDate.of(2025, 3, 1);
LocalDate d2 = LocalDate.of(2025, 3, 10);
long a = ChronoUnit.DAYS.between(d1, d2); // 9
long b = ChronoUnit.DAYS.between(d2, d1); // -9
System.out.println("d1→d2 : " + a);
System.out.println("d2→d1 : " + b);
}
}
Javaここで押さえておきたいのは、
「どちらを“基準”とみなすかで、経過日数の符号が変わる」 ということです。
多くの業務では「過去→未来」で考えるので、
「開始日」「終了日」という名前で変数を持ち、between(start, end) の形に統一しておくと、読み間違いが減ります。
LocalDateTime / ZonedDateTime の経過日数
LocalDateTime でも DAYS.between は使える
日時(時刻付き)でも、ChronoUnit.DAYS.between は使えます。
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
public class ElapsedDaysDateTime {
public static void main(String[] args) {
LocalDateTime start = LocalDateTime.of(2025, 3, 1, 10, 0);
LocalDateTime end = LocalDateTime.of(2025, 3, 3, 9, 0);
long days = ChronoUnit.DAYS.between(start, end);
System.out.println("経過日数 : " + days); // 1
}
}
Java3/1 10:00 → 3/3 9:00 は、
丸 2 日には届いていないので「1 日分」とカウントされます。
ここでのポイントは、
「DAYS.between は“24 時間単位で何回分進んだか”を見ている」 という感覚です。
「カレンダー上で何日またいだか」ではなく、
「時間として何日分経ったか」に近いイメージになります。
日付ベースで数えたいなら LocalDate に落とす
「とにかく日付だけで考えたい」「時刻は無視して、日付の差だけ知りたい」
という場合は、toLocalDate() で日付に落としてから計算するのが安全です。
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
public class ElapsedDaysByDateOnly {
public static void main(String[] args) {
LocalDateTime startDateTime = LocalDateTime.of(2025, 3, 1, 23, 59);
LocalDateTime endDateTime = LocalDateTime.of(2025, 3, 3, 0, 1);
LocalDate start = startDateTime.toLocalDate(); // 2025-03-01
LocalDate end = endDateTime.toLocalDate(); // 2025-03-03
long days = ChronoUnit.DAYS.between(start, end);
System.out.println("日付ベースの経過日数 : " + days); // 2
}
}
Java業務では、「日付単位での経過日数」が欲しいことが多いので、
「LocalDate で扱うか、LocalDateTime で扱うか」を最初に決める のが大事です。
Period を使った「日数」取得との違い
Period.between で days を見るときの注意
Period でも「日」の差を取り出せますが、
これは「年・月・日」に分解された“残り”としての日数です。
import java.time.LocalDate;
import java.time.Period;
public class PeriodDaysExample {
public static void main(String[] args) {
LocalDate start = LocalDate.of(2025, 1, 1);
LocalDate end = LocalDate.of(2025, 3, 10);
Period p = Period.between(start, end);
System.out.println("years : " + p.getYears()); // 0
System.out.println("months: " + p.getMonths()); // 2
System.out.println("days : " + p.getDays()); // 9
}
}
Javaこの days は「2 ヶ月を引いた残りの日数」であって、
「トータルで何日経ったか」ではありません。
「トータルの経過日数」が欲しいときは、ChronoUnit.DAYS.between を使う
と覚えておくと混乱しません。
実務での経過日数の使いどころ
例1:申込から経過日数を出す
「申込から 30 日を過ぎたら自動キャンセル」などの要件です。
import java.time.LocalDate;
import java.time.temporal.ChronoUnit;
public class ApplicationElapsedExample {
public static void main(String[] args) {
LocalDate applied = LocalDate.of(2025, 3, 1);
LocalDate today = LocalDate.of(2025, 4, 5);
long elapsed = ChronoUnit.DAYS.between(applied, today);
System.out.println("経過日数 : " + elapsed); // 35
System.out.println("30日超過? : " + (elapsed > 30)); // true
}
}
Javaここでのポイントは、
「経過日数を一度変数にしてから、業務ルールに当てはめる」 ことです。
あちこちで between を直接 if 文に書き始めると、
後から仕様変更が入ったときに追いかけるのが大変になります。
例2:締切までの残り日数を出す
「締切まであと何日か」をユーザーに見せたいケースです。
import java.time.LocalDate;
import java.time.temporal.ChronoUnit;
public class RemainingDaysExample {
public static void main(String[] args) {
LocalDate today = LocalDate.of(2025, 3, 20);
LocalDate due = LocalDate.of(2025, 3, 25);
long remaining = ChronoUnit.DAYS.between(today, due);
System.out.println("締切まで残り日数 : " + remaining); // 5
}
}
Javaここでも、「今日を含めるかどうか」「締切日を含めるかどうか」は仕様次第です。between の結果をそのまま使うのか、+1 するのか、
“どちらが正しいか”ではなく、“業務としてどう数えるか”を決める ことが大事です。
経過日数ユーティリティとしてまとめる
elapsedDays(start, end) を一か所に閉じ込める
経過日数も、あちこちで同じようなコードを書きがちなので、
ユーティリティメソッドにしておくとスッキリします。
import java.time.LocalDate;
import java.time.temporal.ChronoUnit;
public class DateDiffUtils {
public static long elapsedDays(LocalDate start, LocalDate end) {
if (start == null || end == null) {
throw new IllegalArgumentException("start / end は null にできません");
}
return ChronoUnit.DAYS.between(start, end);
}
public static long inclusiveDays(LocalDate start, LocalDate end) {
return elapsedDays(start, end) + 1;
}
public static void main(String[] args) {
LocalDate s = LocalDate.of(2025, 3, 1);
LocalDate e = LocalDate.of(2025, 3, 10);
System.out.println("経過日数 : " + elapsedDays(s, e)); // 9
System.out.println("両端含む日数 : " + inclusiveDays(s, e)); // 10
}
}
Javaここで深掘りしたいのは、
「経過日数」と「両端を含む日数」を明確に名前で分けている ことです。
名前が分かれていれば、呼び出し側のコードを読んだときに
「どっちの数え方をしているのか」が一目で分かります。
まとめ:経過日数で絶対に覚えてほしいこと
経過日数は、「2つの日付(または日時)の間に“何日分進んだか”」を表す値です。
トータルの経過日数が欲しいときは ChronoUnit.DAYS.between を使う。
LocalDate で扱うか、LocalDateTime で扱うかを最初に決める。
「開始日と終了日を両方含めた日数」が欲しい場合は、自分で +1 するなどルールを明示する。
ユーティリティメソッドに閉じ込めて、「経過日数」と「両端含む日数」を名前で区別する。
もしあなたのコードのどこかに、
「年・月・日をバラして無理やり日数を計算している」ような箇所があれば、
そこを一度 ChronoUnit.DAYS.between ベースに書き換えられないか眺めてみてください。
その小さな置き換えが、
“時間とカレンダーに強いエンジニア”への、確かな一歩になります。
