Date and Time APIについて調べてみた その3
【概要】
今回は日時の変更方法について調べてみました。
【今までの日時変更】
過去のバージョンではCalendarクラスで
addメソッドかsetメソッドを使って値を変更していました。
日付をマイナスする場合はcal.add(Calendar.YEAR, -1)など
マイナス値でaddするというやり方でした。
【プラス/マイナス】
Date and Time APIの場合はプラスとマイナスごとに
メソッドが用意されています。
[サンプルコード]
public static void plusMinus() { final LocalDateTime now = LocalDateTime.now(); final LocalDateTime yearPlus = now.plusYears(1); final LocalDateTime monthPlus = now.plus(2, ChronoUnit.MONTHS); final LocalDateTime dayPlus = now.plus(Duration.ofDays(3)); final LocalDateTime hourMinus = now.minusHours(4); final LocalDateTime minuteMinus = now.minus(5, ChronoUnit.MINUTES); final LocalDateTime secondeMinu = now.minus(Duration.ofSeconds(6)); System.out.println("now : " + now); System.out.println("yearPlus : " + yearPlus); System.out.println("monthPlus : " + monthPlus); System.out.println("dayPlus : " + dayPlus); System.out.println("hourMinus : " + hourMinus); System.out.println("minuteMinus : " + minuteMinus); System.out.println("secondeMinu : " + secondeMinu); }
まずはplusYearsやplusMonthsなどのplusXXXメソッドと
minusYearsやplusMonthsなどのminusXXXメソッドです。
long型のパラメータを受け取り、設定された数値分値が変更されます。
次にplusメソッドとminusメソッドです。
それぞれメソッドシグネチャは2パターンです。
1つ目のパターンはlong型とTemporalUnitインターフェイスのオブジェクトを
パラメータとして受け取るパターンです。
TemporalUnitクラスは日付、時刻を示すためのインターフェイスです。
実装すれば独自の時刻の単位を作れますが、
通常使う単位はChronoUnitクラスで実装されています。
2つ目のパターンは
TemporalAmountインターフェイスのオブジェクトを
パラメータとして受け取るパターンです。
サンプルではDurationクラスのメソッドを使って
TemporalAmountインターフェイスのオブジェクトを生成しています。
[実行結果]
now : 2014-06-14T09:54:20.779 yearPlus : 2015-06-14T09:54:20.779 monthPlus : 2014-08-14T09:54:20.779 dayPlus : 2014-06-17T09:54:20.779 hourMinus : 2014-06-14T05:54:20.779 minuteMinus : 2014-06-14T09:49:20.779 secondeMinu : 2014-06-14T09:54:14.779
それぞれ指定した項目の値が変更されていることがわかります。
Date and Time APIの時刻クラスはイミュータブルなので
plus/minusメソッドを実行しても
元のオブジェクトは変更されません。
[サンプルコード2]
plus/minusメソッドで数値型のパラメータに
マイナスの値を設定しても正常に動作します。
public static void plusMinus02() { final LocalDateTime now = LocalDateTime.now(); final LocalDateTime yearPlus = now.plusYears(-2); final LocalDateTime hourMinus = now.minusYears(-2); System.out.println("yearPlus : " + yearPlus.getYear()); System.out.println("hourMinus : " + hourMinus.getYear()); }
[実行結果2]
yearPlus : 2012 hourMinus : 2016
指定されたパラメータの値どおりにマイナス値が有効になっています。
動きとしては問題ないと思いますが、
plusは増やす時のみ、minusは減らす時のみに使うほうが
コードの意味は汲み取りやすいですね。
【with】
withはCalendar#setメソッドに相当するメソッドで、
日付の項目を指定した値に変更します。
[サンプルコード]
public static void edit() { final LocalDateTime now = LocalDateTime.now(); final LocalDateTime yearWith = now.withYear(2020); final LocalDateTime monthWith = now.with(ChronoField.MONTH_OF_YEAR, 11); final LocalDateTime dayWith = now.with(v -> v.plus(1, ChronoUnit.DAYS)); System.out.println("yearWith : " + yearWith); System.out.println("monthWith : " + monthWith); System.out.println("dayWith : " + dayWith); }
withYearなどのwithXXXメソッドはlong型のパラメータを受け取ります。
受け取った値に変更されます。
withメソッドはメソッドシグネチャを2つ持ちます。
1つめのパターンは
TemporalFieldインターフェイスのオブジェクトとlong型の値を
パラメータとして受け取るパターンです
TemporalFieldインターフェイスは日付項目をあらわすものです。
通常使う日付項目はChronoFieldクラスで定義されています。
2つめのパターンは関数型オブジェクトを
パラメータとして受け取るパターンです。
関数型オブジェクトの
パラメータと戻り値はTemporalオブジェクトです。
[実行結果]
yearWith : 2020-06-14T10:19:44.256 monthWith : 2014-11-14T10:19:44.256 dayWith : 2014-06-15T10:19:44.256
各項目の値が変更されているのがわかります。
【まとめ】
Clandarクラスを使う時と比べて大きく変わったのは
イミュータブルになったことだと思います。
日付オブジェクトがミュータブルとして
扱わなければならないことは少ないと思うので
提供されるAPIとしては安全に扱うことが出来ます。