LocalDateTime をざっくり一言でいうと
LocalDateTime は、
「日付(年・月・日)+時刻(時・分・秒)」を、タイムゾーンなしで表すクラス
です。
LocalDate が「日付だけ」LocalTime が「時刻だけ」
だとしたら、LocalDateTime はその合体版。
「2025 年 1 月 10 日 9 時 30 分」という“カレンダー上の日時”を扱いたいときに使います。
ただし、「それが世界のどの場所の 9:30 か」は含まない、というのが重要なポイントです。
会議日時、締切日時、予約時刻など
「日付と時刻がセットで必要」な場面の基本形が LocalDateTime です。
LocalDateTime の基本:生成と分解
「今この瞬間」と「指定した日時」を作る
まずは一番よく使う作り方から。
import java.time.LocalDateTime;
public class LocalDateTimeBasic {
public static void main(String[] args) {
// 今この瞬間(PC のタイムゾーン基準)
LocalDateTime now = LocalDateTime.now();
System.out.println("now = " + now); // 例: 2025-01-10T09:30:15.123456789
// 指定した日時(2025/01/10 09:30:00)
LocalDateTime meeting =
LocalDateTime.of(2025, 1, 10, 9, 30);
System.out.println("meeting = " + meeting); // 2025-01-10T09:30
}
}
Javaof(年, 月, 日, 時, 分) で、直感通りに指定できます。Date のような「月は 0 始まり」みたいな罠はありません。
秒やナノ秒まで指定したければ、引数を増やせます。
LocalDateTime precise =
LocalDateTime.of(2025, 1, 10, 9, 30, 15, 123_000_000);
// 2025-01-10T09:30:15.123(ナノ秒まで)
Java年・月・日・時・分・秒をばらす
import java.time.LocalDateTime;
LocalDateTime dt = LocalDateTime.of(2025, 1, 10, 9, 30, 15);
int year = dt.getYear(); // 2025
int month = dt.getMonthValue(); // 1
int day = dt.getDayOfMonth(); // 10
int hour = dt.getHour(); // 9
int minute = dt.getMinute(); // 30
int second = dt.getSecond(); // 15
Java「年月日」と「時分秒」が 1 つにまとまっている感覚を掴んでください。
ただし、タイムゾーン(日本かニューヨークか)は含んでいないのがミソです。
LocalDate / LocalTime との関係(頭の中の整理)
LocalDate + LocalTime → LocalDateTime
LocalDateTime は、LocalDate と LocalTime から簡単に作れます。
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
LocalDate date = LocalDate.of(2025, 1, 10);
LocalTime time = LocalTime.of(9, 30);
LocalDateTime dt1 = LocalDateTime.of(date, time);
LocalDateTime dt2 = date.atTime(time);
LocalDateTime dt3 = time.atDate(date);
Javaどれも結果は同じ「2025-01-10T09:30」です。
「日付は別で扱いたいけど、DB には日時として保存したい」
みたいな場面で、LocalDate + LocalTime を一時的に LocalDateTime にまとめる、という使い方もよくします。
LocalDateTime から LocalDate / LocalTime を取り出す
逆方向も簡単です。
LocalDateTime dt = LocalDateTime.of(2025, 1, 10, 9, 30);
LocalDate dateOnly = dt.toLocalDate(); // 2025-01-10
LocalTime timeOnly = dt.toLocalTime(); // 09:30
Java「ロジック的には日付だけ欲しい」「時刻だけ比べたい」
というときは、分解して考えるとシンプルになります。
LocalDateTime の「不変性」とその意味
不変(immutable)なので勝手に書き換わらない
LocalDateTime も LocalDate / LocalTime と同じく、不変です。
LocalDateTime dt1 = LocalDateTime.of(2025, 1, 10, 9, 30);
LocalDateTime dt2 = dt1.plusDays(1);
System.out.println(dt1); // 2025-01-10T09:30
System.out.println(dt2); // 2025-01-11T09:30
JavaplusDays(1) を呼んでも、dt1 は一切変わりません。
新しい LocalDateTime が返ってくるだけです。
この設計のおかげで、
メソッドに渡した日時が、中で勝手に書き換えられない
スレッドが複数あっても、「データ競合」で日時が壊れない
という安全性が得られます。
日時の加算・減算・比較(よく使うところを重点的に)
plusXxx / minusXxx で足し引きする
代表的なものはこうです。
LocalDateTime dt = LocalDateTime.of(2025, 1, 10, 9, 30);
LocalDateTime plusDays = dt.plusDays(3); // 3 日後 → 2025-01-13T09:30
LocalDateTime minusDays = dt.minusDays(5); // 5 日前 → 2025-01-05T09:30
LocalDateTime plusHours = dt.plusHours(2); // 2 時間後 → 11:30
LocalDateTime plusMinutes = dt.plusMinutes(90); // 90 分後 → 11:00
LocalDateTime plusMonths = dt.plusMonths(1); // 1 か月後
LocalDateTime plusYears = dt.plusYears(1); // 1 年後
Java月末やうるう年をまたいだときも、カレンダールールに従ってうまく処理してくれます。
日時計算の基本は「plusXxx / minusXxx を使う」で覚えておけば大丈夫です。
日時の前後関係を調べる
LocalDateTime 同士の比較は isBefore, isAfter, equals で書けます。
LocalDateTime dt1 = LocalDateTime.of(2025, 1, 10, 9, 30);
LocalDateTime dt2 = LocalDateTime.of(2025, 1, 10, 10, 0);
boolean b1 = dt1.isBefore(dt2); // true
boolean b2 = dt1.isAfter(dt2); // false
boolean b3 = dt1.equals(dt2); // false
Javaもう少し実務寄りの例にすると、
「締切日時より前か?」
「予約日時が現在時刻より後か?」
などを自然な条件で書けます。
LocalDateTime now = LocalDateTime.now();
LocalDateTime deadline = LocalDateTime.of(2025, 1, 31, 23, 59);
boolean inTime = now.isBefore(deadline) || now.equals(deadline);
Java日本語に直すと「現在が締切以前かどうか」です。
文字列との相互変換(日時の表示と入力)
LocalDateTime → 文字列(format)
画面表示やログ出力などで、日時を文字列にしたい場面は多いです。DateTimeFormatter を使います。
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
public class LocalDateTimeFormat {
public static void main(String[] args) {
LocalDateTime dt = LocalDateTime.of(2025, 1, 10, 9, 30, 15);
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss");
String s = dt.format(fmt);
System.out.println(s); // 2025/01/10 09:30:15
}
}
JavaDateTimeFormatter はスレッドセーフなので、SimpleDateFormat のように「static で共有したら壊れた」みたいな事故が起きません。
文字列 → LocalDateTime(parse)
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
public class LocalDateTimeParse {
public static void main(String[] args) {
String text = "2025-01-10T09:30:15";
// ISO 形式(yyyy-MM-ddTHH:mm:ss)はそのまま parse 可能
LocalDateTime dt1 = LocalDateTime.parse(text);
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm");
LocalDateTime dt2 = LocalDateTime.parse("2025/01/10 09:30", fmt);
System.out.println(dt1); // 2025-01-10T09:30:15
System.out.println(dt2); // 2025-01-10T09:30
}
}
Javaフォーム入力や設定ファイル・CSV などから「日時文字列」を取り込むときの定番パターンです。
LocalDateTime とタイムゾーン/Instant/Date の関係(ここが重要)
ここは少し深掘りします。LocalDateTime をちゃんと使いこなしたいなら、「何を持っていないか」を理解するのが大事だからです。
LocalDateTime は「タイムゾーンを持っていない」
LocalDateTime は、「2025-01-10 09:30」という“カレンダー上の日時”であって、
「東京の 9:30」なのか「ニューヨークの 9:30」なのかまでは表しません。
同じ「2025-01-10T09:30」でも、
東京で解釈したら「世界標準時では 0:30」
ロンドンで解釈したら「世界標準時では 9:30」
というように、「世界共通の瞬間」としては別物です。
「世界共通の一瞬」を表すのは Instant や Date の役割です。
LocalDateTime ↔ Instant / Date に変換するときは「ZoneId」が必須
LocalDateTime を「世界共通の瞬間(Instant)」に変換するときは、必ずタイムゾーンを指定します。
import java.time.*;
LocalDateTime dt = LocalDateTime.of(2025, 1, 10, 9, 30);
ZoneId tokyo = ZoneId.of("Asia/Tokyo");
Instant instant = dt.atZone(tokyo).toInstant();
System.out.println(instant); // 例: 2025-01-10T00:30:00Z(UTC)
Java逆に、Instant から LocalDateTime に戻すときも同じです。
Instant instant = Instant.now();
ZoneId tokyo = ZoneId.of("Asia/Tokyo");
LocalDateTime dt = LocalDateTime.ofInstant(instant, tokyo);
System.out.println(dt); // 東京時間での現在日時
JavaDate との変換も、「Instant を経由して、ZoneId を意識する」のが鉄板パターンです。
import java.time.*;
import java.util.Date;
// Date → LocalDateTime(東京時間で解釈)
Date legacy = new Date();
Instant instant = legacy.toInstant();
ZoneId tokyo = ZoneId.of("Asia/Tokyo");
LocalDateTime dt = LocalDateTime.ofInstant(instant, tokyo);
// LocalDateTime → Date(東京時間として)
Instant instant2 = dt.atZone(tokyo).toInstant();
Date date = Date.from(instant2);
Javaここでのキモは、
LocalDateTime 自体はタイムゾーンを持たない
「どこの国の日時として解釈するか」を指定した瞬間に、世界共通の Instant にマッピングされる
という感覚です。
LocalDateTime をどんなときに使うべきか(実務的な勘どころ)
向いている場面
例えば、こんな場面では LocalDateTime がしっくり来ます。
予約日時
会議の開始日時
締切日時(「2025-01-31 23:59」など)
クライアントローカルで完結する予定(カレンダーアプリなど)
「ユーザーの住んでいる場所のカレンダー上の日時として意味がある」
という場面です。
あまり向いていない場面
逆に、次のような場面では LocalDateTime だけだと情報不足です。
ログのタイムスタンプ(世界中どこで見ても一意な瞬間が必要)
「サーバー間で日時をやり取りするプロトコル」
タイムゾーンをまたいで厳密に比較するスケジューリング
こういうときは、
保存・通信は Instant(もしくは UTC の OffsetDateTime / ZonedDateTime)
表示やローカル操作のときだけ、ユーザーのタイムゾーンで LocalDateTime に変換
という設計のほうが安全です。
まとめ:LocalDateTime を自分の中でどう位置づけるか
LocalDateTime を初心者向けに一言でまとめると、
「日付+時刻をセットで持つ“カレンダー上の日時”を、タイムゾーン抜きで表すクラス」
です。
押さえておきたいポイントは次の通りです。
- 年・月・日・時・分・秒を 1 つで扱えるが、タイムゾーンは持たない
- 不変(immutable)で、安全に使いまわせる
plusXxx/minusXxxで日時計算、isBefore/isAfterで比較が直感的DateTimeFormatterでフォーマット/パースができ、Date/InstantとはZoneIdを挟んで変換する
