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 は java.time パッケージにあります。
主に使う API を簡単にまとめます。
クラス | 説明 | 使用例 |
---|---|---|
LocalDate | 日付(タイムゾーンなし) |
|
LocalTime | 時刻(タイムゾーンなし) |
|
LocalDateTime | 日時(タイムゾーンなし) |
|
ZoneId | タイムゾーンID。 日本だと"Asia/Tokyo"となり時差は"+09:00"です。 |
|
ZonedDateTime | 日時(タイムゾーンあり) |
|
Instant | 時点 |
|
共通の特徴
不変(イミュータブル)なオブジェクト
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 の拡張形式が基本となります。
例えば 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
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
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
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
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
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は使わない方がよいでしょう。
以下の記事にもまとめていますので、参考にしていただけたら幸いです。
関連記事
- 不変オブジェクト(イミュータブル) とは
- Date, CalendarではなくLocalDateTime, ZonedDateTimeを使おう
- 文字列と日付・時刻の変換
- 日付と時刻、曜日の計算
- 現在時刻(日時)の取得いろいろ
- 現在の曜日(DayOfWeek)を取得
- ZoneIdとZoneOffsetの違い
- API 使用例
- Calendar (カレンダー)
- ChronoLocalDate
- ChronoLocalDateTime
- ChronoZonedDateTime
- Clock (時計)
- Date (日付・時刻)
- DateTimeException (日付・時刻の例外)
- DateTimeParseException (日付・時刻の解析例外)
- DayOfWeek (曜日)
- Duration (時間の量)
- Era (紀元)
- Instant (時点)
- InstantSource
- JapaneseDate (和暦を使った日付)
- LocalDate (日付・タイムゾーンなし)
- LocalDateTime (日時・タイムゾーンなし)
- LocalTime (時刻・タイムゾーンなし)
- Month (月)
- MonthDay (月・日)
- OffsetDateTime (日時・オフセットあり)
- OffsetTime (時刻・オフセットあり)
- Period (日付の量)
- Temporal
- TemporalAccessor
- TemporalAdjuster (日付・時刻の調整)
- TemporalAdjusters (日付・時刻の調整ユーティリティ)
- TimeZone (タイムゾーン)
- Year (年)
- YearMonth (年・月)
- ZonedDateTime (日時・タイムゾーンあり)
- ZoneId (タイムゾーンID)
- ZoneOffset (タイムゾーン・オフセット)