LoginSignup
5
2

More than 5 years have passed since last update.

java.time.Clockで現在時刻を扱うUT

Posted at

現在時刻を扱うUT辛くないですか?
Date and Time API(JSR-310)のJavadoc見ていたら使えそうなクラスを見つけました!
その名もjava.time.Clock

ちょっとJavadoc引用。

タイムゾーンを使用して現在の時点、日付および時間へのアクセスを提供するクロックです。
このクラスのインスタンスは、現在の時点を検索するために使用されます。現在の時点は、保存済みタイムゾーンを使用して現在の日時を検索することで解釈できます。そのためクロックは、System.currentTimeMillis()およびTimeZone.getDefault()のかわりに使用できます。

Clockの使用は任意です。すべての主要な日付/時間クラスには、デフォルト・タイムゾーンのシステム・クロックを使用するnow()ファクトリ・メソッドも用意されています。この抽象の主要目的は、代替クロックを必要なときにプラグインできるようにすることです。アプリケーションはstaticメソッドではなくオブジェクトを使用して現在時間を取得します。これによりテストを単純化できます。

アプリケーションにとってのベスト・プラクティスは、Clockを現在の時点を必要とするメソッドに渡すことです。これを実現するための1つの方法が、Dependency Injectionフレームワークです。

public class MyBean {
private Clock clock; // dependency inject
...
public void process(LocalDate eventDate) {
if (eventDate.isBefore(LocalDate.now(clock)) {
...
}
}
}

このアプローチにより、代替クロック(fixedやoffsetなど)をテストで使用できます。
systemファクトリ・メソッドは、最良の利用可能なシステム・クロックに基づくクロックを提供します。これは、System.currentTimeMillis()またはより分解能の高いクロック(利用できる場合)を使用します。

これってようはClockインスタンスをDIすることでテストを単純化できるって言っていますよね??

ということはClockインスタンスを生成さえできればどうとでもなるということで、Clockインスタンスの生成を試してみましょう!

Scalaで書きますよ!
Javaは1.8.0_131
Scalaは2.12.2
を使っています。

以降はimport java.time._している前提で。

Clockインスタンスの生成

一番シンプルな使い方はこの辺かな。

scala> Clock.systemDefaultZone
res0: java.time.Clock = SystemClock[Asia/Tokyo]

scala> res0.instant
res1: java.time.Instant = 2017-06-29T16:26:19.189Z

scala> Clock.systemUTC
res2: java.time.Clock = SystemClock[Z]

scala> res2.instant
res3: java.time.Instant = 2017-06-29T16:27:40.517Z

まぁこの辺は完全に現在時刻取得です。

次に固定化したClock生成。

scala> val zoneId = ZoneId.systemDefault
zoneId: java.time.ZoneId = Asia/Tokyo

scala> val datetime = ZonedDateTime.of(2017, 6, 27, 22, 0, 0, 0, zoneId).toInstant
datetime: java.time.Instant = 2017-06-27T13:00:00Z

scala> val clock = Clock.fixed(datetime, zoneId)
clock: java.time.Clock = FixedClock[2017-06-27T13:00:00Z,Asia/Tokyo]

こんな感じで固定化したClockが使えますね。

固定化したClockインスタンスを使う

これは簡単。ぱっと見た感じ日付、時間、Instant系はnow(Clock clock)メソッドを持っているので、例えばこんな感じ。

scala> val now = ZonedDateTime.now(clock)
now: java.time.ZonedDateTime = 2017-06-27T22:00+09:00[Asia/Tokyo]

java.util.Date を使っているって場合は変換すれば良い。

scala> val date = java.util.Date.from(Instant.now(clock))
date: java.util.Date = Tue Jun 27 22:00:00 JST 2017

これを差し込めばUTも楽勝っすね!
あ、でもMinimal Cake Patternを使えばClockは一切使わずにしかもかなり簡単にいけることに書いて気づいたぞ。。。

既存のアプリケーションにいれようとするとお膳立てしないといけないから、それはそれで大変そう。それならMinimal Cake Pattern化するよね。

Minimal Cake Patternすげーって結論になってしまった。。。
面白いAPIだと思ったのに。

5
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
2