Java日付 - Date-Time API
概要
Java SE 8から、日付/時刻を扱う新しいAPIとしてDate and Time APIが導入されました。Date-Time APIはjava.timeパッケージに含まれています。
java.timeパッケージで提供される主なクラスは次のとおりです。
LocalDateTime/LocalDate/LocalTime: 時差情報のないローカル日時OffsetDateTime/OffsetTime: 時差情報を持つ日付と時刻ZonedDateTime: タイムゾーンと地域に基づく情報(サマータイムなど)を持つ日付と時刻
一般的には、時差情報を必要としない場合はLocalクラスを使用し、そうでない場合はZonedクラスを使用する形で区別されます。Offset~クラスを利用する場面はあまり多くないと思われます。
LocalDateTimeのnow/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へ変換する方法
Stringをjava.time.LocalDateへ変換する場合は、LocalDate.parseとDateTimeFormatterを利用して日付文字列を変換します。
Stringをjava.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_DATEはyyyy-MM-ddを定数として宣言します。