カテゴリ: Java 更新日: 2026/04/07

Javaの日付・時間API(java.time)を徹底解説!LocalDateとLocalDateTimeの使い方

Javaの日付・時間API(java.time)とは?LocalDate/LocalDateTimeの全体像を解説
Javaの日付・時間API(java.time)とは?LocalDate/LocalDateTimeの全体像を解説

先生と生徒の会話形式で理解しよう

生徒

「Javaで今日の日付を表示させたいんですけど、昔のやり方は難しいって聞きました。今はどうするのが正解なんですか?」

先生

「そうですね。昔はDateクラスやCalendarクラスを使っていましたが、現在はJava 8以降で導入された『Date-Time API(java.timeパッケージ)』を使うのが標準ですよ。」

生徒

「java.timeですか。LocalDateとかLocalDateTimeとか似たような名前がいっぱいあって、どれを使えばいいか迷っちゃいます。」

先生

「役割がしっかり分かれているので、一度整理すれば簡単です。基本から具体的なコードの書き方まで、詳しく解説していきましょう!」

1. Javaの日付・時間APIの基本とメリット

1. Javaの日付・時間APIの基本とメリット
1. Javaの日付・時間APIの基本とメリット

Javaで日付や時間を扱う際、かつてはjava.util.Datejava.util.Calendarが使われていました。しかし、これらは「設計が複雑」「スレッドセーフではない」「月のカウントが0から始まる」といった多くの課題を抱えていました。これらを解決するために登場したのが、java.timeパッケージに含まれる新しいAPIです。

この新しいAPIの大きな特徴は、不変性(イミュータブル)です。一度作成した日付オブジェクトは変更されず、変更を加える操作をすると新しいオブジェクトが生成されます。これにより、複数の処理が同時に動くプログラムでも安全に利用できるというメリットがあります。また、メソッド名が直感的になり、「今日の日付を取得するならnow()」「特定の日付を作るならof()」といったように、初心者でも理解しやすい設計になっています。

さらに、国際的な標準規格であるISO-8601に基づいているため、他システムとのデータ連携もスムーズに行えます。現代のJava開発において、日付や時間を扱うならこのjava.timeをマスターすることは必須と言えるでしょう。

2. LocalDateで日付のみを管理する方法

2. LocalDateで日付のみを管理する方法
2. LocalDateで日付のみを管理する方法

LocalDateは、時間やタイムゾーンの情報を含まず、「年・月・日」という日付情報のみを扱うクラスです。誕生日や記念日、有効期限のように、具体的な時刻を必要としないデータを扱う際に最適です。

例えば、システムが動いている当日の日付を取得したり、特定の日付(例:2025年12月25日)をプログラムの中で指定したりする場合に使用します。内部的には「2025-12-25」のような形式で保持されます。以下のコードで、基本的な使い方を確認してみましょう。


import java.time.LocalDate;

public class LocalDateExample {
    public static void main(String[] args) {
        // 現在の日付を取得
        LocalDate today = LocalDate.now();
        System.out.println("今日の日付: " + today);

        // 特定の日付を指定して作成 (2025年12月25日)
        LocalDate christmas = LocalDate.of(2025, 12, 25);
        System.out.println("今年のクリスマス: " + christmas);
    }
}

今日の日付: 2026-01-05
今年のクリスマス: 2025-12-25

このように、LocalDate.now()を使えば一瞬で実行時の日付が取得できます。月を指定する際も、古いCalendarクラスのように「1月を0とする」必要はなく、そのまま「12」と書けば12月として認識されるため、ミスが少なくなります。

3. LocalTimeで時刻のみを精密に扱う

3. LocalTimeで時刻のみを精密に扱う
3. LocalTimeで時刻のみを精密に扱う

日付は不要で、「何時何分何秒」という時刻だけが必要な場合には、LocalTimeクラスを使用します。営業開始時間や、アラームの設定、特定のスケジュールが開始されるタイミングなどを管理するのに適しています。

LocalTimeは、ナノ秒単位まで精度を持っており、非常に細かな時間計測も可能です。もちろん、秒やナノ秒を省略して「15時30分」といったシンプルな指定も可能です。まずは現在時刻を取得する方法と、任意の時刻を生成する方法を見ていきましょう。


import java.time.LocalTime;

public class LocalTimeExample {
    public static void main(String[] args) {
        // 現在の時刻を取得
        LocalTime nowTime = LocalTime.now();
        System.out.println("現在の時刻: " + nowTime);

        // 指定した時刻を作成 (14時30分00秒)
        LocalTime targetTime = LocalTime.of(14, 30, 0);
        System.out.println("指定した時刻: " + targetTime);
    }
}

現在の時刻: 14:36:18.123456789
指定した時刻: 14:30

出力結果の「14:36:18.123456789」のように、実行環境によっては非常に細かい単位まで表示されます。ビジネスロジックで「分」までしか使わない場合は、後述するフォーマット機能を使って見た目を整えるのが一般的です。

4. LocalDateTimeで日付と時刻を組み合わせて使う

4. LocalDateTimeで日付と時刻を組み合わせて使う
4. LocalDateTimeで日付と時刻を組み合わせて使う

実務で最も頻繁に利用されるのが、このLocalDateTimeです。名前の通り、LocalDateLocalTimeの両方の情報を兼ね備えており、「2025年10月10日の午前10時」といった情報を一つのオブジェクトで保持できます。

予約システムの予約日時、SNSの投稿日時、ログの出力タイミングなど、日付と時刻をセットで記録する必要があるシーンでは、このクラスを選択すれば間違いありません。LocalDateLocalTimeを組み合わせてLocalDateTimeを作ることも可能ですし、最初から「今」をまるごと取得することもできます。


import java.time.LocalDateTime;
import java.time.Month;

public class LocalDateTimeExample {
    public static void main(String[] args) {
        // 現在の日付と時刻を取得
        LocalDateTime currentDateTime = LocalDateTime.now();
        System.out.println("現在日時: " + currentDateTime);

        // 詳細な日時を指定して作成 (2025年1月1日 0時0分)
        LocalDateTime newYear = LocalDateTime.of(2025, Month.JANUARY, 1, 0, 0);
        System.out.println("2025年の元旦: " + newYear);
    }
}

現在日時: 2026-01-05T14:36:18.123456789
2025年の元旦: 2025-01-01T00:00

出力の中に「T」という文字が入っていますが、これはISO-8601規格で日付と時刻の区切りを示す記号です。表示する際は、プログラミング側で適切に整形してユーザーに見せることが多いです。

5. 日付の計算や比較を簡単に行う便利なメソッド

5. 日付の計算や比較を簡単に行う便利なメソッド
5. 日付の計算や比較を簡単に行う便利なメソッド

Javaの新しい日付APIが便利な理由の一つに、日付の計算が非常に容易である点が挙げられます。「3日後」「1ヶ月前」「1週間後」といった計算を、直感的なメソッド名で実行できます。古いCalendarクラスで行っていた複雑な計算式はもう必要ありません。

代表的なメソッドには、加算を行うplusDaysplusMonthsplusYearsや、減算を行うminusWeeksなどがあります。また、日付の前後関係を判定するisBeforeisAfterといったメソッドも用意されており、条件分岐もスムーズに記述できます。


import java.time.LocalDate;

public class DateCalculationExample {
    public static void main(String[] args) {
        LocalDate baseDate = LocalDate.of(2025, 5, 20);
        
        // 1週間後の日付を取得
        LocalDate nextWeek = baseDate.plusWeeks(1);
        System.out.println("1週間後: " + nextWeek);
        
        // 2ヶ月前の日付を取得
        LocalDate twoMonthsAgo = baseDate.minusMonths(2);
        System.out.println("2ヶ月前: " + twoMonthsAgo);
        
        // 日付の比較
        boolean isBefore = baseDate.isBefore(nextWeek);
        System.out.println("2025/5/20は1週間後より前か?: " + isBefore);
    }
}

1週間後: 2025-05-27
2ヶ月前: 2025-03-20
2025/5/20は1週間後より前か?: true

これらのメソッドは、元のオブジェクトを書き換えるのではなく、計算結果を持った「新しいオブジェクト」を返します。この不変性の性質により、計算の途中で意図せずデータが書き換わるバグを防ぐことができます。

6. 日付のフォーマットと文字列変換(DateTimeFormatter)

6. 日付のフォーマットと文字列変換(DateTimeFormatter)
6. 日付のフォーマットと文字列変換(DateTimeFormatter)

システム内部で保持している日付オブジェクトを、画面に表示したり帳票に出力したりする際には、「2025/05/20」や「2025年5月20日(火)」といった特定の形式に変換する必要があります。この変換を担うのがDateTimeFormatterクラスです。

逆に、ユーザーが入力した文字列(例:"2025-10-31")をJavaの日付オブジェクトに変換(パース)する場合も、このクラスを使用します。フォーマットのパターンを指定することで、自由自在な見た目にカスタマイズ可能です。


import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

public class FormatExample {
    public static void main(String[] args) {
        LocalDateTime now = LocalDateTime.now();
        
        // フォーマットを指定 (例:2025/12/31 15:30:45)
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss");
        
        // 日時を文字列に変換
        String formattedDate = now.format(formatter);
        System.out.println("フォーマット後: " + formattedDate);
        
        // 文字列から日時オブジェクトに変換
        String dateStr = "2025-12-25 10:00:00";
        LocalDateTime parsedDate = LocalDateTime.parse(dateStr, formatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
        System.out.println("解析後の日時: " + parsedDate);
    }
}

フォーマット後: 2026/01/05 14:36:18
解析後の日時: 2025-12-25T10:00

ofPatternで指定する記号(yは年、Mは月、dは日、Hは24時間制の時など)は、大文字と小文字で意味が異なるため注意が必要です。例えば「mm」は「分」ですが、「MM」は「月」を意味します。ここを間違えると全く異なる日付として処理されてしまうため、公式ドキュメントを確認しながら正確に指定しましょう。

7. ZonedDateTimeでタイムゾーンを考慮する

7. ZonedDateTimeでタイムゾーンを考慮する
7. ZonedDateTimeでタイムゾーンを考慮する

グローバルなシステムを構築する場合、日本の時刻だけでなく、ニューヨークやロンドンの時刻も扱う必要があります。LocalDateTimeは「ローカル」な日時、つまりどこか特定の場所(タイムゾーン)を意識しない日時を扱いますが、ZonedDateTimeを使えば「東京の2025年1月1日」といった具体的な地域情報を持たせることができます。

タイムゾーンを跨ぐ計算(例:日本時間からロンドン時間を算出する)や、サーバーの設置場所に関係なく絶対的な時間を記録したい場合に非常に強力です。世界標準時(UTC)との時差も自動的に計算してくれるため、複雑な計算を自分で行う必要はありません。


import java.time.ZonedDateTime;
import java.time.ZoneId;

public class ZonedDateTimeExample {
    public static void main(String[] args) {
        // 日本の現在日時を取得
        ZonedDateTime japanTime = ZonedDateTime.now(ZoneId.of("Asia/Tokyo"));
        System.out.println("日本の現在時刻: " + japanTime);

        // ニューヨークの現在日時を取得
        ZonedDateTime nyTime = ZonedDateTime.now(ZoneId.of("America/New_York"));
        System.out.println("ニューヨークの現在時刻: " + nyTime);
    }
}

日本の現在時刻: 2026-01-05T14:36:18.123456+09:00[Asia/Tokyo]
ニューヨークの現在時刻: 2026-01-05T00:36:18.123456-05:00[America/New_York]

出力に含まれる「+09:00」は、世界標準時から9時間進んでいることを示しています。このように、場所による時間のズレを正確に管理できるのがZonedDateTimeの強みです。初心者の方は、まずはLocalDateLocalDateTimeに慣れてから、必要に応じてこのクラスを学習すると良いでしょう。

8. 期間を測るためのクラス:PeriodとDuration

8. 期間を測るためのクラス:PeriodとDuration
8. 期間を測るためのクラス:PeriodとDuration

「特定の日付から特定の日付まで、何日間あるか?」や「ある処理に何秒かかったか?」といった「期間」を扱いたい場面があります。JavaのDate-Time APIでは、日付ベースの期間にはPeriod、時間ベースの期間にはDurationという2つのクラスを使い分けます。

Periodは「2年と3ヶ月と10日間」といったカレンダー上の差分を扱い、Durationは「48時間や3600秒」といった絶対的な時間の長さを扱います。これらを使いこなすことで、年齢の計算や有効期限の残り日数の算出が非常にシンプルになります。


import java.time.LocalDate;
import java.time.Period;

public class PeriodExample {
    public static void main(String[] args) {
        LocalDate start = LocalDate.of(2023, 1, 1);
        LocalDate end = LocalDate.of(2025, 5, 20);

        // 2つの日付の差を計算
        Period period = Period.between(start, end);

        System.out.println("期間: " + period.getYears() + "年 " 
                           + period.getMonths() + "ヶ月 " 
                           + period.getDays() + "日間");
    }
}

期間: 2年 4ヶ月 19日間

このように、Period.betweenメソッドを使うだけで、複雑なうるう年などの計算を気にすることなく正確な期間を導き出せます。時間の差を求めたい場合は、同様にDuration.betweenを使用すれば、ナノ秒単位までの正確な経過時間を取得することが可能です。

9. 実務でよくある日付操作の逆引きリファレンス

9. 実務でよくある日付操作の逆引きリファレンス
9. 実務でよくある日付操作の逆引きリファレンス

最後に、実際のプログラミング現場でよく遭遇するニーズに対する解決策をまとめておきます。これらを知っておくと、コーディングのスピードが格段にアップします。

  • 月末の日付を知りたい: TemporalAdjusters.lastDayOfMonth()を使用します。
  • 翌週の月曜日を取得したい: TemporalAdjusters.next(DayOfWeek.MONDAY)を使用します。
  • 日付の妥当性チェック: LocalDate.parseをtry-catchで囲み、DateTimeParseExceptionが発生するかどうかで判定できます。
  • エポックミリ秒(long型)への変換: ZonedDateTime.toInstant().toEpochMilli()で、古いDateクラスや外部APIと連携するためのミリ秒形式を取得できます。

Java 8より前の時代には、こうした操作を行うために「その月の1日を求めてから1ヶ月足して1日引く」といったトリッキーなコードを書く必要がありました。しかし現在のAPIでは、目的をそのままコードに書けるようなメソッドが豊富に用意されています。積極的に活用して、読みやすくバグの少ないプログラムを目指しましょう。

カテゴリの一覧へ
新着記事
New1
Quarkus
VSCodeでQuarkus開発が快適になる拡張機能まとめ!初心者向け開発環境構築ガイド
New2
Quarkus
Quarkusでテスト環境を構築する方法を完全解説!JUnitとMockitoで始める初心者向けテスト入門
New3
Quarkus
Quarkus 3.x の最新動向と新機能を徹底解説!Javaエンジニアのための次世代フレームワーク完全ガイド
New4
Micronaut
Micronautの依存関係をGradleで追加する方法!implementationの基本を解説
人気記事
No.1
Java&Spring記事人気No1
Micronaut
Micronautのフィルタ徹底解説!HTTPリクエスト共通処理をスマートに追加する方法
No.2
Java&Spring記事人気No2
Quarkus
Quarkus入門!GitHub ActionsでCI/CDパイプラインを構築して自動ビルドを実現する方法
No.3
Java&Spring記事人気No3
Quarkus
Quarkus拡張開発入門!自作Extensionを作る基本ステップと仕組みを徹底解説
No.4
Java&Spring記事人気No4
Micronaut
Micronautで非同期HTTP処理を行う方法!リアクティブ対応の基礎知識
No.5
Java&Spring記事人気No5
Quarkus
QuarkusのCI/CD入門!GitHub Actionsで自動デプロイを実現する方法
No.6
Java&Spring記事人気No6
Quarkus
Quarkus拡張開発をマスター!ビルドプロセスの仕組みと内部構造を徹底解説
No.7
Java&Spring記事人気No7
Micronaut
Micronautのリクエスト制限(Rate Limiting)を徹底解説!サーバーを守る流量制御
No.8
Java&Spring記事人気No8
Java
Javaの型変換(キャスト)を徹底解説!暗黙的・明示的変換の違いを整理