抑えておくべき日付や時刻を表すクラス 以下の4つを抑えておきましょう。
java.time.LocalDateTime
java.time.LocalDate
java.time.LocalTime
java.time.ZonedDateTime
逆に、以下の3つは使用しないようにしましょう。
java.util.Date
java.util.Calendar
java.util.GregorianCalendar
現在のインスタンスを取得する方法 現在の日付や時刻を取得するにはスタティックメソッドのnow
を使います。
1 2 3 4 System.out.println(ZonedDateTime.now()); System.out.println(LocalDateTime.now()); System.out.println(LocalDate.now()); System.out.println(LocalTime.now());
実行例 1 2 3 4 2019-09-23T20:06:44.903432+09:00[Asia/Tokyo] 2019-09-23T20:06:44.904434600 2019-09-23 20:06:44.904434600
指定した日時のインスタンスを取得する方法 LocalDateTime of
メソッドを使います。
1 2 3 4 5 6 7 8 var ldt = LocalDateTime.of(2020, 1, 2, 3, 4, 5); assertThat(ldt.getYear()).isEqualTo(2020); assertThat(ldt.getMonthValue()).isEqualTo(1); assertThat(ldt.getDayOfMonth()).isEqualTo(2); assertThat(ldt.getHour()).isEqualTo(3); assertThat(ldt.getMinute()).isEqualTo(4); assertThat(ldt.getSecond()).isEqualTo(5); assertThat(ldt.getDayOfWeek()).isEqualTo(DayOfWeek.THURSDAY);
上記は、年、月、日、時、分、秒からLocalDateTimeのインスタンスを取得しています。 他にもいくつか種類があります。詳細はドキュメントを見てください。https://docs.oracle.com/javase/jp/8/docs/api/java/time/LocalDateTime.html
LocalDateTime of
メソッドを使います。
1 2 3 4 var ld = LocalDate.of(2020, 1, 2); assertThat(ld.getYear()).isEqualTo(2020); assertThat(ld.getMonthValue()).isEqualTo(1); assertThat(ld.getDayOfMonth()).isEqualTo(2);
上記は、年、月、日からLocalDateのインスタンスを取得しています。 他にもいくつか種類があります。詳細はドキュメントを見てください。https://docs.oracle.com/javase/jp/8/docs/api/java/time/LocalDate.html
LocalDate of
メソッドを使います。
1 2 3 4 var lt = LocalTime.of(3, 4, 5); assertThat(lt.getHour()).isEqualTo(3); assertThat(lt.getMinute()).isEqualTo(4); assertThat(lt.getSecond()).isEqualTo(5);
上記は、時、分、秒からLocalTimeのインスタンスを取得しています。 他にもいくつか種類があります。詳細はドキュメントを見てください。https://docs.oracle.com/javase/jp/8/docs/api/java/time/LocalTime.html
ZonedDateTime of
メソッドを使います。
1 2 var ldt = LocalDateTime.of(2020, 1, 2, 3, 4, 5); var zdt = ZonedDateTime.of(ldt, ZoneId.of("Asia/Tokyo"));
上記は、LocalDateTimeとZoneIdからZonedDateTimeのインスタンスを取得しています。 他にも、LocalDateとLocalTimeとZoneIdから取得するなどいくつか種類があります。詳細はドキュメントを見てください。https://docs.oracle.com/javase/jp/8/docs/api/java/time/ZonedDateTime.html
このZoneIdとはタイムゾーンのIDのことです。 東京はUTCとの時差はプラス9時間です。
UTCは協定世界時といい、世界の時刻はこの時刻を基準としています。 UTCが6時なら、東京は9時間プラスの15時です。 UTCの説明はこちら。https://ja.wikipedia.org/wiki/%E5%8D%94%E5%AE%9A%E4%B8%96%E7%95%8C%E6%99%82
世界の時差はこちらのサイトのように世界地図で表示されているとイメージしやすいと思います。https://www.timeanddate.com/time/current-number-time-zones.html
東京はプラス9時間ですが、中国はプラス8時間です。 東京が6時なら、中国は5時です。この1時間後に中国は6時になります。
どのクラスを使えばいい? 1つの考え方として、ある特定の地域でのみ動作させるプログラムならLocalDateTimeで十分です。 複数の地域(ZoneIdが異なる地域)でも動作させるプログラムならZonedDateTimeを使えばいいと思います。
また、ZonedDateTimeを使う場合でも、DBなどに保存されている情報はレコードごとにタイムゾーンを持っていないと思います。 なのでマッピングにはLocalDateTimeを使用して、ビジネスロジック部分ではZonedDateTimeに変換すればいいと思います。
時間の加算、減算の方法 加算にはplus
メソッドやplusMinutes
メソッド、plusSeconds
メソッドなどを使います。
1 2 3 4 5 6 var ldt = LocalDateTime.of(2020, 1, 2, 3, 4, 5); // 10分加算 assertThat(ldt.plus(Duration.ofMinutes(10)).getMinute()).isEqualTo(14); assertThat(ldt.plus(10, ChronoUnit.MINUTES).getMinute()).isEqualTo(14); assertThat(ldt.plusMinutes(10).getMinute()).isEqualTo(14);
この3つのパターンを覚えておきましょう。
plus(10分間)
plus(10, 分)
plusMinutes(10)
時間の切り捨ての方法 truncatedTo
を使います。
1 2 3 4 5 6 7 8 var ldt = LocalDateTime.of(2020, 1, 2, 3, 4, 5); // 秒未満を切り捨て assertThat(ldt.truncatedTo(ChronoUnit.SECONDS).getSecond()).isEqualTo(5); // 分未満を切り捨て assertThat(ldt.truncatedTo(ChronoUnit.MINUTES).getSecond()).isEqualTo(0); assertThat(ldt.truncatedTo(ChronoUnit.MINUTES).getMinute()).isEqualTo(4);
文字列への変換方法 format
メソッドを使います。引数に指定するのはDateTimeFormatter
です。DateTimeFormatter
にはあらかじめいくつか用意されています。 詳細はドキュメントを見てください。https://docs.oracle.com/javase/jp/8/docs/api/java/time/format/DateTimeFormatter.html
1 2 3 4 5 var ldt = LocalDateTime.of(2020, 1, 2, 3, 4, 5); assertThat(ldt.format(DateTimeFormatter.ISO_LOCAL_TIME)).isEqualTo("03:04:05"); assertThat(ldt.format(DateTimeFormatter.ISO_LOCAL_DATE)).isEqualTo("2020-01-02"); assertThat(ldt.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME)).isEqualTo("2020-01-02T03:04:05");
独自のフォーマットを作るにはDateTimeFormatter
のofPattern
メソッドを使います。 引数に指定するフォーマットは以下のとおりです(一部)。
1 2 3 4 5 6 7 8 9 10 y = year (yy or yyyy) M = month (MM) d = day in month (dd) h = hour (0-12) (hh) H = hour (0-23) (HH) m = minute in hour (mm) s = seconds (ss) S = milliseconds (SSS) z = time zone text Z = time zone, time offset
詳細はドキュメントを見てください。https://docs.oracle.com/javase/jp/8/docs/api/java/time/format/DateTimeFormatter.html
1 2 3 4 5 6 7 8 9 var ldt = LocalDateTime.of(2020, 1, 2, 3, 4, 5); { var dtf = DateTimeFormatter.ofPattern("yyyy/MM/dd"); assertThat(ldt.format(dtf)).isEqualTo("2020/01/02"); } { var dtf = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss"); assertThat(ldt.format(dtf)).isEqualTo("2020/01/02 03:04:05"); }
タイムゾーンの変換方法 ユーザーに表示するときなど、この時刻は東京だと15時だけど、中国では何時?といった変換をしたいことがあります。 この場合はwithZoneSameInstant
メソッドを使います。このメソッドは日時情報を変えずにタイムゾーンを変更します。
1 2 3 4 5 6 var ldt = LocalDateTime.of(2020, 1, 2, 3, 4, 5); var zdt = ZonedDateTime.of(ldt, ZoneId.of("Asia/Tokyo")); assertThat(zdt.withZoneSameInstant(ZoneId.of("Asia/Shanghai")) .format(DateTimeFormatter.ISO_ZONED_DATE_TIME)) .isEqualTo("2020-01-02T02:04:05+08:00[Asia/Shanghai]");
一方、日時情報を変えてタイムゾーンを変えることもできます。この場合はwithZoneSameLocal
メソッドを使います。 (どのようなときに使用するのか思いつきませんでしたが)
1 2 3 4 5 6 var ldt = LocalDateTime.of(2020, 1, 2, 3, 4, 5); var zdt = ZonedDateTime.of(ldt, ZoneId.of("Asia/Tokyo")); assertThat(zdt.withZoneSameLocal(ZoneId.of("Asia/Shanghai")) .format(DateTimeFormatter.ISO_ZONED_DATE_TIME)) .isEqualTo("2020-01-02T03:04:05+08:00[Asia/Shanghai]");