| この記事の要点 |
|
結論: Java 8 以降なら LocalDate を使う
本稿は Java の日付を加算、減算する方法について記載します。Java 8 で導入された java.time パッケージの LocalDate(日付)・LocalDateTime(日時)を使うと、1 行で書けます。
import java.time.LocalDate;
LocalDate today = LocalDate.now();
LocalDate tomorrow = today.plusDays(1); // 1 日後
LocalDate yesterday = today.minusDays(1); // 1 日前
LocalDate nextWeek = today.plusWeeks(1); // 1 週間後
LocalDate twoMonthsAgo = today.minusMonths(2); // 2 か月前
LocalDate nextYear = today.plusYears(1); // 1 年後
LocalDate は不変(イミュータブル)なので、plusDays は元のオブジェクトを変えずに新しいオブジェクトを返します。戻り値を受け取らないと何も変わらない点に注意してください。
主なメソッド一覧
| 単位 | 加算 | 減算 | 対応クラス |
|---|---|---|---|
| 年 | plusYears(n) | minusYears(n) | LocalDate / LocalDateTime |
| 月 | plusMonths(n) | minusMonths(n) | LocalDate / LocalDateTime |
| 週 | plusWeeks(n) | minusWeeks(n) | LocalDate / LocalDateTime |
| 日 | plusDays(n) | minusDays(n) | LocalDate / LocalDateTime |
| 時・分・秒 | plusHours(n) など | minusMinutes(n) など | LocalDateTime / LocalTime |
| 任意の単位 | plus(n, ChronoUnit.DAYS) | minus(Period.ofMonths(1)) | 共通 |
負の値を渡すこともできます(plusDays(-1) は minusDays(1) と同じ)。
文字列の日付を加算・減算する(新 API)
「20180101」のような文字列を受け取り、計算して文字列に戻す場合は DateTimeFormatter を使います。
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyyMMdd");
LocalDate date = LocalDate.parse("20180101", fmt);
String strDate = date.minusDays(1).format(fmt); // "20171231"
"yyyy-MM-dd" 形式(ISO 形式)ならフォーマッタ無しで LocalDate.parse("2018-01-01") と書けます。DateTimeFormatter はスレッドセーフなので、定数として使い回せます。
従来の方法: Calendar クラス(Java 7 以前のコード)
既存システムでは Date と Calendar を使った書き方もよく見かけます。処理の流れは次の通りです。
- SimpleDateFormat クラスで解析する日付の形式を指定する(例: yyyy/MM/dd)
- 文字列の日付を解析して Date クラスに変換する
- 日付計算は Calendar クラスで行うので、Calendar に変換する
addメソッドで加算・減算する(負の値で減算)- SimpleDateFormat で計算後の日付を文字列に変換する
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
...
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
Date date = sdf.parse("20180101");
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
calendar.add(Calendar.DATE, -1);
String strDate = sdf.format(calendar.getTime()); // "20171231"
sdf.parse は検査例外 ParseException を投げるため、try-catch か throws 宣言が必要です。Calendar.DATE と Calendar.DAY_OF_MONTH は同じ意味で、月は Calendar.MONTH、年は Calendar.YEAR を指定します。
| 比較項目 | Calendar / Date(旧) | LocalDate(新) |
|---|---|---|
| 可変性 | 可変(add で自分自身が変わる) | 不変(新しいオブジェクトを返す) |
| スレッドセーフ | SimpleDateFormat は非スレッドセーフ | DateTimeFormatter はスレッドセーフ |
| 月の番号 | 0 始まり(1 月が 0) | 1 始まり |
| コード量 | 多い | 少ない |
旧 API と新 API は date.toInstant() や Date.from(...) で相互変換できるので、既存コードを少しずつ置き換えられます。
落とし穴
- 月末の丸め:
LocalDate.of(2026, 1, 31).plusMonths(1)は 2026-02-28 になる。月末日を求めたいならwith(TemporalAdjusters.lastDayOfMonth())を使う - SimpleDateFormat の寛容モード: 既定では「20181332」のような存在しない日付も繰り越して解釈してしまう。
sdf.setLenient(false)で厳密にする - SimpleDateFormat を static で共有: 複数スレッドから同時に使うと結果が壊れる。メソッド内で生成するか DateTimeFormatter に移行する
- パターンの大文字小文字:
MMは月、mmは分。yyyyMMddをyyyymmddと書くと誤った結果になる - 時差を含む計算: 夏時間のある地域で時刻をまたぐ計算をするなら
ZonedDateTimeを使う
確認方法: 日数の差を求める
計算結果の検証や「何日後か」を求めるには ChronoUnit が便利です。
import java.time.temporal.ChronoUnit;
long days = ChronoUnit.DAYS.between(
LocalDate.of(2026, 1, 1), LocalDate.of(2026, 3, 1)); // 59
関連
- Java日時API入門|java.time・LocalDate・Instant・Duration
- Java Calendar.getInstance() 使い方
- Java で現在日時を取得する方法 (Date / LocalDateTime)
- Javaの文字列API|String・StringBuilder
子ページはありません
人気ページ
- 1 Eclipseで「サーバーに追加または除去できるリソースがありません。」の原因と対処法
- 2 tomcat の起動 / 停止ログと catalina.log・catalina.out の違い
- 3 JavaScript で base URL を取得する方法|window.location.origin
- 4 YouTube Data API v3 エラー一覧|403・400・404 の原因と対処
- 5 Laravel エラー一覧|500/Blade/DB 接続/ルーティングの代表エラー
- 6 3Dグラフィックスのソフト一覧|Blender・Metasequoiaと用途別の選び方
- 7 Spring Frameworkのアノテーション一覧
- 8 【Spring】@Valueアノテーションとは
- 9 CATALINA_HOME の確認方法 (Linux / Mac)
- 10 【Spring】@Autowiredアノテーションとは
最近更新/作成されたページ
- Visual Studio「デザイナーを表示できません」エラーの原因と対処 2026-10-28 12:06:00
- SSH 認証に失敗しました。再試行してください の対処 2026-10-28 12:06:00
- SSH2 秘密鍵の読み込みに失敗しました の原因と対処 2026-10-28 12:06:00
- TeraTerm のよくあるエラーと対処法完全ガイド — Connection refused / 2026-10-28 12:06:00
- Visual Studio エラー一覧|コンパイルエラー・警告の確認方法と対処 2026-10-28 11:39:57
- Whitelabel Error Page の原因と消し方|Spring Boot のエラーページ 2026-10-28 11:39:57
- Eclipseで「サーバーに追加または除去できるリソースがありません。」の原因と対処法 2026-10-28 11:39:57
- SQL WHERE 句完全ガイド 2026-10-28 11:39:57
- SQL JOIN 完全ガイド (INNER/LEFT/RIGHT/FULL OUTER) 2026-10-28 11:39:57
- tomcat の起動 / 停止ログと catalina.log・catalina.out の違い 2026-10-28 10:24:23
- Tomcat の起動確認方法 5 つ|localhost:8080・ポート・プロセス・ログ 2026-10-28 10:24:23
- Oracle 19c COMMITの使い方: 暗黙コミット・自動確定・応答不明時の確認 2026-10-28 09:59:09
- Oracle 19c DELETE文|削除対象の確認・COMMIT前の判断・ROLLBACKの条件 2026-10-28 09:59:09
- Oracle 19c INSERT文|INSERT ALL・SELECT・RETURNINGとMERGEの使い分け 2026-10-28 09:59:09
- Oracle 19cのトランザクション制御|COMMIT・ROLLBACK・分離レベルと接続設定 2026-10-28 09:59:09