こんにちは、かつコーチです。
「今日の日付を出したいだけなのに、DateとCalendarのどっちを使えばいいの?」と迷ったことはありませんか。
今回はJava 21でも標準の日付・時刻ライブラリであるjava.time(日付や時刻を安全に扱うためのパッケージ)の基本を解説します。
java.timeとは?
なぜDateやCalendarを使わないのか
古いJavaにはjava.util.Dateとjava.util.Calendarという日付クラスがありましたが、これらには「月が0始まり」「スレッドセーフでない」「値を変更できてしまう」といった分かりにくい問題がありました。
そこでJava 8以降はjava.timeパッケージが標準になり、今もこちらを使うのが基本です。
java.timeの主要クラス
- LocalDate(時刻を持たない日付):年月日だけを扱う
- LocalTime(日付を持たない時刻):時分秒だけを扱う
- LocalDateTime(日付と時刻の両方):年月日+時分秒を扱う
- DateTimeFormatter(日付・時刻の書式を変換するクラス):文字列との相互変換に使う
用途に応じてクラスを使い分けるのが、java.timeを理解する最初のポイントです。
基本の書き方
現在日時の取得
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
public class DateTimeSample {
public static void main(String[] args) {
LocalDate today = LocalDate.now();
LocalTime now = LocalTime.now();
LocalDateTime dateTime = LocalDateTime.now();
System.out.println(today); // 例:2026-08-31
System.out.println(now); // 例:14:23:05.123
System.out.println(dateTime); // 例:2026-08-31T14:23:05.123
}
}
now()メソッドを呼ぶだけで、現在の日付・時刻を取得できます。LocalDateは年月日のみ、LocalDateTimeは時刻まで含む点が違いです。
日付の指定・加算・比較
import java.time.LocalDate;
LocalDate birthday = LocalDate.of(1990, 4, 1); // 年,月,日を指定
LocalDate nextWeek = LocalDate.now().plusWeeks(1); // 1週間後
LocalDate lastMonth = LocalDate.now().minusMonths(1); // 1ヶ月前
boolean isBefore = birthday.isBefore(LocalDate.now());
System.out.println(isBefore); // true
plusDays・plusMonths・minusYearsのようなメソッドで日付を加算・減算でき、isBefore・isAfterで前後関係を比較できます。
すべて新しいLocalDateインスタンスを返すイミュータブル(変更不可)な設計なので、元の値が勝手に変わる心配がありません。
文字列との相互変換(DateTimeFormatter)
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
LocalDate date = LocalDate.of(2026, 8, 31);
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy年MM月dd日");
String text = date.format(formatter);
System.out.println(text); // 2026年08月31日
LocalDate parsed = LocalDate.parse("2026-12-25");
System.out.println(parsed); // 2026-12-25
画面表示用に和暦っぽい形式にしたいときはDateTimeFormatter.ofPatternでパターンを指定します。
逆に文字列からLocalDateを作りたいときはparseを使いますが、フォーマットが一致しないと例外が発生するので注意が必要です。
よくあるつまずきポイント・エラー対処
文字列のフォーマット不一致でDateTimeParseException
実際に私が業務で日付をCSVから取り込む処理を書いたとき、次のコードで例外が発生しました。
// ❌Before:フォーマットを指定せずparseして例外発生
import java.time.LocalDate;
String csvDate = "2026/08/31";
LocalDate date = LocalDate.parse(csvDate); // 例外発生
このコードはjava.time.format.DateTimeParseException: Text '2026/08/31' could not be parsedという例外になります。LocalDate.parseは引数なしだとyyyy-MM-dd形式しか受け付けないため、/区切りの文字列はそのままでは解析できません。
// ✅After:DateTimeFormatterで元の形式を明示する
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
String csvDate = "2026/08/31";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy/MM/dd");
LocalDate date = LocalDate.parse(csvDate, formatter);
System.out.println(date); // 2026-08-31
外部から受け取る日付文字列を扱うときは、必ず元データの形式に合わせたDateTimeFormatterを用意する癖をつけましょう。
応用・一歩先の使い方
期間の差分を求める(Period・Duration)
import java.time.LocalDate;
import java.time.Period;
LocalDate start = LocalDate.of(2026, 1, 1);
LocalDate end = LocalDate.of(2026, 8, 31);
Period period = Period.between(start, end);
System.out.println(period.getMonths() + "ヶ月" + period.getDays() + "日");
日付同士の差を求めたいときはPeriod(日付の差分を表すクラス)を使います。
時刻同士の差分(何時間何分か)を求めたいときは、同じ考え方でDurationクラスを使います。
タイムゾーンを扱う(ZonedDateTime)
import java.time.ZonedDateTime;
import java.time.ZoneId;
ZonedDateTime tokyoTime = ZonedDateTime.now(ZoneId.of("Asia/Tokyo"));
ZonedDateTime nyTime = tokyoTime.withZoneSameInstant(ZoneId.of("America/New_York"));
System.out.println(tokyoTime);
System.out.println(nyTime);
海外向けサービスでタイムゾーンを扱う必要が出てきたら、LocalDateTimeではなくZonedDateTime(タイムゾーン情報付きの日時)に切り替えます。
まとめ
この記事のポイント
- java.timeは
LocalDate・LocalTime・LocalDateTimeを用途に応じて使い分ける - すべてイミュータブルなので、加算・減算のメソッドは新しいインスタンスを返す
- 文字列との変換は
DateTimeFormatterでフォーマットを明示する - 差分計算には
Period・Duration、タイムゾーンにはZonedDateTimeを使う
次に読むべき記事
- ファイル入出力(java.nio.file)
- Scannerで入力を受け取る
タグ: Java, 初心者向け, 標準ライブラリ