Clock を一言でいうと
Clock は
「“今”をどう決めるかをカプセル化するためのオブジェクト」
です。
Instant.now() や LocalDateTime.now() が、裏側で「どの時計を使うか」を決めるために使うのが Clock。
アプリ側で Clock を自分で持つことで、「テストしやすい現在時刻」「タイムゾーンを意識した現在時刻」を扱えるようになります。
なぜ Clock が必要になるのか
直接 now() を呼ぶと何が困るか
素朴に書くと、こうなります。
LocalDateTime now = LocalDateTime.now();
Java一見これで十分に見えますが、問題は「テスト」と「再現性」です。
今この瞬間にテストを実行したときと、1 分後に実行したときで、now の値が変わってしまいます。
「今日が締切日かどうか」「今が営業時間内かどうか」といったロジックをテストしたいとき、now() を直接呼んでいると、テストが「そのときの実時間」に依存してしまいます。
ここで Clock の出番です。Clock を使うと、「今」を外から差し込めるようになります。
Clock の基本:now(Clock) という形にする
Clock を渡して現在時刻を決める
LocalDateTime や Instant には、now(Clock clock) というオーバーロードがあります。
Clock clock = Clock.systemDefaultZone(); // システムデフォルトのタイムゾーンを使う時計
LocalDateTime now = LocalDateTime.now(clock);
Instant instantNow = Instant.now(clock);
Javaここで重要なのは、「どの Clock を使うか」を自分で選べることです。
本番では「本物の時計」、テストでは「固定された時計」を渡す、という切り替えができます。
Clock をフィールドとして持つ設計
サービスクラスなどで、こういう形にしておくと強いです。
class BillingService {
private final Clock clock;
BillingService(Clock clock) {
this.clock = clock;
}
LocalDate today() {
return LocalDate.now(clock);
}
}
Java本番コードでは Clock.systemDefaultZone() や Clock.systemUTC() を渡し、
テストコードでは Clock.fixed(...) を渡す。
これだけで、「時間に依存するロジック」を、テスト可能な形にできます。
代表的な Clock 実装
systemDefaultZone と systemUTC
Clock.systemDefaultZone() は、「システムのデフォルトタイムゾーン」を使う時計です。
Clock systemClock = Clock.systemDefaultZone();
ZonedDateTime now = ZonedDateTime.now(systemClock);
JavaClock.systemUTC() は、「UTC 固定」の時計です。
Clock utcClock = Clock.systemUTC();
Instant nowUtc = Instant.now(utcClock);
Javaアプリ全体で「内部は UTC で扱う」と決めるなら、systemUTC() を使うのが筋が良いです。
fixed:テスト用の「止まった時計」
Clock.fixed(Instant, ZoneId) は、「常に同じ時刻を返す時計」です。
Instant fixedInstant = Instant.parse("2025-01-18T10:00:00Z");
Clock fixedClock = Clock.fixed(fixedInstant, ZoneId.of("Asia/Tokyo"));
Instant now1 = Instant.now(fixedClock);
Instant now2 = Instant.now(fixedClock);
System.out.println(now1); // どちらも 2025-01-18T10:00:00Z
System.out.println(now2);
Javaテストで「今が 2025-01-18T10:00:00Z だと仮定して、このロジックがどう動くか」を検証したいときに使います。
これにより、テスト結果が「実行した時間」に左右されなくなります。
offset:基準の Clock からズラした時計
Clock.offset(Clock base, Duration offset) は、「ある時計から一定時間ずらした時計」です。
Clock base = Clock.systemUTC();
Clock plusOneHour = Clock.offset(base, Duration.ofHours(1));
Instant baseNow = Instant.now(base);
Instant plusNow = Instant.now(plusOneHour);
Java「1 時間後の世界をシミュレーションしたい」といったテストで使えます。
Clock を使うとテストがどう楽になるか
直接 now() を呼んでいるコードのつらさ
例えば、こんなメソッドを考えます。
boolean isToday(LocalDate date) {
return LocalDate.now().equals(date);
}
Javaこのメソッドをテストしたいとき、「テスト実行時の“今日”」に依存してしまいます。
明日になったらテストコードを書き換えないといけない、という最悪の状態です。
Clock を注入する形に変える
Clock を使うと、こう書き換えられます。
class DateChecker {
private final Clock clock;
DateChecker(Clock clock) {
this.clock = clock;
}
boolean isToday(LocalDate date) {
return LocalDate.now(clock).equals(date);
}
}
Javaテストでは、こうします。
Instant fixedInstant = Instant.parse("2025-01-18T00:00:00Z");
Clock fixedClock = Clock.fixed(fixedInstant, ZoneId.of("Asia/Tokyo"));
DateChecker checker = new DateChecker(fixedClock);
assert checker.isToday(LocalDate.of(2025, 1, 18)); // true
assert !checker.isToday(LocalDate.of(2025, 1, 19)); // false
Java「テストの中で“今日”を自由に決められる」ようになるのが、Clock 最大の価値です。
設計としての一番大事なポイント:「時間を依存性として扱う」
「時間も依存性注入する」という発想
データベース接続や外部 API クライアントを DI するのと同じように、
「現在時刻を決める仕組み(Clock)」も DI する、という発想がモダンな設計です。
時間を直接 now() で取ってしまうと、そのメソッドは「環境にべったり依存したコード」になります。
Clock を受け取るようにしておけば、
本番環境では「本物の時計」
テスト環境では「固定された時計」
を差し替えられる、柔軟な設計になります。
「どこまで Clock を伝播させるか」を決める
現実的には、アプリ全体で 1 個の Clock を管理し、
サービス層やドメイン層にコンストラクタ経由で渡していく、という形が多いです。
コントローラ層で Clock を new してしまうのではなく、
DI コンテナ(Spring など)で Clock を Bean として管理し、
必要なクラスに注入する、というスタイルにすると、設計がさらにきれいになります。
まとめ:Clock を自分の言葉で説明するなら
あなたの言葉で Clock を説明するなら、こうです。
「Clock は、“今”をどう決めるかをオブジェクトとして切り出したもの。LocalDateTime.now() のように直接現在時刻を取るのではなく、LocalDateTime.now(clock) のように Clock を渡すことで、
本番では本物の時計、テストでは固定された時計を使い分けられる。
時間を依存性として扱うことで、“時間に依存するロジック”をテストしやすく、再現性のあるコードにできる。」
