Java日付 - Date-Time API

LocalDateTime/OffsetDateTime/ZonedDateTime

概要

Java SE 8から、日付/時刻を扱う新しいAPIとしてDate and Time APIが導入されました。Date-Time APIはjava.timeパッケージに含まれています。
java.timeパッケージで提供される主なクラスは次のとおりです。

  • LocalDateTime/LocalDate/LocalTime: 時差情報のないローカル日時
  • OffsetDateTime/OffsetTime: 時差情報を持つ日付と時刻
  • ZonedDateTime: タイムゾーンと地域に基づく情報(サマータイムなど)を持つ日付と時刻

一般的には、時差情報を必要としない場合はLocalクラスを使用し、そうでない場合はZonedクラスを使用する形で区別されます。Offset~クラスを利用する場面はあまり多くないと思われます。

LocalDateTimenow/of/parseメソッド

now/of/parseメソッドは、文字列から日付/時刻値を生成します。

public static LocalDateTime now()
public static LocalDateTime of(int year, int month, int day, int hour, int minute [,int second [,int nano]])
public static LocalDate parse(CharSequence text)
    year: 
    month: 
    day: 
    hour: 
    minute: 
    second: 
    nano: ナノ秒
    text: 日付/時刻文字列

java.timeパッケージでは、目的に応じてLocal/Offset/Zoned系のクラスが用意されており、これらのメソッドによる生成方法は同じです。現在時刻を表示するにはnowメソッドを使用します。ofメソッドは年月日/時分秒を指定してオブジェクトを生成します。parseメソッドを使用して日付/時刻文字列からオブジェクトを生成することもできます。

package com.devkuma.basic.datetime;

import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;

public class TimeCreate {
    public static void main(String[] args) {
        LocalDateTime local = LocalDateTime.now();
        System.out.println(local);
        // 結果: 2022-09-05T12:03:34.123041

        OffsetDateTime offset = OffsetDateTime.of(
                2022, 9, 5, 12, 3, 29, 0, ZoneOffset.of("+09:00"));
        System.out.println(offset);
        // 結果: 2022-09-05T12:03:29+09:00

        ZonedDateTime zoned = ZonedDateTime.parse("2022-09-05T12:03:29+09:00[Asia/Seoul]");
        System.out.println(zoned);
        // 結果: 2022-09-05T12:03:29+09:00[Asia/Seoul]
    }
}

実行結果:

2022-09-05T12:03:34.123041
2022-09-05T12:03:29+09:00
2022-09-05T12:03:29+09:00[Asia/Seoul]

各オブジェクトでは、次のメソッドを使用してそれぞれの日付/時刻要素にアクセスすることもできます。

各日付/時刻要素にアクセスするメソッド

メソッド 概要
getYear
getMonth 月(Month型)
getMonthValue 月(1~12)
getDayOfMonth
getDayOfWeek 曜日
getDayOfYear 年内通算日
getHour
getMinute
getSecond
getNano ナノ秒

betweenメソッド

betweenメソッドは、日付/時刻値の差を求めます。

public static Period between(LocalDate start, LocalDate end) // Period
public static Duration between(Temporal start, Temporal end) // Duration
    start: 開始日時
    end: 終了日時

Period/Duration#betweenメソッドを使用すると、日付/時刻オブジェクト間の時間差を求められます。Periodは日付の間隔を表し、Durationは時間の間隔を表すオブジェクトです。

  • TemporalクラスはLocal/Offset/Zoned系クラスの共通インターフェースです。

次は、あらかじめ用意した2つの日付/時刻の差をPeriod/Duration#betweenメソッドで求める例です。

TimeBetween.java

package com.devkuma.basic.datetime;

import java.time.Duration;
import java.time.LocalDateTime;
import java.time.Period;

public class TimeBetween {
    public static void main(String[] args) {
        LocalDateTime local1 = LocalDateTime.of(
                2021, 1, 1, 3, 30, 0, 0);
        LocalDateTime local2 = LocalDateTime.of(
                2022, 9, 5, 12, 14, 30, 0);
        System.out.println(local1); // 結果: 2021-01-01T03:30
        System.out.println(local2); // 結果: 2022-09-05T12:14:30

        Period period = Period.between(local1.toLocalDate(), local2.toLocalDate());
        System.out.println("날짜 차이: " + period);   // 結果: 날짜 차이: P1Y8M4D

        System.out.println("날짜 차이: " +
                period.getYears() + "년 " + period.getMonths() + "월 " +
                period.getDays() + "일"); // 結果: 날짜 차이: 1년 8월 4일

        Duration duration = Duration.between(local1, local2);
        System.out.println("시간 차이: " + duration);
        // 結果: 시간 차이: PT14696H44M30S

        System.out.println("시간 차이: " + duration.toHours() + "시간");
        // 結果: 시간 차이: 14696시간

        System.out.println("시간 차이: " + duration.toMinutes() + "분");
        // 結果: 시간 차이: 881804분

        System.out.println("시간 차이: " + duration.getSeconds() + "초");
        // 結果: 시간 차이: 52908270초
    }
}

実行結果:

2021-01-01T03:30
2022-09-05T12:14:30
날짜 차이: P1Y8M4D
날짜 차이: 1년 8월 4일
시간 차이: PT14696H44M30S
시간 차이: 14696시간
시간 차이: 881804분
시간 차이: 52908270초

Period/Durationオブジェクトから日数や時間数を求めるには、次のようなメソッドを使用します。

Period/Durationクラスの主なメソッド

クラス メソッド 概要
Period getYears 年数
getMonths 月数
getDays 日数
Duration toDays 日数
toHours 時間数
toMinutes 分数
toMillis ミリ秒数
toNanos ナノ秒数

日付および時刻データの計算

public LocalDateTime plus(long value, TemporalUnit unit)
public LocalDateTime minus(long value, TemporalUnit unit)
    value: 増減分
    unit: 単位

plus/minusメソッドを使用すると、日付/時刻要素を加算または減算できます。引数unitには、TemporalUnitインターフェースの実装クラスであるChronoUnitの定数で、追加または減算したい単位を指定します。

TemporalUnitインターフェースの主な定数

定数 概要
YEARS
MONTHS
DAYS
WEEKS
HOURS 時間
MINUTES
SECONDS
MILLIS ミリ秒
NANOS ナノ秒

次は、あらかじめ用意した日付について、3か月後と10日前の日付を求める例です。

package com.devkuma.basic.datetime;

import java.time.LocalDateTime;

public class TimePlus {
    public static void main(String[] args) {
        LocalDateTime local = LocalDateTime.parse("2022-09-05T12:30");
        System.out.println(local);  // 結果: 2022-09-05T12:30
        System.out.println(local.plusMonths(3));    // 結果: 2022-12-05T12:30
        System.out.println(local.minusDays(10));    // 結果: 2022-08-26T12:30
    }
}

実行結果:

2022-09-05T12:30
2022-12-05T12:30
2022-08-26T12:30

また、plus/minusメソッドには、それぞれの日付/時刻要素に特化したメソッドが次のように用意されています。

日付/時刻を加算/減算するメソッド

メソッド 概要
plusYears/minusYears
plusMonths/minusMonths
plusDays/minusDays
plusWeeks/minusWeeks 週数
plusHours/minusHours 時間
plusMinutes/minusMinutes
plusSeconds/minusSeconds
plusNanos/minusNanos ナノ秒

Date/CalendarクラスからDate-Time APIクラスへの相互変換

public static Date from(Instant instant) // Date
public Instant toInstant() // Date/Calendar
public static LocalDateTime ofInstant(Instant instant, ZoneId zone) // XxxxxDateTime
    instant: 変換するインスタント

新しくDate-Time APIが導入されたとはいえ、突然すべてのコードをDate-Time APIに統一するのは現実的には簡単ではありません。当面は既存のjava.utilパッケージと併用することになるでしょう。そのため、既存のDate/Calendarクラスには、Date-Time APIと相互変換するためのメソッドが提供されています。
Date#fromメソッドは、指定されたInstantオブジェクトからDateオブジェクトを生成します。Instantは、日付時刻を1970年1月1日以降の経過時間として保持するクラスです。Date-Time APIの日付/時刻クラスはそれぞれtoInstantメソッドを提供しており、Instantオブジェクトを生成できるため、これをfromメソッドに渡すとDateオブジェクトを生成できます。

  • CalendarクラスにはDate#fromメソッドに相当するメソッドはありません。生成されたDateオブジェクトからCalendarオブジェクトを生成します。

Calendar/DateクラスにもtoInstantメソッドが提供されています。生成されたInstantオブジェクトをLocalDateTime/OffsetDateTime/ZonedDateTimeクラスのofInstantメソッドに渡すことで、それぞれ対応するオブジェクトを生成できます。

次は、LocalDateTimeオブジェクトをDateオブジェクトへ、CalendarオブジェクトをLocalDateTimeオブジェクトへ変換する例です。

package com.devkuma.basic.datetime;

import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.util.Calendar;
import java.util.Date;

public class TimeTrans {
    public static void main(String[] args) {
        LocalDateTime local = LocalDateTime.now();
        System.out.println(local);  // 結果: 2022-09-05T14:32:05.526238

        Instant instant = local.toInstant(ZoneOffset.of("+09:00"));
        Date date = Date.from(instant);
        System.out.println(date);   // 結果: Mon Sep 05 14:32:05 KST 2022

        Calendar cal = Calendar.getInstance();
        Instant instant2 = cal.toInstant();
        LocalDateTime local2 = LocalDateTime.ofInstant(instant2, ZoneId.of("Asia/Seoul"));
        System.out.println(local2); // 結果: 2022-09-05T14:32:05.542
    }
}

実行結果:

2022-09-05T14:32:05.526238
Mon Sep 05 14:32:05 KST 2022
2022-09-05T14:32:05.542

StringからLocalDate/LocalDateTimeへ変換する方法

Stringjava.time.LocalDateへ変換する場合は、LocalDate.parseDateTimeFormatterを利用して日付文字列を変換します。
Stringjava.time.LocalDateTimeへ変換する場合は、文字列をLocalDateにし、LocalTimeと一緒に引数として受け取って生成します。

package com.devkuma.basic.datetime;

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

public class StringConvent {
    public static void main(String[] args) {
        String strDate = "2022/12/12";
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy/MM/dd");

        LocalDate localDate = LocalDate.parse(strDate, dateTimeFormatter);
        System.out.println(localDate);

        LocalDateTime ldt = LocalDateTime.of(localDate, LocalTime.of(0, 0));
        System.out.println(ldt);
    }
}

実行結果:

2022-12-12
2022-12-12T00:00

日付文字列が2022/12/12のような形式であれば、Format指定はDateTimeFormatter.ISO_DATEで代替できます。DateTimeFormatter.ISO_DATEyyyy-MM-ddを定数として宣言します。