TL;DR
LocalDateTime
に対して月の差を取得するためにChronoUnit.MONTHS.between
関数を用いた場合、0.1秒でも期間に足らなければ差が1減ってしまうため、求めたい値になりません。
正確に計算しようと思えば型を変換するなどして、余計な情報を無くした上で比較する必要があります。
起きた問題
以下のようなコードを書いたところ、plusMonths(3)
しているにも関わらず2が表示されました。
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.concurrent.TimeUnit;
public class Main {
public static void main(String[] args) throws InterruptedException {
LocalDateTime endDateTime = LocalDateTime.now().plusMonths(3);
TimeUnit.MILLISECONDS.sleep(1); // 時間差の再現
LocalDateTime startDateTime = LocalDateTime.now();
// 2が出力される
System.out.println(ChronoUnit.MONTHS.between(startDateTime, endDateTime));
}
}
原因
公式ドキュメントでは以下のように説明されています。
計算では、2つの時間的オブジェクト間の完全な単位の数を表す整数を返します。たとえば、時間11:30と13:29の間の量は、2時間には1分足りないため、時間数では1時間だけになります。
ChronoUnit (Java Platform SE 8 )
つまり、たとえ1msであっても月の差に足りなければ切り捨てられてしまうということです。
対処
YearMonth
にすることで日時情報を切り捨てることで確実に欲しい値が出ます。
import java.time.LocalDateTime;
import java.time.YearMonth;
import java.time.temporal.ChronoUnit;
import java.util.concurrent.TimeUnit;
public class Main {
public static void main(String[] args) throws InterruptedException {
LocalDateTime endDateTime = LocalDateTime.now().plusMonths(3);
TimeUnit.MILLISECONDS.sleep(1); // 時間差の再現
LocalDateTime startDateTime = LocalDateTime.now();
// 3が出力される
System.out.println(
ChronoUnit.MONTHS.between(
YearMonth.from(startDateTime), YearMonth.from(endDateTime)
)
);
}
}
補足
公式ドキュメントには以下のように
実装では、2番目の型を最初の型のインスタンスに変換してから、量を計算します。
ChronoUnit (Java Platform SE 8 )