Java8のDate and Time APIを使いたい

Javaプログラマーなら、SimpleDateFormatを
使ったことのある人は多いのではないでしょうか。
私は業務では古いJavaのバージョンでも開発しているので、
今だにSimpleDateFormatは現役で使っています。

Java8ではDate and Time APIという新しいライブラリが導入され、
日付関連の処理が今まで以上に使いやすくなっている・・かもしれないので
実際に手を動かして確認してみる。
※Java7の環境ならJoda Timeを使えば似たような事ができます。Joda Timeは業務でも現役。
Joda-Time - Home


  • よくあるSimpleDateFormatの例
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
// 文字列を日付に変換
Date stringToDate = new Date();
try {
	stringToDate = sdf.parse("2012-12-12");
} catch (ParseException e) {
	// TODO Auto-generated catch block
	e.printStackTrace();
}

// 日付を文字列に変換
String dateToString = sdf.format(new Date());

// コンソール出力
System.out.println("stringToDate:" + stringToDate.toString());
System.out.println("dateToString:" + dateToString);
  • コンソール出力結果
stringToDate:Wed Dec 12 00:00:00 JST 2012
dateToString:2016-09-22

上記はよくある典型的な使用例です。
これをDate and Time APIを使って実装してみます。

  • 同じことをDate and Time APIを使ってやってみる。
// 文字列を日付に変換(Date and Time API Version)
LocalDate localDateToDate = LocalDate.parse("2012-12-12", DateTimeFormatter.ofPattern("yyyy-MM-dd"));
LocalDateTime localDateTimeToDate = localDateToDate.atTime(00, 00);
		
// 日付を文字列に変換
Instant instant = new Date().toInstant();
LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, ZoneOffset.systemDefault());
String localDateToString = localDateTime.toLocalDate().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
		
// コンソール出力
System.out.println("localDateToDate:" + localDateTimeToDate.toString());
System.out.println("localDateToString" + localDateToString.toString());
  • コンソール出力結果
localDateToDate:2012-12-12T00:00
localDateToString2016-09-24

単純な日付型←→文字列の変換だと、コード量はあまり変わらない様子。

  • 比較もやってみる。
// 日付A
LocalDateTime compareDateA = LocalDateTime.of(2013, 3, 1, 10, 10);

// 日付B
LocalDateTime compareDateB = LocalDateTime.of(2013, 3, 1, 10, 5);

// 比較 引数より後の場合は0より大きい、引数より前の場合は0より小さい、等しい場合は0
System.out.println("日付Aと日付Bの比較結果:" + compareDateA.compareTo(compareDateB));
  • コンソール出力結果
日付Aと日付Bの比較結果:1
  • 個人的にはequalsメソッドによる比較よりも、ミリ秒比較のほうが分かりやすくて好きです。
// 日付Aのミリ秒
ZonedDateTime zdtCompareDateA = compareDateA.atZone(ZoneId.systemDefault());
long compareDateAMillis = zdtCompareDateA.toInstant().toEpochMilli();
System.out.println("日付Aのミリ秒:" + compareDateAMillis);
// 日付Bのミリ秒
ZonedDateTime zdtCompareDateB = compareDateB.atZone(ZoneId.systemDefault());
long compareDateBMillis = zdtCompareDateB.toInstant().toEpochMilli();
System.out.println("日付Bのミリ秒:" + compareDateBMillis);

// 単純比較
if (compareDateAMillis > compareDateBMillis) {
	System.out.println("比較結果:日付Aは日付Bより大きい(後)");
} else {
	System.out.println("比較結果:日付Aは日付Bより小さい(前)または、等しい");
}
  • コンソール出力結果
日付Aのミリ秒:1362100200000
日付Bのミリ秒:1362099900000
比較結果:日付Aは日付Bより大きい(後)

ふむ、今までのDate型と同じような比較が可能ですね。

  • Date and Time APIを使うメリットってなんだ?

上記のように一見するとどっち使っても同じのように見えるんですが、
Date and Time APIを使うことによって下記のようなメリットがあるんです。

  1. 日付の加算・減算にCalendarクラスを使う必要がない。
    JavaてDate型のみだと日付の加算や減算ってやりにくくてですね、
    加算や減算をしたいならCalendarクラスを使ったりして、上手にやりくりしないといけない。
    つまり生成するインスタンスが増えるんですね。コード記述も綺麗じゃない。
    Date and Time APIなら簡単に加算・減算ができる。

    • シンプルに日付を足してみる
    System.out.println("加算前の日付:" + compareDateA);
    // 1日足す
    compareDateA = compareDateA.plusDays(1);
    System.out.println("加算後の日付:" + compareDateA);
    
    • コンソール出力結果
    加算前の日付:2013-03-01T10:10
    加算後の日付:2013-03-02T10:10


  2. スレッドセーフである。
    マルチスレッドプログラミング時に、真価を発揮します。
    SimpleDateFormatはスレッドセーフではないので、マルチスレッド処理で
    期待していない結果を出す時があります。これは覚えておかないと、不具合の原因になります。
    Date and Time APIはスレッドセーフであるため、マルチスレッド処理で積極的に使っていけます。
    というか、SimpleDateFormatはマルチスレッド処理では使っちゃダメですね。

Date and Time API有識者の方々が
多くのナレッジを残してくれているので、私がBlogとして残すのも
今更感がしましたが、いい学習にはなりました。
下記に参考サイトを載せてますので、参考にしていただけると。

参考にしたサイト
EclipseのCtrl + SpaceがmacでSpotlight検索に化ける問題の解消方法
macのEclipseでコード補完のキーバインド変更 - xykの日記

■Date and Time API関連
Date and Time API 復習 - Qiita
Java8 新機能についてのまとめ 2 - A Memorandum
datetime - How to get milliseconds from LocalDateTime in Java 8 - Stack Overflow
ImmutableでスレッドセーフになったJavaの新しい日時APIの基礎知識 (1/5):ここが大変だよJava 8 Date-Time API(1) - @IT
http://www.coppermine.jp/docs/programming/2014/07/jsr310-essentials.html
http://www.coppermine.jp/docs/programming/2016/05/jjug-ccc-2016-spring.html