Java : 日付と時刻、曜日の計算
日付と時刻、曜日の計算 … 例えば
- 12:00 に 100分 を足したら何時になる?
- 2022年7月の第2月曜日は何日?
などなど。
本記事では、Java標準 API を使った日時と曜日の計算についてご紹介します。
はじめに
日時や曜日を扱うために、以下の Java API を主に使います。
- 時刻:LocalTime
- 日付:LocalDate
- 日時:LocalDateTime
もしそのあたりに不安のあるかたは、下記の記事も合わせてご確認いただけたら幸いです。
関連記事:日付・時刻の基本
用語の定義
本記事では、時間に関する用語を以下のように定義します。
用語 | 定義 | 例 |
---|---|---|
日付 | 年と月と日 | 2021/5/4 2000年12月31日 |
時刻 | 時と分と秒 | 12:30:59 7時30分45秒 |
日時 | 日付と時刻 | 2021/5/4 12:30:59 2000年12月31日 7時30分45秒 |
簡単なまとめ
日時の計算に関する Java API は、大きく3つに分けられます。
- 足し算:plus~ メソッド
- 引き算:minus~ メソッド
- 月の最終日や、曜日の計算など:with メソッド + TemporalAdjusters
足し算
計算 | API | コード例 |
---|---|---|
時 | LocalTimeクラス LocalTime plusHours (long hoursToAdd) |
|
分 | LocalTimeクラス LocalTime plusMinutes (long minutesToAdd) |
|
秒 | LocalTimeクラス LocalTime plusSeconds (long secondstoAdd) |
|
時分秒の長さ | LocalTimeクラス LocalTime plus (TemporalAmount amountToAdd) + Duration |
|
年 | LocalDateクラス LocalDate plusYears (long yearsToAdd) |
|
月 | LocalDateクラス LocalDate plusMonths (long monthsToAdd) |
|
日 | LocalDateクラス LocalDate plusDays (long daysToAdd) |
|
年月日の長さ | LocalDateクラス LocalDate plus (TemporalAmount amountToAdd) + Period |
|
引き算
計算 | API | コード例 |
---|---|---|
時 | LocalTimeクラス LocalTime minusHours (long hoursToSubtract) |
|
分 | LocalTimeクラス LocalTime minusMinutes (long minutesToSubtract) |
|
秒 | LocalTimeクラス LocalTime minusSeconds (long secondsToSubtract) |
|
時分秒の長さ | LocalTimeクラス LocalTime minus (TemporalAmount amountToSubtract) + Duration |
|
年 | LocalDateクラス LocalDate minusYears (long yearsToSubtract) |
|
月 | LocalDateクラス LocalDate minusMonths (long monthsToSubtract) |
|
日 | LocalDateクラス LocalDate minusDays (long daysToSubtract) |
|
年月日の長さ | LocalDateクラス LocalDate minus (TemporalAmount amountToSubtract) + Period |
|
月の最終日や、曜日の計算
※コード例を確認しやすくするためのカレンダーです。
計算 | API | コード例 |
---|---|---|
月の最終日 | LocalDateクラス LocalDate with (TemporalAdjuster adjuster) + TemporalAdjusters.lastDayOfMonth () |
|
次のx曜日 | LocalDateクラス LocalDate with (TemporalAdjuster adjuster) + TemporalAdjusters.next (DayOfWeek dayOfWeek) |
|
前のx曜日 | LocalDateクラス LocalDate with (TemporalAdjuster adjuster) + TemporalAdjusters.previous (DayOfWeek dayOfWeek) |
|
月の最初のx曜日 | LocalDateクラス LocalDate with (TemporalAdjuster adjuster) + TemporalAdjusters.firstInMonth (DayOfWeek dayOfWeek) |
|
月の最後のx曜日 | LocalDateクラス LocalDate with (TemporalAdjuster adjuster) + TemporalAdjusters.lastInMonth (DayOfWeek dayOfWeek) |
|
月の第x何曜日 | LocalDateクラス LocalDate with (TemporalAdjuster adjuster) + TemporalAdjusters.dayOfWeekInMonth (int ordinal, DayOfWeek dayOfWeek) |
|
補足
簡単なまとめとしては、時刻 (LocalTime) と日付 (LocalDate) の計算をご紹介しました。
日時 (LocalDateTime) については省略していますが、時刻と日付で使った計算用メソッドがそのまま使えます。
詳細
時刻
時刻の計算には LocalTime クラスを使います。
似た API に OffsetTime がありますが、そちらも同じように計算できます。
足し算
足し算には LocalTime.plus~ メソッドを使います。
例
- plusHours : (時間を足します)
- plusMinutes : (分を足します)
- plusSeconds : (秒を足します)
- plus : (時分秒の長さを足します)
// 10時30分15秒
final var time = LocalTime.of(10, 30, 15);
System.out.println(time); // 10:30:15
// +5時間
final var ret1 = time.plusHours(5);
System.out.println(ret1); // 15:30:15
// +10分
final var ret2 = time.plusMinutes(10);
System.out.println(ret2); // 10:40:15
// +30秒
final var ret3 = time.plusSeconds(30);
System.out.println(ret3); // 10:30:45
計算の結果が 23:59:59 より大きくなると 00:00:00 に戻ります。
(正確にはナノ秒も含めると 23:59:59.999999999 です)
// 23時59分59秒
final var time = LocalTime.of(23, 59, 59);
System.out.println(time); // 23:59:59
// +1時間
final var ret1 = time.plusHours(1);
System.out.println(ret1); // 00:59:59
// +2分
final var ret2 = time.plusMinutes(2);
System.out.println(ret2); // 00:01:59
// +3秒
final var ret3 = time.plusSeconds(3);
System.out.println(ret3); // 00:00:02
時分秒をまとめて足したいときは、Duration クラスを使います。
Duration は時分秒を合計した長さ…つまり時間の長さを表します。
例えば、4時間と20分と30秒 を足したい場合は次のようにします。
final var time = LocalTime.of(10, 30, 15);
System.out.println(time); // 10:30:15
// 4時間と20分と30秒
final var duration = Duration.ofHours(4).plusMinutes(20).plusSeconds(30);
System.out.println(duration); // PT4H20M30S
// 時間の長さを足します。
final var ret = time.plus(duration);
System.out.println(ret); // 14:50:45
引き算
引き算には LocalTime.minus~ メソッドを使います。
例
- minusHours : (時間を引きます)
- minusMinutes : (分を引きます)
- minusSeconds : (秒を引きます)
- minus : (時分秒の長さを引きます)
// 10時30分15秒
final var time = LocalTime.of(10, 30, 15);
System.out.println(time); // 10:30:15
// -5時間
final var ret1 = time.minusHours(5);
System.out.println(ret1); // 05:30:15
// -10分
final var ret2 = time.minusMinutes(10);
System.out.println(ret2); // 10:20:15
// -30秒
final var ret3 = time.minusSeconds(30);
System.out.println(ret3); // 10:29:45
もしくは、plus~ メソッドに負数を指定しても問題ありません。
足し算のところの例も合わせてご確認ください。
日付
日付の計算には LocalDate クラスを使います。
足し算
足し算には LocalDate.plus~ メソッドを使います。
例
- plusYears : (年を足します)
- plusMonths : (月を足します)
- plusDays : (日を足します)
- plus : (年月日の長さを足します)
// 1999年1月1日
final var date = LocalDate.of(1999, 1, 1);
System.out.println(date); // 1999-01-01
// +1年
final var ret1 = date.plusYears(1);
System.out.println(ret1); // 2000-01-01
// +2か月
final var ret2 = date.plusMonths(2);
System.out.println(ret2); // 1999-03-01
// +3日
final var ret3 = date.plusDays(3);
System.out.println(ret3); // 1999-01-04
月が12月を超えると、年が +1 されます。
また、日にちが月の最終日を超えると、月が +1 されます。
// 1999年12月31日
final var date = LocalDate.of(1999, 12, 31);
System.out.println(date); // 1999-12-31
// +3か月
final var ret1 = date.plusMonths(3);
System.out.println(ret1); // 2000-03-31
// +1日
final var ret2 = date.plusDays(1);
System.out.println(ret2); // 2000-01-01
計算の結果、月の日にちがカレンダーに存在しない日(例えば 2月31日 など)になってしまう場合は、月の最終日に補正されます。
// 2022年1月31日
final var date = LocalDate.of(2022, 1, 31);
System.out.println(date); // 2022-01-31
// +1か月 (日にちは 31日ではなく 28日になります)
final var ret1 = date.plusMonths(1);
System.out.println(ret1); // 2022-02-28
年月日をまとめて足したいときは、Period クラスを使います。
Period は年と月と日を合計した長さ…つまり日付の長さを表します。
例えば、10年と2か月と5日 を足したい場合は次のようにします。
final var date = LocalDate.of(1999, 2, 1);
System.out.println(date); // 1999-02-01
// 10年と2か月と5日
final var period = Period.of(10, 2, 5);
System.out.println(period); // P10Y2M5D
// 日付の長さを足します。
final var ret = date.plus(period);
System.out.println(ret); // 2009-04-06
引き算
引き算には LocalDate.minus~ メソッドを使います。
例
- minusYears : (年を引きます)
- minusMonths : (月を引きます)
- minusDays : (日を引きます)
- minus : (年月日の長さを引きます)
// 2000年10月15日
final var date = LocalDate.of(2000, 10, 15);
System.out.println(date); // 2000-10-15
// -1年
final var ret1 = date.minusYears(1);
System.out.println(ret1); // 1999-10-15
// -2か月
final var ret2 = date.minusMonths(2);
System.out.println(ret2); // 2000-08-15
// -3日
final var ret3 = date.minusDays(3);
System.out.println(ret3); // 2000-10-12
もしくは、LocalDate.plus~ メソッドに負数を指定しても問題ありません。
足し算のところの例も合わせてご確認ください。
月の最終日
月の最終日を取得するには、LocalDate.with メソッドを使います。
パラメータには TemporalAdjusters の lastDayOfMonth メソッドで取得したアジャスタを指定します。
アジャスタとは、簡単にいうと
- 月の最終日を計算
- 次のx曜日を計算
- 月の最後のx曜日を計算
といった異なる計算を、TemporalAdjuster という統一したインタフェースで計算する仕組みです。
API仕様には、デザインパターンの Strategy パターンを使っている、とありますね。
標準API の TemporalAdjusters クラスには、いろいろと便利なアジャスタが用意されています。
それでは、アジャスタを使って月の最終日を取得する例を見てみましょう。
final var adjuster = TemporalAdjusters.lastDayOfMonth();
// 2022年1月の最終日
final var ret1 = LocalDate.of(2022, 1, 1).with(adjuster);
System.out.println(ret1); // 2022-01-31
// 2022年2月の最終日
final var ret2 = LocalDate.of(2022, 2, 1).with(adjuster);
System.out.println(ret2); // 2022-02-28
// 2022年3月の最終日
final var ret3 = LocalDate.of(2022, 3, 1).with(adjuster);
System.out.println(ret3); // 2022-03-31
// 2022年4月の最終日
final var ret4 = LocalDate.of(2022, 4, 1).with(adjuster);
System.out.println(ret4); // 2022-04-30
うるう年も考慮されます。
// 2000年2月1日
final var date = LocalDate.of(2000, 2, 1);
System.out.println(date); // 2000-02-01
// 2000年は、うるう年です。
System.out.println(date.isLeapYear()); // true
// 2000年2月の最終日を取得します。
final var ret = date.with(TemporalAdjusters.lastDayOfMonth());
System.out.println(ret); // 2000-02-29
次のx曜日
次のx曜日を取得するには LocalDate.with メソッドを使います。
パラメータに指定するのは TemporalAdjusters の next で取得したアジャスタです。
final var formatter = DateTimeFormatter.ofPattern("yyyy年MM月dd日(E)");
final var date = LocalDate.of(2022, 7, 1);
System.out.println(date.format(formatter)); // 2022年07月01日(金)
// 7月1日(金) の1つ次の土曜日
final var ret1 = date.with(TemporalAdjusters.next(DayOfWeek.SATURDAY));
System.out.println(ret1.format(formatter)); // 2022年07月02日(土)
// 7月1日(金) の1つ次の日曜日
final var ret2 = date.with(TemporalAdjusters.next(DayOfWeek.SUNDAY));
System.out.println(ret2.format(formatter)); // 2022年07月03日(日)
// 7月1日(金) の1つ次の金曜日
final var ret3 = date.with(TemporalAdjusters.next(DayOfWeek.FRIDAY));
System.out.println(ret3.format(formatter)); // 2022年07月08日(金)
前のx曜日
前のx曜日を取得するには LocalDate.with メソッドを使います。
パラメータに指定するのは TemporalAdjusters の previous で取得したアジャスタです。
final var formatter = DateTimeFormatter.ofPattern("yyyy年MM月dd日(E)");
final var date = LocalDate.of(2022, 7, 30);
System.out.println(date.format(formatter)); // 2022年07月30日(土)
// 7月30日(土) の1つ前の金曜日
final var ret1 = date.with(TemporalAdjusters.previous(DayOfWeek.FRIDAY));
System.out.println(ret1.format(formatter)); // 2022年07月29日(金)
// 7月30日(土) の1つ前の木曜日
final var ret2 = date.with(TemporalAdjusters.previous(DayOfWeek.THURSDAY));
System.out.println(ret2.format(formatter)); // 2022年07月28日(木)
// 7月30日(土) の1つ前の土曜日
final var ret3 = date.with(TemporalAdjusters.previous(DayOfWeek.SATURDAY));
System.out.println(ret3.format(formatter)); // 2022年07月23日(土)
月の最初のx曜日
月の最初のx曜日を取得するには LocalDate.with メソッドを使います。
パラメータに指定するのは TemporalAdjusters の firstInMonth で取得したアジャスタです。
final var formatter = DateTimeFormatter.ofPattern("yyyy年MM月dd日(E)");
final var date = LocalDate.of(2022, 7, 1);
System.out.println(date.format(formatter)); // 2022年07月01日(金)
// 月の最初の月曜日
final var ret1 = date.with(TemporalAdjusters.firstInMonth(DayOfWeek.MONDAY));
System.out.println(ret1.format(formatter)); // 2022年07月04日(月)
// 月の最初の火曜日
final var ret2 = date.with(TemporalAdjusters.firstInMonth(DayOfWeek.TUESDAY));
System.out.println(ret2.format(formatter)); // 2022年07月05日(火)
// 月の最初の金曜日
final var ret3 = date.with(TemporalAdjusters.firstInMonth(DayOfWeek.FRIDAY));
System.out.println(ret3.format(formatter)); // 2022年07月01日(金)
月の最後のx曜日
月の最後のx曜日を取得するには LocalDate.with メソッドを使います。
パラメータに指定するのは TemporalAdjusters の lastInMonth で取得したアジャスタです。
final var formatter = DateTimeFormatter.ofPattern("yyyy年MM月dd日(E)");
final var date = LocalDate.of(2022, 7, 1);
System.out.println(date.format(formatter)); // 2022年07月01日(金)
// 月の最後の月曜日
final var ret1 = date.with(TemporalAdjusters.lastInMonth(DayOfWeek.MONDAY));
System.out.println(ret1.format(formatter)); // 2022年07月25日(月)
// 月の最後の火曜日
final var ret2 = date.with(TemporalAdjusters.lastInMonth(DayOfWeek.TUESDAY));
System.out.println(ret2.format(formatter)); // 2022年07月26日(火)
// 月の最後の金曜日
final var ret3 = date.with(TemporalAdjusters.lastInMonth(DayOfWeek.FRIDAY));
System.out.println(ret3.format(formatter)); // 2022年07月29日(金)
月の第x何曜日
月の第x何曜日を取得するには LocalDate.with メソッドを使います。
例えば、2022年7月の第2月曜日は 7月11日 といった感じです。
パラメータに指定するのは TemporalAdjusters の dayOfWeekInMonth で取得したアジャスタです。
final var formatter = DateTimeFormatter.ofPattern("yyyy年MM月dd日(E)");
final var date = LocalDate.of(2022, 7, 1);
System.out.println(date.format(formatter)); // 2022年07月01日(金)
// 第1月曜日を取得。
final var ret1 = date.with(TemporalAdjusters.dayOfWeekInMonth(1, DayOfWeek.MONDAY));
System.out.println(ret1.format(formatter)); // 2022年07月04日(月)
// 第2月曜日を取得。
final var ret2 = date.with(TemporalAdjusters.dayOfWeekInMonth(2, DayOfWeek.MONDAY));
System.out.println(ret2.format(formatter)); // 2022年07月11日(月)
// 第4金曜日を取得。
final var ret3 = date.with(TemporalAdjusters.dayOfWeekInMonth(4, DayOfWeek.FRIDAY));
System.out.println(ret3.format(formatter)); // 2022年07月22日(金)
日時
日時の計算には LocalDateTime クラスを使います。
日時を表すクラスには、他にも ZonedDateTime や OffsetDateTime などありますが、同じように計算できます。
また、基本的には 日付 と 時刻 でご紹介したメソッドがそのまま使えます。
詳細はそちらもご確認ください。
足し算の例です。
// 1999年1月1日 10時30分15秒
final var dateTime = LocalDateTime.of(1999, 1, 1, 10, 30, 15);
System.out.println(dateTime); // 1999-01-01T10:30:15
// +1年
final var ret1 = dateTime.plusYears(1);
System.out.println(ret1); // 2000-01-01T10:30:15
// +2か月
final var ret2 = dateTime.plusMonths(2);
System.out.println(ret2); // 1999-03-01T10:30:15
// +3日
final var ret3 = dateTime.plusDays(3);
System.out.println(ret3); // 1999-01-04T10:30:15
// +5時間
final var ret4 = dateTime.plusHours(5);
System.out.println(ret4); // 1999-01-01T15:30:15
// +10分
final var ret5 = dateTime.plusMinutes(10);
System.out.println(ret5); // 1999-01-01T10:40:15
// +30秒
final var ret6 = dateTime.plusSeconds(30);
System.out.println(ret6); // 1999-01-01T10:30:45
時刻が 23:59:59 より大きくなると、日にちが +1 されます。
(正確にはナノ秒も含めると 23:59:59.999999999 です)
// 1999年12月31日 23時59分59秒
final var dateTime = LocalDateTime.of(1999, 12, 31, 23, 59, 59);
System.out.println(dateTime); // 1999-12-31T23:59:59
// +1秒
final var ret = dateTime.plusSeconds(1);
System.out.println(ret); // 2000-01-01T00:00
まとめ
Java の標準 API には、日時や曜日を計算するための API がいろいろとそろっています。
- 足し算:plus~ メソッド
- 引き算:minus~ メソッド
- 月の最終日の取得や、曜日の計算など:with メソッド + TemporalAdjusters
ぜひ、これらを有効に活用していきましょう。
関連記事
- 日付・時刻の基本
- 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 (タイムゾーン・オフセット)