Java 逆引き集 | 日付時間API(java.time: LocalDate/LocalDateTime/Duration) — 日時処理

Java Java
スポンサーリンク

日付時間API(java.time: LocalDate / LocalDateTime / Duration) — 日時処理

日時は「正しく扱えるか」で品質が決まります。java.time(Java 8以降)は不変で安全、直感的なクラス設計で、旧来の Date/Calendar の弱点を解決します。まずは LocalDate/LocalDateTime/Duration に絞って、実務で使う定番をかみ砕いて解説します。


基本の考え方(不変・役割分担)

  • 不変(immutable): 値は変更されず、加算・減算は新しいインスタンスとして返る。スレッドセーフで扱いやすい。
  • 役割分担:
    • LocalDate: 年月日(タイムゾーンなし)
    • LocalDateTime: 年月日+時分秒(タイムゾーンなし)
    • Duration: 時間の差(秒・ナノ秒単位)。日付差は Period を使うが、今回は Duration に集中。
  • 旧APIとの違い: Date/Calendar は可変で直感的でない。今は java.time を基本にするのが推奨。

LocalDate(年月日)

生成・取得・加減算

import java.time.*;

var today = LocalDate.now();                 // 今日
var d1 = LocalDate.of(2025, 12, 7);          // 指定日
var nextWeek = today.plusWeeks(1);           // 1週間後
var lastMonth = today.minusMonths(1);        // 1ヶ月前

int year = today.getYear();
int month = today.getMonthValue();
int day = today.getDayOfMonth();
Java
  • ポイント: 可変ではなく、新しい値が返る。祝日計算などは別ライブラリかルール実装で対応。

比較・判定

boolean after = d1.isAfter(today);
boolean before = d1.isBefore(today);
DayOfWeek dow = today.getDayOfWeek(); // 月曜〜日曜
Java

LocalDateTime(年月日+時分秒)

生成・取得・加減算

import java.time.*;

var now = LocalDateTime.now();                        // 現在の日時
var dt = LocalDateTime.of(2025, 12, 7, 16, 30, 0);   // 指定日時
var plus = dt.plusHours(2).minusMinutes(15);         // 2時間加算→15分減算

int hour = now.getHour();
int minute = now.getMinute();
int second = now.getSecond();
Java
  • タイムゾーン注意: LocalDateTime はタイムゾーンを持たない。ゾーン付きが必要なら ZonedDateTime を使う。

ゾーン適用とInstant変換

var tokyo = ZoneId.of("Asia/Tokyo");
var zoned = dt.atZone(tokyo);        // LocalDateTime にゾーン適用
var instant = zoned.toInstant();     // UTC系の瞬間に変換
Java
  • 用途: DBや外部APIとやり取りする場合は Instant や ZonedDateTime を適切に使い分ける。

Duration(時間差:秒・ナノ秒)

生成・差分・加減算

import java.time.*;

var start = LocalDateTime.of(2025, 12, 7, 9, 0);
var end   = LocalDateTime.of(2025, 12, 7, 17, 30);
var dur = Duration.between(start, end);     // 差分(8時間30分)

long seconds = dur.getSeconds();            // トータル秒
var plus30m = dur.plusMinutes(30);          // 30分追加
Java
  • 注意: 日月年の差は Period。時間量やタイマーには Duration が適切。

フォーマットとパース(DateTimeFormatter)

文字列に整形

import java.time.format.DateTimeFormatter;

var fmtDate = DateTimeFormatter.ofPattern("yyyy-MM-dd");
var fmtDateTime = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

String s1 = today.format(fmtDate);     // 2025-12-07
String s2 = now.format(fmtDateTime);   // 2025-12-07 16:30:00(例)
Java

文字列から読み込み

var parsedDate = LocalDate.parse("2025-12-07", fmtDate);
var parsedDt = LocalDateTime.parse("2025-12-07 16:30:00", fmtDateTime);
Java
  • 定番フォーマット: ISO系(toString 既定)を基本に、表示だけ独自フォーマット。パース例外への対処も忘れずに。

例題で身につける

例題1: 締切日までの日数(LocalDate + Period)

import java.time.*;

var deadline = LocalDate.of(2025, 12, 31);
var today = LocalDate.now();
var daysLeft = deadline.toEpochDay() - today.toEpochDay(); // シンプルに日数差
System.out.println("残り日数: " + daysLeft);
Java
  • 解説: 日数差なら EpochDay の差分が簡単。月年をまたぐ「暦の差」計算は Period でも可。

例題2: 稼働時間の集計(LocalDateTime + Duration)

import java.time.*;

record Shift(LocalDateTime start, LocalDateTime end) {}

var s1 = new Shift(LocalDateTime.of(2025,12,7,9,0),  LocalDateTime.of(2025,12,7,12,0));
var s2 = new Shift(LocalDateTime.of(2025,12,7,13,0), LocalDateTime.of(2025,12,7,17,30));

var total = Duration.between(s1.start(), s1.end())
    .plus(Duration.between(s2.start(), s2.end()));
System.out.println("合計分: " + total.toMinutes()); // 450分
Java
  • 解説: 区間ごとに Duration を取り、合計するのが定石。ナノ秒精度で安全に扱える。

例題3: タイムゾーン付き表示(ZonedDateTime)

import java.time.*;
import java.time.format.*;

var utc = Instant.parse("2025-12-07T07:30:00Z"); // UTCの瞬間
var tokyoTime = utc.atZone(ZoneId.of("Asia/Tokyo"));
var fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss VV");
System.out.println(tokyoTime.format(fmt)); // 2025-12-07 16:30:00 Asia/Tokyo
Java
  • 解説: 表示はゾーンを適用してからフォーマット。夏時間の存在する地域では ZonedDateTime が不可欠。

すぐ使えるテンプレート

  • 今日・今・加減算
var today = LocalDate.now();
var now = LocalDateTime.now();
var nextMonth = today.plusMonths(1);
var in2h = now.plusHours(2);
Java
  • 差分(Duration)
var dur = Duration.between(start, end);
long minutes = dur.toMinutes();
Java
  • フォーマット/パース
var fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
String s = now.format(fmt);
var parsed = LocalDateTime.parse(s, fmt);
Java
  • ゾーン適用
var zoned = LocalDateTime.now().atZone(ZoneId.of("Asia/Tokyo"));
Java

実務のコツと落とし穴

  • タイムゾーンを意識: 保存は UTC(Instant)、表示はユーザのゾーン。LocalDateTime は「ゾーンなしの壁時計」。
  • 不変を前提に組み立てる: 加減算は新しい値。副作用を避けた処理が書ける。
  • フォーマットは集中管理: DateTimeFormatter を定数化して再利用、パース例外に備える。
  • 旧APIの混在を避ける: Date/Calendar はラップや変換に限定し、java.time を中心に。

まとめ

  • LocalDate / LocalDateTime / Duration を押さえれば、ほとんどの業務日時は安全に扱える。
  • 不変・直感的なAPIで、加減算・差分・フォーマット・ゾーン適用がシンプル。
  • 保存と表示を分ける設計(UTC保存+ゾーン表示)で、国際化や夏時間にも対応しやすい。

タイトルとURLをコピーしました