広告

Java : 日付・時刻の基本

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


用語の定義

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

用語 定義
日付 年と月と日 2100/5/4
1999年12月31日
時刻 時と分と秒 12:30:59
7時30分45秒
日時 日付と時刻 2100/5/4 12:30:59
1999年12月31日 7時30分45秒
時点 世界のどこででも同じ基準となる時間軸上の一点。
(具体的にはエポック秒とナノ秒で表します)
4102444800.123 (2100-01-01T00:00:00.123Z)

日付・時刻のAPI

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

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

クラス 説明 使用例
LocalDate 日付(タイムゾーンなし)
final var date = LocalDate.of(2100, 5, 1);
System.out.println(date); // 2100-05-01

System.out.println(date.getYear()); // 2100
System.out.println(date.getMonth()); // MAY
System.out.println(date.getDayOfMonth()); // 1
LocalTime 時刻(タイムゾーンなし)
final var time = LocalTime.of(12, 30, 45);
System.out.println(time); // 12:30:45

System.out.println(time.getHour()); // 12
System.out.println(time.getMinute()); // 30
System.out.println(time.getSecond()); // 45
LocalDateTime 日時(タイムゾーンなし)
final var dateTime = LocalDateTime.of(2100, 5, 1, 12, 30, 45);
System.out.println(dateTime); // 2100-05-01T12:30:45

System.out.println(dateTime.getYear()); // 2100
System.out.println(dateTime.getMonth()); // MAY
System.out.println(dateTime.getDayOfMonth()); // 1

System.out.println(dateTime.getHour()); // 12
System.out.println(dateTime.getMinute()); // 30
System.out.println(dateTime.getSecond()); // 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 dateTime = ZonedDateTime.of(2100, 5, 1, 12, 30, 45, 0, zoneId);
System.out.println(dateTime); // 2100-05-01T12:30:45+09:00[Asia/Tokyo]

System.out.println(dateTime.getYear()); // 2100
System.out.println(dateTime.getMonth()); // MAY
System.out.println(dateTime.getDayOfMonth()); // 1

System.out.println(dateTime.getHour()); // 12
System.out.println(dateTime.getMinute()); // 30
System.out.println(dateTime.getSecond()); // 45

System.out.println(dateTime.getZone()); // Asia/Tokyo
Instant 時点
final var instant = Instant.ofEpochSecond(4102444800L);
System.out.println(instant); // 2100-01-01T00:00:00Z

System.out.println(instant.getEpochSecond()); // 4102444800
System.out.println(instant.getNano()); // 0

共通の特徴

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

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

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

final var date = LocalDate.of(2100, 1, 1);
System.out.println(date); // 2100-01-01

final var ret1 = date.withYear(2999);
System.out.println(ret1); // 2999-01-01

final var ret2 = date.withMonth(8);
System.out.println(ret2); // 2100-08-01

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

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

文字列表記(ISO 8601)

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

日付と時刻の文字列表記は、ISO 8601 の拡張形式が基本となります。
例えば toString メソッドで取得できる文字列は ISO 8601 です。

final var dateTime = LocalDateTime.of(2100, 12, 30, 16, 47, 23);
final var str = dateTime.toString();
System.out.println(str); // 2100-12-30T16:47:23

ISO 8601 は Java に限らずいろいろなプログラミング言語でお目にかかるので、理解しておいて損はないでしょう。

形式 表記例
拡張形式 2100-12-30T16:47:23
基本形式 21001230T164723

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

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

LocalDate

ISO-8601暦体系のタイムゾーンのない日付、2007-12-03など。
LocalDateは、日付(年-月-日として表示されることが多い)を表す不変の日付/時間オブジェクトです。

クラス構成

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

例えば、2100-12-03 や 1999-05-01 などです。
また、曜日の情報も取得できます。(2100年5月3日月曜日など)

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

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

// 年月日の取得
System.out.println(date.getYear()); // 2100
System.out.println(date.getMonth()); // MAY
System.out.println(date.getDayOfMonth()); // 1
// 曜日の取得
final var date1 = LocalDate.of(2100, 5, 2);
System.out.println(date1); // 2100-05-02
System.out.println(date1.getDayOfWeek()); // SUNDAY

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

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

現在の日付を取得するには now メソッドを使います。

// 現在の日付を取得
final var now = LocalDate.now();
System.out.println(now); // 2023-01-14

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

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

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

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

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

final var str4 = date.format(DateTimeFormatter.ofLocalizedDate(FormatStyle.FULL));
System.out.println(str4); // 2100年5月1日土曜日

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

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

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

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

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

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

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

final var ret1 = date.plusYears(6);
System.out.println(ret1); // 2106-05-01

final var ret2 = date.minusMonths(3);
System.out.println(ret2); // 2100-02-01

final var ret3 = date.plusDays(50);
System.out.println(ret3); // 2100-06-20

LocalTime

ISO-8601暦体系における、タイムゾーンのない時間(10:15:30など)。
LocalTimeは、時間(時-分-秒として表示されることが多い)を表す不変の日付/時間オブジェクトです。

クラス構成

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

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

// 作成
final var 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

現在の時刻を取得するには now メソッドを使います。

// 現在時刻を取得
final var now = LocalTime.now();
System.out.println(now); // 16:54:02.676090600

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

final var 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

final var str4 = time.format(DateTimeFormatter.ofLocalizedTime(FormatStyle.MEDIUM));
System.out.println(str4); // 18:30:45

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

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

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

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

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

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

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

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

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

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

LocalDateTime

ISO-8601暦体系のタイムゾーンのない日付/時間、2007-12-03T10:15:30など。
LocalDateTimeは、日付/時間(年-月-日-時-分-秒として表示されることが多い)を表す不変の日付/時間オブジェクトです。

クラス構成

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

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

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

// 年月日の取得
System.out.println(dateTime.getYear()); // 2100
System.out.println(dateTime.getMonth()); // MAY
System.out.println(dateTime.getDayOfMonth()); // 1

// 時分秒の取得
System.out.println(dateTime.getHour()); // 18
System.out.println(dateTime.getMinute()); // 30
System.out.println(dateTime.getSecond()); // 45
// LocalDate, LocalTimeから作成
final var date = LocalDate.of(2100, 5, 1);
final var time = LocalTime.of(18, 30, 45);

final var dateTime = LocalDateTime.of(date, time);
System.out.println(dateTime); // 2100-05-01T18:30:45

現在の日時を取得するには now メソッドを使います。

// 現在日時を取得
final var now = LocalDateTime.now();
System.out.println(now); // 2023-01-15T15:06:55.081933400

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

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

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

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

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

final var str4 = dateTime.format(DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM));
System.out.println(str4); // 2100/05/01 18:30:45

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

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

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

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

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

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

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

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

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

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

final var ret1 = dateTime.plusYears(5);
System.out.println(ret1); // 2105-05-01T18:30:45

final var ret2 = dateTime.minusMonths(3);
System.out.println(ret2); // 2100-02-01T18:30:45

final var ret3 = dateTime.plusDays(50);
System.out.println(ret3); // 2100-06-20T18:30:45

final var ret4 = dateTime.plusHours(2);
System.out.println(ret4); // 2100-05-01T20:30:45

final var ret5 = dateTime.minusMinutes(10);
System.out.println(ret5); // 2100-05-01T18:20:45

final var ret6 = dateTime.plusSeconds(100);
System.out.println(ret6); // 2100-05-01T18:32:25

ZoneId

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

クラス構成

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

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

"Asia/Tokyo" を明示して ZoneId を作成したい場合は、of メソッドを使います。

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

"Asia/Tokyo" ではいつでも時差 +09:00 となります。
(サマータイムのある地域では、日付によって時差が変わることがあります)

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

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

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

関連記事:ZoneIdとZoneOffsetの違い


ZonedDateTime

ISO-8601の暦体系によるタイムゾーン付きの日付/時間です(2007-12-03T10:15:30+01:00 Europe/Parisなど)。
ZonedDateTimeはタイムゾーン付き日付/時間の不変表現です。

クラス構成

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

例えば、

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

などです。

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

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

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

// 年月日の取得
System.out.println(dateTime.getYear()); // 2100
System.out.println(dateTime.getMonth()); // MAY
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.getNano()); // 0

// タイムゾーンの取得
System.out.println(dateTime.getZone()); // Asia/Tokyo
final var utc = ZoneOffset.UTC;
System.out.println(utc); // Z

final var date = LocalDate.of(2100, 5, 1);
final var time = LocalTime.of(18, 30, 45);

final var dateTime = ZonedDateTime.of(date, time, utc);
System.out.println(dateTime); // 2100-05-01T18:30:45Z

現在の日時を取得するには now メソッドを使います。

// 現在日時を取得
final var now = ZonedDateTime.now();
System.out.println(now); // 2023-01-15T16:05:52.630309300+09:00[Asia/Tokyo]

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

final var dateTime = ZonedDateTime.of(2100, 5, 1, 18, 30, 45, 0, ZoneId.systemDefault());

final var str1 = dateTime.format(DateTimeFormatter.ISO_ZONED_DATE_TIME);
System.out.println(str1); // 2100-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); // 2100/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); // 2100年05月01日(土) 午後 06時30分45秒 JST

final var str4 = dateTime.format(DateTimeFormatter.ofLocalizedDateTime(FormatStyle.FULL));
System.out.println(str4); // 2100年5月1日土曜日 18時30分45秒 日本標準時

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Instant

時系列の時点。
このクラスは時系列上の単一時点をモデル化します。

クラス構成

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

少し難しいクラスですが、Java の日付・時刻 API の中心となるとても大事なクラスです。

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

final var instant = Instant.ofEpochSecond(0);
System.out.println(instant); // 1970-01-01T00:00:00Z
final var instant = Instant.ofEpochSecond(4102444800L, 123000000L);
System.out.println(instant); // 2100-01-01T00:00:00.123Z

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

// ナノ秒部分の取得
System.out.println(instant.getNano()); // 123000000

現在時刻を取得するには now メソッドを使います。

// 現在時刻の取得
final var now = Instant.now();
System.out.println(now); // 2023-01-15T08:20:27.081219300Z

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

final var instant = Instant.ofEpochSecond(3000000000L, 123000000L);
System.out.println(instant); // 2065-01-24T05:20:00.123Z

final var ret1 = instant.plusSeconds(999);
System.out.println(ret1.getEpochSecond()); // 3000000999
System.out.println(ret1.getNano()); // 123000000

final var ret2 = instant.minusMillis(100);
System.out.println(ret2.getEpochSecond()); // 3000000000
System.out.println(ret2.getNano()); // 23000000

final var ret3 = instant.plusNanos(500);
System.out.println(ret3.getEpochSecond()); // 1000000000
System.out.println(ret3.getNano()); // 123000500

補足

文字列との相互変換

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

現在時刻(日時)の取得

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

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

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

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


関連記事

ページの先頭へ