動作確認version: Java11
なぜ現在日時を変える必要があるか
JUnitレベルではなく実際にWebサーバを起動してイベントの開始・終了の制御等をテストしたいとき、サーバの現在日時を変えたくなる。しかしLinuxサーバの時間を変えるのはおすすめできない。最近のカーネルは、安易に時間を変えてしばらくするとクラッシュすることが多い。具体的にはCentOS6時代は問題なかったがCentOS7は問題がよく起こる。
単純にLinuxサーバの時間を変えるのではなくfaketime
というツールを使えば問題なく日時を変えられるが、今回はJavaだけで安全に日時を変える方法について書く。
現在日時をずらす
Clock.offset
を使用すれば、現在日時を今から n秒後, n分後, n時間後, n日後などずらして取得することができる。
static class LocalDateTimeOffset {
public static LocalDateTime now() {
Clock clock = Clock.offset(Clock.systemDefaultZone(), Duration.ofSeconds(60));
return LocalDateTime.now(clock);
}
}
public static void main(String[] args) {
System.out.println(LocalDateTime.now()); // 2020-03-02T23:36:50.052898
System.out.println(LocalDateTimeOffset.now()); // 2020-03-02T23:37:50.053739
}
現在日時を固定する
時間をずらすのではなく常に同じ日時をさしてほしい用途の場合にはClock.fixed
が使える。
static class LocalDateTimeFixed {
public static LocalDateTime now() {
Clock clock = Clock.fixed(Instant.parse("2020-01-01T01:00:00.00Z"), ZoneId.systemDefault());
return LocalDateTime.now(clock);
}
}
public static void main(String[] args) {
LocalDateTime now = LocalDateTimeFixed.now();
System.out.println(now); // 2020-01-01T10:00
}
プログラム全体で日本時間だけ扱っているとしても、Clock.fixed
を使う場合はUTC時間に頭の中で変換してから指定したい日時を設定しなければならないため、ちょっとめんどくさい。タイムゾーンを気にせず指定日時を設定するには工夫がいる。
タイムゾーンを気にせず現在日時を固定する
LocalDateTime
にはもともとタイムゾーンの概念がないので、Instant
にパースさせるのではなくLocalDateTime
にパースさせればタイムゾーンを気にしないで現在日時が固定できる。
static class LocalDateTimeFixed {
public static LocalDateTime now() {
LocalDateTime localDateTime = LocalDateTime.parse("2020-01-01T10:00:00");
Instant instant = localDateTime.toInstant(OffsetDateTime.now().getOffset());
Clock clock = Clock.fixed(instant, ZoneId.systemDefault());
return LocalDateTime.now(clock);
}
}
public static void main(String[] args) {
LocalDateTime now = LocalDateTimeFixed.now();
System.out.println(now); // 2020-01-01T10:00
}