| この記事の要点 |
|
結論: 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 / Maya)
- 7 Spring Frameworkのアノテーション一覧
- 8 【Spring】@Valueアノテーションとは
- 9 CATALINA_HOME の確認方法 (Linux / Mac)
- 10 【Spring】@Autowiredアノテーションとは
最近更新/作成されたページ
- プロジェクトをTomcatプロジェクトとして認識させる方法 2026-10-07 22:32:50
- MySQLの1366 Incorrect string value|Laravelの文字コード・絵文字エラー 2026-10-07 21:54:03
- curlの証明書ホスト名不一致|旧エラー51・現行60の確認と対処 2026-10-07 21:54:03
- LaravelのMassAssignmentException|fillableの原因と安全な対処 2026-10-07 21:54:03
- Eclipse で Tomcat の起動ログがコンソールに出ない時の確認手順 2026-10-07 21:54:02
- MySQLにおける中央値(Median)の導き方(バージョン8未満) 2026-10-07 13:49:45
- getInputForward 2026-10-07 13:41:15
- JSONから配列に変換 2026-10-07 13:41:15
- ビューから値をモデルに格納しコントローラーで受け取る方法 2026-10-07 13:23:41
- Laravelのテーブル作成と定義変更|マイグレーション・up/down・注意点 2026-10-07 13:23:41
- NumPy 配列に要素を追加する方法 (append / concatenate) 2026-10-07 13:23:41
- MariaDB・MySQLで現在日時を取得する方法|NOW・タイムゾーン・保存型 2026-10-07 13:13:36
- 【django】テンプレートで定数を使用する方法 2026-10-07 13:10:15
- Spring BootにおけるApplication.propertiesの環境依存設定の分割方法 2026-10-07 12:09:35
- Not supported for DML operations【Springエラー】 2026-10-07 11:09:38