日付減算の本質は「過去にさかのぼるカレンダー計算を任せること」
日付減算は、「今日から 7 日前」「3 ヶ月前」「1 年前の同じ日」といった
“カレンダー上で過去にさかのぼる”計算です。
ここでも一番やってはいけないのは、year-- や day -= 7 のように、自分で年・月・日をいじることです。
月の長さ、うるう年、月末などを全部自前で面倒見るのはほぼ無理ゲーです。
正解は、minusXxx(または plusXxx にマイナス値)を素直に使うこと。
「過去方向のカレンダー計算も Java に任せる」という発想を持つのがスタートラインです。
LocalDate の基本的な日付減算
日数を引く:minusDays
「N 日前」は minusDays で書きます。
import java.time.LocalDate;
public class MinusDaysBasic {
public static void main(String[] args) {
LocalDate today = LocalDate.of(2025, 3, 26);
LocalDate before7 = today.minusDays(7);
System.out.println("today : " + today); // 2025-03-26
System.out.println("before7 : " + before7); // 2025-03-19
}
}
Javaここで押さえてほしいポイントは二つです。
一つ目は、「月またぎ・年またぎも勝手にやってくれる」こと。
3 月 1 日から 1 日引けば 2 月 28 日(うるう年なら 2 月 29 日)になります。
二つ目は、「元の値は変わらない(不変)」こと。today はそのまま、before7 だけが新しい日付です。
“うっかり上書き”系のバグを防げます。
月を引く:minusMonths と「月末問題(逆方向)」
import java.time.LocalDate;
public class MinusMonthsBasic {
public static void main(String[] args) {
LocalDate d1 = LocalDate.of(2025, 3, 15);
LocalDate d2 = d1.minusMonths(1);
System.out.println(d1); // 2025-03-15
System.out.println(d2); // 2025-02-15
}
}
Javaここで重要なのが、減算でも「存在しない日付は末日に丸められる」というルールです。
LocalDate endMar = LocalDate.of(2025, 3, 31);
LocalDate minus1 = endMar.minusMonths(1);
System.out.println(minus1); // 2025-02-28
Java3 月 31 日から 1 ヶ月引くと、2 月 31 日は存在しないので
「その月で可能な最大の日(末日)」に寄せられます。
年に対しても同じです。
LocalDate leap = LocalDate.of(2024, 2, 29);
LocalDate prevYear = leap.minusYears(1);
System.out.println(prevYear); // 2023-02-28
Java「minusYears / minusMonths でも、存在しない日付は末日に丸められる」
この挙動を知っておくと、結果に戸惑わなくなります。
Period を使った「年+月+日」の減算
Period をマイナス方向に使う
Period は「何年何ヶ月何日」という“期間”を表すクラスです。
加算だけでなく、減算にもそのまま使えます。
import java.time.LocalDate;
import java.time.Period;
public class PeriodMinusExample {
public static void main(String[] args) {
LocalDate base = LocalDate.of(2025, 3, 26);
Period period = Period.of(1, 2, 10); // 1年2ヶ月10日
LocalDate result = base.minus(period);
System.out.println("base : " + base); // 2025-03-26
System.out.println("before : " + result); // 2024-01-16
}
}
Java業務的には、
「契約開始日の 1 年 2 ヶ月 10 日前から受付開始」
「満了日の 1 ヶ月前に通知」
のようなルールを Period で表現しておき、target.minus(period) で「いつから/いつまで」を計算するイメージです。
業務シナリオで考える日付減算
例1:支払期限から 7 日前にリマインド
「支払期限の 7 日前にメールを送る」というよくある要件です。
import java.time.LocalDate;
public class ReminderExample {
public static void main(String[] args) {
LocalDate dueDate = LocalDate.of(2025, 4, 25);
LocalDate remindDate = dueDate.minusDays(7);
System.out.println("支払期限 : " + dueDate); // 2025-04-25
System.out.println("通知日 : " + remindDate); // 2025-04-18
}
}
Javaここで大事なのは、
「“基準日”を決めて、そこから minusDays / minusMonths でさかのぼる」
というパターンを体に染み込ませることです。
例2:契約満了日の 1 ヶ月前に通知
import java.time.LocalDate;
public class ContractNoticeExample {
public static void main(String[] args) {
LocalDate expire = LocalDate.of(2025, 3, 31);
LocalDate notice = expire.minusMonths(1);
System.out.println("満了日 : " + expire); // 2025-03-31
System.out.println("通知日 : " + notice); // 2025-02-28
}
}
Javaここでも月末問題が出ます。
3 月 31 日の 1 ヶ月前は 2 月 28 日(うるう年なら 2 月 29 日)になります。
「必ず月末に通知したい」という仕様ならこれで OK。
「必ず 1 ヶ月前の同じ日(31 日前)」という意味なら、minusDays(31) のように日数で扱うべきです。
「1 ヶ月前」と「30 日前/31 日前」は違う
という感覚を、減算でもしっかり意識してください。
LocalDateTime / ZonedDateTime での日付減算
LocalDateTime の minusXxx
LocalDateTime でも、日付部分の減算は同じ感覚で書けます。
import java.time.LocalDateTime;
public class LocalDateTimeMinusExample {
public static void main(String[] args) {
LocalDateTime dt = LocalDateTime.of(2025, 3, 26, 9, 0);
LocalDateTime before = dt.minusDays(3);
System.out.println(dt); // 2025-03-26T09:00
System.out.println(before); // 2025-03-23T09:00
}
}
Java日付が動くときに、時刻も一緒に動く——それだけです。
ZonedDateTime の minusXxx(タイムゾーンも考慮)
ZonedDateTime では、タイムゾーンやサマータイムも含めて
“現地時間で N 日前”を計算してくれます。
import java.time.ZoneId;
import java.time.ZonedDateTime;
public class ZonedDateTimeMinusExample {
public static void main(String[] args) {
ZonedDateTime zdt = ZonedDateTime.of(
2025, 3, 26,
9, 0, 0, 0,
ZoneId.of("Asia/Tokyo")
);
ZonedDateTime before = zdt.minusDays(1);
System.out.println(zdt);
System.out.println(before);
}
}
Javaサマータイムのある地域では、
「1 日前」が 24 時間前とは限らないこともありますが、ZonedDateTime はそのあたりも含めて正しく処理してくれます。
minusXxx と plusXxx(負の値) の関係
minusDays(7) と plusDays(-7) は同じ
実は、次の二つは同じ意味です。
date.minusDays(7);
date.plusDays(-7);
Javaただし、読みやすさの観点からは minusDays(7) を使う方が圧倒的におすすめです。
「7 日前」と書いてある方が、コードを読む人の脳に優しいからです。
まとめ:日付減算で絶対に覚えてほしいこと
日付減算は、「過去方向のカレンダー計算」を安全に書くための技術です。
自前で year-- や day -= 30 を書かない。LocalDate / LocalDateTime / ZonedDateTime の minusDays / minusMonths / minusYears を使う。
存在しない日付は、加算と同じく「その月の末日に丸められる」。
「1 ヶ月前」と「30 日前/31 日前」は違う——ビジネスルールに合わせて選ぶ。
複合期間は Period を使い、minus(period) でさかのぼる。
あなたのコードのどこかに、
「締切の 7 日前を day - 7 で計算している」ような箇所があれば、
そこを一度 minusDays や minusMonths に置き換えられないか眺めてみてください。
その小さな一歩が、
“時間とカレンダーに強いエンジニア”への、確かな前進になります。

