Java : 日付・時刻の基本

日付・時刻の作成、現在時刻の取得、演算などなど。
Java 8 で追加された新しいAPIの LocalDate, LocalTime, LocalDateTime, ZonedDateTime の基本的な使い方をご紹介します。


用語の定義

本記事では、時間に関する用語を以下のように定義します。

用語 定義
日付 年と月と日 2021/5/4
2000年12月31日
時刻 時と分と秒 12:30:59
7時30分45秒
日時 日付と時刻 2021/5/4 12:30:59
2000年12月31日 7時30分45秒
時点 時間軸上の一点。
(具体的にはエポック秒とナノ秒で表します)
1609504200.123
(日時に変換すると 2021-01-01T12:30:00.123Z となります)

日付・時刻のAPI

日付、時間、インスタント、デュレーションのメインAPI。
ここで定義されるクラスは主要な日付/時間の概念(時点、デュレーション、日付、時間、タイムゾーン、期間など)を表します。

日付・時刻のAPIは java.time パッケージにあります。
主に使うAPIを簡単にまとめます。

クラス 説明 使用例
LocalDate 日付(タイムゾーンなし)
final var date = LocalDate.of(2021, 5, 1);
System.out.println(date); // 2021-05-01
LocalTime 時刻(タイムゾーンなし)
final var time = LocalTime.of(12, 30, 45);
System.out.println(time); // 12:30:45
LocalDateTime 日時(タイムゾーンなし)
final var dateTime = LocalDateTime.of(2021, 5, 1, 12, 30, 45);
System.out.println(dateTime); // 2021-05-01T12:30:45
ZoneId タイムゾーンID。
日本だと"Asia/Tokyo"となり時差は"+09:00"です。
final var zoneId = ZoneId.systemDefault();
System.out.println(zoneId); // Asia/Tokyo
ZonedDateTime 日時(タイムゾーンあり)
final var zoneId = ZoneId.systemDefault();
final var zonedDateTime = ZonedDateTime.of(2021, 5, 1, 12, 30, 45, 0, zoneId);
System.out.println(zonedDateTime); // 2021-05-01T12:30:45+09:00[Asia/Tokyo]
Instant 時点
final var instant = Instant.ofEpochSecond(1609849845L);
System.out.println(instant); // 2021-01-05T12:30:45Z

共通の特徴

不変(イミュータブル)なオブジェクト

java.time パッケージのAPIは不変(イミュータブル)なオブジェクトです。
つまりスレッドセーフでもあります。

値を変更できないと不便では…と思われるかもしれません。
大丈夫です。間接的に変更できる便利なメソッドが用意されています。(with~メソッド)

本記事は基本…ということで、不変オブジェクトのメリットについては割愛します。
もう少し詳しく知りたい方は下記の関連記事もご参照ください。

関連記事:不変オブジェクト(イミュータブル) とは

文字列表記(ISO 8601)

基本的な文字列表記(toStringの結果)は ISO 8601 の拡張形式になります。
ISO 8601 は Javaに限らずいろいろなプログラミング言語でお目にかかるので、理解しておいて損はないでしょう。

ISO 8601は、日付と時刻の表記に関するISOの国際規格である。

形式 表記例
基本形式 20210428T164723
拡張形式 2021-04-28T16:47:23

ちょっと見慣れないのが、日付と時刻を区切る文字として T を使っているところでしょうか。

ユーザに見せる表記としては向いていませんが、プログラム内で管理するには ISO 8601 を使うと便利なことも多いです。
(例えば、ユーザには見せないテキストファイルに日時を保存したい場合など)

LocalDate

ISO-8601暦体系のタイムゾーンのない日付、2007-12-03など。
LocalDateは、日付(年-月-日として表示されることが多い)を表す不変の日付/時間オブジェクトです。 他の日付フィールド(「年の日」、曜日、「年の週番号」など)にもアクセスできます。 たとえば、「2007年10月2日」という値をLocalDateに格納できます。

クラス構成

LocalDate は、タイムゾーンのない日付を表します。

例えば、2007-12-03 や 2021-05-01 などです。
また、曜日の情報も取得できます。(2021年12月18日土曜日など)

LocalDate の作成には of メソッドを使います。

// 作成
final LocalDate date = LocalDate.of(2021, 5, 1);
System.out.println(date); // 2021-05-01

// 年月日の取得
System.out.println(date.getYear()); // 2021
System.out.println(date.getMonthValue()); // 5
System.out.println(date.getDayOfMonth()); // 1
// 現在の日付を取得
final LocalDate now = LocalDate.now();
System.out.println(now); // 2021-05-17
// 曜日の取得
final LocalDate date1 = LocalDate.of(2021, 5, 2);
System.out.println(date1); // 2021-05-02
System.out.println(date1.getDayOfWeek()); // SUNDAY

final LocalDate date2 = LocalDate.of(2021, 5, 3);
System.out.println(date2); // 2021-05-03
System.out.println(date2.getDayOfWeek()); // MONDAY

final LocalDate date3 = LocalDate.of(2021, 5, 4);
System.out.println(date3); // 2021-05-04
System.out.println(date3.getDayOfWeek()); // TUESDAY

文字列へ変換するには、format メソッドと DateTimeFormatter を使います。

final LocalDate date = LocalDate.of(2021, 5, 1);

final var str1 = date.format(DateTimeFormatter.ISO_LOCAL_DATE);
System.out.println(str1); // 2021-05-01

final var str2 = date.format(DateTimeFormatter.ofPattern("yyyy/MM/dd"));
System.out.println(str2); // 2021/05/01

final var str3 = date.format(DateTimeFormatter.ofPattern("yyyy年MM月dd日(E)"));
System.out.println(str3); // 2021年05月01日(土)

with~メソッドを使うことで、with~で指定した要素と、それ以外は元のオブジェクトの値を引き継いだ新しい LocalDate を作成できます。
setter の代わりとして使えます。

final LocalDate date = LocalDate.of(2021, 5, 1);
System.out.println(date); // 2021-05-01

// 年が変更されたコピーを返します。
final LocalDate update1 = date.withYear(1999);
System.out.println(update1); // 1999-05-01

// 月が変更されたコピーを返します。
final LocalDate update2 = date.withMonth(12);
System.out.println(update2); // 2021-12-01

// 日が変更されたコピーを返します。
final LocalDate update3 = date.withDayOfMonth(31);
System.out.println(update3); // 2021-05-31

日付の演算には、plus~メソッド、minus~メソッドを使います。

final LocalDate date = LocalDate.of(2021, 5, 1);
System.out.println(date); // 2021-05-01

final LocalDate update1 = date.plusYears(5);
System.out.println(update1); // 2026-05-01

final LocalDate update2 = date.minusMonths(3);
System.out.println(update2); // 2021-02-01

final LocalDate update3 = date.plusDays(50);
System.out.println(update3); // 2021-06-20

LocalTime

ISO-8601暦体系における、タイムゾーンのない時間(10:15:30など)。
LocalTimeは、時間(時-分-秒として表示されることが多い)を表す不変の日付/時間オブジェクトです。 時間は、ナノ秒の精度まで表されます。 たとえば、「13:45.30.123456789」という値をLocalTimeに格納できます。

クラス構成

LocalTime は、タイムゾーンのない時刻を表します。
例えば、10:15:30 や 13:45.30.123456789 などです。

LocalTime の作成には of メソッドを使います。

// 作成
final LocalTime time = LocalTime.of(18, 30, 45);
System.out.println(time); // 18:30:45

// 時分秒の取得
System.out.println(time.getHour()); // 18
System.out.println(time.getMinute()); // 30
System.out.println(time.getSecond()); // 45
// 現在時刻を取得
final LocalTime now = LocalTime.now();
System.out.println(now); // 16:54:02.676090600

文字列へ変換するには、format メソッドと DateTimeFormatter を使います。

final LocalTime time = LocalTime.of(18, 30, 45);

final var str1 = time.format(DateTimeFormatter.ISO_LOCAL_TIME);
System.out.println(str1); // 18:30:45

final var str2 = time.format(DateTimeFormatter.ofPattern("HH時mm分ss秒"));
System.out.println(str2); // 18時30分45秒

final var str3 = time.format(DateTimeFormatter.ofPattern("a hh:mm:ss"));
System.out.println(str3); // 午後 06:30:45

with~メソッドを使うことで、with~で指定した要素と、それ以外は元のオブジェクトの値を引き継いだ新しい LocalTime を作成できます。
setterの代わりとして使えます。

final LocalTime time = LocalTime.of(18, 30, 45);
System.out.println(time); // 18:30:45

// 時が変更されたコピーを返します。
final LocalTime update1 = time.withHour(9);
System.out.println(update1); // 09:30:45

// 分が変更されたコピーを返します。
final LocalTime update2 = time.withMinute(15);
System.out.println(update2); // 18:15:45

// 秒が変更されたコピーを返します。
final LocalTime update3 = time.withSecond(0);
System.out.println(update3); // 18:30

時刻の演算には、plus~メソッド、minus~メソッドを使います。

final LocalTime time = LocalTime.of(18, 30, 45);
System.out.println(time); // 18:30:45

final LocalTime update1 = time.plusHours(2);
System.out.println(update1); // 20:30:45

final LocalTime update2 = time.minusMinutes(10);
System.out.println(update2); // 18:20:45

final LocalTime update3 = time.plusSeconds(100);
System.out.println(update3); // 18:32:25

LocalDateTime

ISO-8601暦体系のタイムゾーンのない日付/時間、2007-12-03T10:15:30など。
LocalDateTimeは、日付/時間(年-月-日-時-分-秒として表示されることが多い)を表す不変の日付/時間オブジェクトです。他の日付と時間フィールド(「年の日」、曜日、「年の週番号」など)にもアクセスできます。時間は、ナノ秒の精度まで表されます。 たとえば、「2007年10月2日の13:45.30.123456789」という値をLocalDateTimeに格納できます。

クラス構成

LocalDateTime は、タイムゾーンのない日時を表します。
例えば、2007-12-03T10:15:30 や 2021-05-01T18:30:45 などです。

LocalDateTime の作成には of メソッドを使います。

// 作成
final LocalDateTime dateTime1 = LocalDateTime.of(2021, 5, 1, 18, 30, 45);
System.out.println(dateTime1); // 2021-05-01T18:30:45

// LocalDate, LocalTimeから作成
final LocalDate date = LocalDate.of(2021, 5, 1);
final LocalTime time = LocalTime.of(18, 30, 45);

final LocalDateTime dateTime2 = LocalDateTime.of(date, time);
System.out.println(dateTime2); // 2021-05-01T18:30:45
// 現在日時を取得
final LocalDateTime now = LocalDateTime.now();
System.out.println(now); // 2021-05-17T16:56:38.742354200
final LocalDateTime dateTime = LocalDateTime.of(2021, 5, 1, 18, 30, 45);

// 年月日の取得
System.out.println(dateTime.getYear()); // 2021
System.out.println(dateTime.getMonthValue()); // 5
System.out.println(dateTime.getDayOfMonth()); // 1

// 時分秒の取得
System.out.println(dateTime.getHour()); // 18
System.out.println(dateTime.getMinute()); // 30
System.out.println(dateTime.getSecond()); // 45

文字列へ変換するには、format メソッドと DateTimeFormatter を使います。

final LocalDateTime dateTime = LocalDateTime.of(2021, 5, 1, 18, 30, 45);

final var str1 = dateTime.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME);
System.out.println(str1); // 2021-05-01T18:30:45

final var str2 = dateTime.format(DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss"));
System.out.println(str2); // 2021/05/01 18:30:45

final var str3 = dateTime.format(DateTimeFormatter.ofPattern("yyyy年MM月dd日(E) a hh時mm分ss秒"));
System.out.println(str3); // 2021年05月01日(土) 午後 06時30分45秒

with~メソッドを使うことで、with~で指定した要素と、それ以外は元のオブジェクトの値を引き継いだ新しい LocalDateTime を作成できます。
setterの代わりとして使えます。

final LocalDateTime dateTime = LocalDateTime.of(2021, 5, 1, 18, 30, 45);
System.out.println(dateTime); // 2021-05-01T18:30:45

// 年が変更されたコピーを返します。
final LocalDateTime update1 = dateTime.withYear(1999);
System.out.println(update1); // 1999-05-01T18:30:45

// 月が変更されたコピーを返します。
final LocalDateTime update2 = dateTime.withMonth(12);
System.out.println(update2); // 2021-12-01T18:30:45

// 日が変更されたコピーを返します。
final LocalDateTime update3 = dateTime.withDayOfMonth(31);
System.out.println(update3); // 2021-05-31T18:30:45

// 時が変更されたコピーを返します。
final LocalDateTime update4 = dateTime.withHour(9);
System.out.println(update4); // 2021-05-01T09:30:45

// 分が変更されたコピーを返します。
final LocalDateTime update5 = dateTime.withMinute(15);
System.out.println(update5); // 2021-05-01T18:15:45

// 秒が変更されたコピーを返します。
final LocalDateTime update6 = dateTime.withSecond(0);
System.out.println(update6); // 2021-05-01T18:30

日時の演算には、plus~メソッド、minus~メソッドを使います。

final LocalDateTime dateTime = LocalDateTime.of(2021, 5, 1, 18, 30, 45);
System.out.println(dateTime); // 2021-05-01T18:30:45

final LocalDateTime update1 = dateTime.plusYears(5);
System.out.println(update1); // 2026-05-01T18:30:45

final LocalDateTime update2 = dateTime.minusMonths(3);
System.out.println(update2); // 2021-02-01T18:30:45

final LocalDateTime update3 = dateTime.plusDays(50);
System.out.println(update3); // 2021-06-20T18:30:45

final LocalDateTime update4 = dateTime.plusHours(2);
System.out.println(update4); // 2021-05-01T20:30:45

final LocalDateTime update5 = dateTime.minusMinutes(10);
System.out.println(update5); // 2021-05-01T18:20:45

final LocalDateTime update6 = dateTime.plusSeconds(100);
System.out.println(update6); // 2021-05-01T18:32:25

ZonedDateTime

ISO-8601の暦体系によるタイムゾーン付きの日付/時間です(2007-12-03T10:15:30+01:00 Europe/Parisなど)。
ZonedDateTimeはタイムゾーン付き日付/時間の不変表現です。 このクラスは、すべての日付および時間フィールド (ナノ秒精度) とタイムゾーン (あいまいなローカル日付/時間を処理するために使用するゾーン・オフセット付き) を格納します。 たとえば、値2nd October 2007 at 13:45.30.123456789 +02:00 in the Europe/Paris time-zoneをZonedDateTimeに格納できます。

クラス構成

ZonedDateTime は、タイムゾーン付きの日時を表します。

例えば、

  • 2021-05-01T18:30:45+09:00 Asia/Tokyo
  • 2000-01-01T01:02:03-06:00 America/Chicago
  • 2021-04-15T00:00Z

などです。

ZonedDateTime の作成には of メソッドを使います。

final ZoneId zoneId = ZoneId.systemDefault();
System.out.println(zoneId); // Asia/Tokyo

// 作成
final ZonedDateTime dateTime1 = ZonedDateTime.of(2021, 5, 1, 18, 30, 45, 0, zoneId);
System.out.println(dateTime1); // 2021-05-01T18:30:45+09:00[Asia/Tokyo]

// LocalDate, LocalTimeから作成
final LocalDate date = LocalDate.of(2021, 5, 1);
final LocalTime time = LocalTime.of(18, 30, 45);

final ZonedDateTime dateTime2 = ZonedDateTime.of(date, time, zoneId);
System.out.println(dateTime2); // 2021-05-01T18:30:45+09:00[Asia/Tokyo]
// 現在日時を取得
final ZonedDateTime now = ZonedDateTime.now();
System.out.println(now); // 2021-05-17T17:00:36.412974+09:00[Asia/Tokyo]
final ZoneId zoneId = ZoneId.systemDefault();
System.out.println(zoneId); // Asia/Tokyo

final ZonedDateTime dateTime = ZonedDateTime.of(2021, 5, 1, 18, 30, 45, 0, zoneId);
System.out.println(dateTime); // 2021-05-01T18:30:45+09:00[Asia/Tokyo]

// 年月日の取得
System.out.println(dateTime.getYear()); // 2021
System.out.println(dateTime.getMonthValue()); // 5
System.out.println(dateTime.getDayOfMonth()); // 1

// 時分秒の取得
System.out.println(dateTime.getHour()); // 18
System.out.println(dateTime.getMinute()); // 30
System.out.println(dateTime.getSecond()); // 45

// タイムゾーンの取得
System.out.println(dateTime.getZone()); // Asia/Tokyo

文字列へ変換するには、format メソッドと DateTimeFormatter を使います。

// 作成
final ZonedDateTime dateTime = ZonedDateTime.of(2021, 5, 1, 18, 30, 45, 0, ZoneId.systemDefault());

final var str1 = dateTime.format(DateTimeFormatter.ISO_ZONED_DATE_TIME);
System.out.println(str1); // 2021-05-01T18:30:45+09:00[Asia/Tokyo]

final var str2 = dateTime.format(DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss VV"));
System.out.println(str2); // 2021/05/01 18:30:45 Asia/Tokyo

final var str3 = dateTime.format(DateTimeFormatter.ofPattern("yyyy年MM月dd日(E) a hh時mm分ss秒 z"));
System.out.println(str3); // 2021年05月01日(土) 午後 06時30分45秒 JST

with~メソッドを使うことで、with~で指定した要素と、それ以外は元のオブジェクトの値を引き継いだ新しい ZonedDateTime を作成できます。
setterの代わりとして使えます。

final ZoneId zoneId = ZoneId.systemDefault();
System.out.println(zoneId); // Asia/Tokyo

final ZonedDateTime dateTime = ZonedDateTime.of(2021, 5, 1, 18, 30, 45, 0, zoneId);
System.out.println(dateTime); // 2021-05-01T18:30:45+09:00[Asia/Tokyo]

// 年が変更されたコピーを返します。
final ZonedDateTime update1 = dateTime.withYear(1999);
System.out.println(update1); // 1999-05-01T18:30:45+09:00[Asia/Tokyo]

// 月が変更されたコピーを返します。
final ZonedDateTime update2 = dateTime.withMonth(12);
System.out.println(update2); // 2021-12-01T18:30:45+09:00[Asia/Tokyo]

// 日が変更されたコピーを返します。
final ZonedDateTime update3 = dateTime.withDayOfMonth(31);
System.out.println(update3); // 2021-05-31T18:30:45+09:00[Asia/Tokyo]

// 時が変更されたコピーを返します。
final ZonedDateTime update4 = dateTime.withHour(9);
System.out.println(update4); // 2021-05-01T09:30:45+09:00[Asia/Tokyo]

// 分が変更されたコピーを返します。
final ZonedDateTime update5 = dateTime.withMinute(15);
System.out.println(update5); //2021-05-01T18:15:45+09:00[Asia/Tokyo]

// 秒が変更されたコピーを返します。
final ZonedDateTime update6 = dateTime.withSecond(0);
System.out.println(update6); // 2021-05-01T18:30+09:00[Asia/Tokyo]

日時の演算には、plus~メソッド、minus~メソッドを使います。

final ZoneId zoneId = ZoneId.systemDefault();
System.out.println(zoneId); // Asia/Tokyo

final ZonedDateTime dateTime = ZonedDateTime.of(2021, 5, 1, 18, 30, 45, 0, zoneId);
System.out.println(dateTime); // 2021-05-01T18:30:45+09:00[Asia/Tokyo]

final ZonedDateTime update1 = dateTime.plusYears(5);
System.out.println(update1); // 2026-05-01T18:30:45+09:00[Asia/Tokyo]

final ZonedDateTime update2 = dateTime.minusMonths(3);
System.out.println(update2); // 2021-02-01T18:30:45+09:00[Asia/Tokyo]

final ZonedDateTime update3 = dateTime.plusDays(50);
System.out.println(update3); // 2021-06-20T18:30:45+09:00[Asia/Tokyo]

final ZonedDateTime update4 = dateTime.plusHours(2);
System.out.println(update4); // 2021-05-01T20:30:45+09:00[Asia/Tokyo]

final ZonedDateTime update5 = dateTime.minusMinutes(10);
System.out.println(update5); // 2021-05-01T18:20:45+09:00[Asia/Tokyo]

final ZonedDateTime update6 = dateTime.plusSeconds(100);
System.out.println(update6); // 2021-05-01T18:32:25+09:00[Asia/Tokyo]

ZoneId

タイムゾーンID(ヨーロッパ/パリなど)。
ZoneIdは、InstantおよびLocalDateTimeの間の変換に使用するルールを識別するために使用されます。

クラス構成

ZoneId はタイムゾーンを表します。
日本の一般的な環境では、デフォルトで "Asia/Tokyo" となります。

// Windows 10の日本語環境で実行しています。
final var zoneId = ZoneId.systemDefault();
System.out.println(zoneId); // Asia/Tokyo

もし、"Asia/Tokyo" を明示したい場合は次のようにします。

final var zoneId1 = ZoneId.of("Asia/Tokyo");
System.out.println(zoneId1); // Asia/Tokyo

// もしくはショート名(JST)を使います。
final var zoneId2 = ZoneId.of("JST", ZoneId.SHORT_IDS);
System.out.println(zoneId2); // Asia/Tokyo

特殊なタイムゾーン(正確にはZoneOffset)として UTC(協定世界時) があります。

final ZoneId utc = ZoneOffset.UTC;
System.out.println(utc); // Z

関連記事:ZoneIdとZoneOffsetの違い

Instant

時系列の時点。
...
これを実現するために、このクラスはエポック秒を表すlongと、「1秒のうちのナノ秒」を表すint(常に0と999,999,999の間になる)を保存します。 エポック秒は、標準Javaエポック (1970-01-01T00:00:00Z) から測定されます。

クラス構成

Instant は、世界のどこででも同じ基準となる絶対的な時点を表します。
厳密にはうるう秒とかややこしいですが、簡単にいうと 1970-01-01T00:00:00Z から経過した秒数です。

基本にしては少し難しいクラスですが、大事なクラスなのでコード例を載せておきます。

final Instant instant = Instant.ofEpochSecond(1609849845L, 123000000L);
System.out.println(instant); // 2021-01-05T12:30:45.123Z

// エポック秒の取得
System.out.println(instant.getEpochSecond()); // 1609849845

// ナノ秒部分の取得
System.out.println(instant.getNano()); // 123000000
// 現在時刻の取得
final Instant now = Instant.now();
System.out.println(now); // 2021-05-17T07:14:33.388491500Z

時点の演算には、plus~メソッド、minus~メソッドを使います。

final Instant instant = Instant.ofEpochSecond(1000000000L, 123000000L);
System.out.println(instant); // 2001-09-09T01:46:40.123Z

final Instant update1 = instant.plusSeconds(999);
System.out.println(update1); // 2001-09-09T02:03:19.123Z
System.out.println(update1.getEpochSecond()); // 1000000999
System.out.println(update1.getNano()); // 123000000

final Instant update2 = instant.minusMillis(100);
System.out.println(update2); // 2001-09-09T01:46:40.023Z
System.out.println(update2.getEpochSecond()); // 1000000000
System.out.println(update2.getNano()); // 23000000

final Instant update3 = instant.plusNanos(300);
System.out.println(update3); // 2001-09-09T01:46:40.123000300Z
System.out.println(update3.getEpochSecond()); // 1000000000
System.out.println(update3.getNano()); // 123000300

補足

文字列との相互変換

詳細は別記事にまとめています。そちらをご参照ください。

現在時刻(日時)の取得

詳細は別記事にまとめています。そちらをご参照ください。

古いAPI(Date, Calendar)は使わないようにしよう

古いAPIとして、Date と Calendar があります。
これらのAPIは使わない方がよいでしょう。

以下の記事にもまとめていますので、参考にしていただけたら幸いです。


関連記事

ページの先頭へ