2018年4月27日金曜日

[JavaSE8 Goldへの道] その15 Date/Time APIその3 日時に基づく各種計算

JavaSE8 Goldへの道(Upgrade to Java SE 8 Programmer 1Z0-810 試験対策)12回目です。

一連の記事は「JavaSE8Gold」ラベルを付けていきます。

いよいよ最終回です。最後は日時に基づく各種計算方法を解説します。



Clockクラス

java.time.Clockクラスは、Instantと同じようにある時点を示しますが、基本的な使い方は外的要因で定まる日時をシステムに与えるケースで、日時クラスの生成時に渡してやることでシステム全体の日時を制御するために使えます。
例えばLocalDateTime#nowの引数に渡します。

Clockの生成方法は以下のようなものがあります。
//システムデフォルトのタイムゾーンで生成
Clock.systemDefaultZone();

//UTCで生成
Clock.systemUTC();

//タイムゾーンを指定して生成
Clock.system(ZoneId.of("Asia/Tokyo"));

//固定日時で生成→このクロックで生成する日時は常に固定になる
Clock.fixed(Instant.parse("2018-04-24T16:35:44Z"), ZoneId.of("Asia/Tokyo"));

//秒以下が常に0で、1分ごとに進む
Clock.tickMinutes(ZoneId.systemDefault());

//ナノ秒フィールドが常に0(ミリ秒以下)で、1秒毎に進む
Clock.tickSeconds(ZoneId.systemDefault());

//指定された単位のDurationで進む
Clock.tick(Clock.systemDefaultZone(), Duration.of(2, ChronoUnit.SECONDS));
fixedメソッドで生成されたClockを引数にしたLocalDateTime#now(他の日時クラスも同様)の結果は、常に固定の値になります。
またtick~メソッドでは特定の単位でのみ進むようになります。

よくあるパターンでは「業務日付」などと呼ばれる、DB等で管理されるカレンダーに従って動くシステムを実装する際や、テストにおいて特定の日(月初や年初など)を指定できるように、Clockを元に日時クラスを生成しておくと良さそうです。


Durationクラス

その1でも紹介した、時刻ベースの時間量を表すクラスです。

いつもの参考サイトのサンプルコード
Instant now = Instant.now();
//「1時間」を表す時間量
Duration d = Duration.ofHours(1);
Instant then = now.plus(d);
System.out.println("now : " + now + " ; then : " + then);
実行結果
now : 2018-04-24T07:43:33.515Z ; then : 2018-04-24T08:43:33.515Z
Duration同士を足し合わせたり、自身の値に対して加減算したコピーを生成することができます。
Duration d1 = Duration.ofHours(1);
Duration d2 = Duration.ofDays(2);
d1 = d1.plus(d2);
System.out.println("Total duration : " + d1);
実行結果
Total duration : PT49H
Duration#toStringの結果は、ISO-8601秒ベース表現を使用した文字列表現です(PT8H6M12.345Sなど)。
「PT」のあと、時分秒が記号で表されます。それより大きな単位(日など)は次に出てくるPeriodクラスと混同しないように時間単位で出力されるようです。


Periodクラス

こちらも紹介済みの、日付ベースの時間量を表すクラスです。

参考サイトのサンプルコード
LocalDate today = LocalDate.parse("2018-04-24");
Period sixDays = Period.ofDays(7);
LocalDate nextWeek = today.plus(sixDays);
System.out.println("next week : " + nextWeek);
実行結果
next week : 2018-05-01
そのままですね。

betweenメソッドも解説済みですが。
LocalDate newYear = LocalDate.parse("2018-01-01");
Period passed = Period.between(newYear, LocalDate.now());
System.out.println("passed since NY : " + passed);
実行結果
passed since NY : P3M23D
Period#toStringもISO-8601の期間フォーマットで出力されます。先頭にPがついて、記号と共に表されます。


TemporalUnit

java.time.temporal.TemporalUnitインタフェースは日時の単位を表すものです。
その実装としてChronoUnit列挙型があります。

ちょうど、Calendarクラスである単位の値を取るときに定数を指定したのと同じようなイメージです。

※もう一つ、TemporalFieldというインタフェースもあり、実装としてChronoField列挙型があります。
ChronoUnitは時間量のDuration,Periodや日時の加減算に使用し、ChronoFieldは日時クラスの各要素にアクセスする際(getwithメソッドなど)に指定します。

参考サイトのサンプルコード
LocalDate today = LocalDate.now();
System.out.println("Today: " + today);

LocalDate twoWeeksLater = today.plus(2, ChronoUnit.WEEKS);
System.out.println("Two weeks later: " + twoWeeksLater);
実行結果
Today: 2018-04-24
Two weeks later: 2018-05-08
ChronoUnitの定義を見ると、一般的なDAYSHOURSなどの他に、CENTURIESFOREVERなんてのもあります。
FOREVERの説明は「永遠の概念を表す人為的単位。」とあり、なんか哲学的です。


各日時クラスにはtruncatedToメソッドというのがあり、引数で指定したTemporalUnitよりも小さい単位を切り詰めた日時を返します。
LocalDateTime ldtStart = LocalDateTime.of(2018, 4, 23, 12, 7, 1);
LocalDateTime ldtEnd   = LocalDateTime.of(2018, 4, 23, 15, 8, 2);

LocalDateTime ldtStartNew = ldtStart.truncatedTo(ChronoUnit.MINUTES);
System.out.println("Start time truncated to minutes : " + ldtStartNew);

LocalDateTime ldtEndNew = ldtEnd.truncatedTo(ChronoUnit.HOURS);
System.out.println("End time truncated to hours : " + ldtEndNew);
実行結果
Start time truncated to minutes : 2018-04-23T12:07
End time truncated to hours : 2018-04-23T15:00
ChronoUnit#betweenメソッドを使うと、自身の単位で2つの日時の差を計算できます。
LocalDateTime ldtStart = LocalDateTime.of(2018, 4, 23, 12, 7, 1);
LocalDateTime ldtEnd   = LocalDateTime.of(2018, 4, 23, 15, 8, 2);

long numberOfHours = ChronoUnit.HOURS.between(ldtStart, ldtEnd);
System.out.println("Between in hours : " + numberOfHours);

long numberOfMinutes = ChronoUnit.MINUTES.between(ldtStart, ldtEnd);
System.out.println("Between in minutes : " + numberOfMinutes);
実行結果
Between in hours : 3
Between in minutes : 181



と、い、う、わ、け、で

これでJava SE 8 Goldアップグレード試験の全範囲の解説が終わりました。 もうチケットは買ったので、近い内に受験して結果を報告したいと思います。 一連の記事が、皆様のお役に立てば幸いです。

今回も以下のサイトとGoldの通常試験の参考書を参考にしています。
一連の記事は「JavaSE8Gold」ラベルを付けています。

それではみなさまよきガジェットライフを(´∀`)ノ


▼こちらの記事もどうぞ

▼ブログを気に入っていただけたらRSS登録をお願いします!
▼ブログランキング参加中!応援よろしくお願いします。

スポンサーリンク