日々常々

ふつうのプログラマがあたりまえにしたいこと。

Date and Time APIを触ってみた

JavaAdventCalendar2012の24日目。カレンダーなんで日付のです。24日とかただの日だし。12/24とか約分したら1/2だし。


ところでこれの答えわかります?*1

System.out.println(12/24);

準備とか

バージョン 0.7.0-alpha と書かれている通り、まだ出来てないとかなんとか。0.6.3ならダウンロードできるんだけど、チラチラ見てると幾らか変わってるので、GitHubから持ってきてビルドします。

clone して ant 叩いて build にできた threeten-0.7.0-alpha.jar を適当な場所に持ってって、クラスパスに通せば完了。

ざーっと使ってみる

  • Instant - An instant on the time-line
  • Duration - A duration of time

瞬間と期間っぽい。

Instant instant = Instant.now();
Duration duration = Duration.ofHours(-3);
println(instant);  // 2012-12-24T12:52:12.837Z
println(duration); // PT-10800S

DateTime dateTime = duration.doPlusAdjustment(instant);
println(dateTime); // 2012-12-24T09:52:12.837Z
  • LocalDate - A date, with no time nor zone-offset
  • LocalTime - A time, with no date nor zone-offset
  • LocalDateTime - A date-time, with no zone-offset

日付、時間、その組み合わせっと。OffsetDateとかZonedDateTimeとかもあるみたいなんだけど、とりあえず割愛。

LocalDate date = LocalDate.of(2012, Month.DECEMBER, 24);

println(date); // 2012-12-24
printf("year: %s, monthValue: %s, dayOfMonth: %s%n", date.getYear(), date.getMonthValue(), date.getDayOfMonth());
// year: 2012, monthValue: 12, dayOfMonth: 24

println(date.withYear(2013)); // 2013-12-24
println(date.withMonth(11)); // 2012-11-24
println(date.withDayOfMonth(22)); // 2012-12-22

println(date.plusDays(7)); // 2012-12-31
println(date.plusDays(8)); // 2013-01-01

println(date.toEpochDay()); // 15698

println(date.atTime(12, 34)); // 2012-12-24T12:34
println(date.atTime(LocalTime.ofSecondOfDay(80000))); // 2012-12-24T22:13:20

Immutableなので、withとかplusとかしても値は変わりません。"Clear, explicit and expected" とか書いてる通り、素直に使える感じですね。
enum Monthとか、MonthValueの値が1-12だとか、地味に嬉しいところ。Timeも同じような感じで使えます。DateTimeはDateとTimeの両方の操作がほぼ全部できる感じでした。


DateTimeはDateとTimeをくっつけたもので、この3クラスは以下のようにくっつけたり剥がしたりできました。

LocalDateTime dateTime = LocalDateTime.of(2012, 12, 24, 11, 22, 33);
println(dateTime); // 2012-12-24T11:22:33

LocalDate date = dateTime.getDate();
LocalTime time = dateTime.getTime();
println(date); // 2012-12-24
println(time); // 11:22:33

println(date.atTime(time)); // 2012-12-24T11:22:33
println(time.atDate(date)); // 2012-12-24T11:22:33


"Fluent API"ってのはこの辺かな。withとAdjusterを使うのとか。

LocalDate date = LocalDate.of(2012, Month.DECEMBER, 24);

println(date.with(firstDayOfMonth())); // 2012-12-01
println(date.with(firstInMonth(FRIDAY))); // 2012-12-07
println(date.with(next(MONDAY))); // 2012-12-31
println(date.with(nextOrSame(MONDAY))); // 2012-12-24

いい感じだとは思う、けれどもstatic importが前提になるので、これまた既存のJavaコーディング規約との微妙な戦いをするはめになりますね。Adjusterとかは自分で作れるので、上手いこと使えば……

脱線

ところでWithAdjusterは1メソッドのインタフェースです。

public interface WithAdjuster {
    DateTime doWithAdjustment(DateTime dateTime);
}

つまりLambda使えますね。

DateTime now = Instant.now();
println(now.with(it -> Duration.ofDays(10).doPlusAdjustment(it)));

嬉しさがわからない(真顔
実際この辺は三営業日後を取得したりとか*2、複雑な日付計算を押し込めてなんぼだろうし、Lambdaでやって嬉しいことはあまりなさそうな気がします。

感想

だいたい業務システムだと日付は日付で扱いたいときが多くて、素直に同じ日がequalsでtrueになってくれるだけでも、Dateはありがたいです。標準で使えるのがいいと思んです。ぶっちゃ業務でJoda-Timeとか見たことないです。
ビルドして出来たjarに javadoc に書かれてるクラスとかが普通に無かったりして、ほんのり触ってみた程度になりました。でもいい感じには思えました。少なくともDateやCalendarより扱いやすいのは間違いなさそうです。

*1:そうですね、0ですね。

*2:そんな感じのことが書いてありました