Spring Boot内の現在日時を変更する
2023-03-05T11:43:31+09:00
前提
プロジェクトをテストする中でどうしてもアプリ日時を変更したいときがあると思います。
アプリを起動するコンテナの日時を変更しても実現はできますが、HTTPS通信をする際にエラーが発生することがありました。そのためClockクラスを利用して日時変更をする方法を試したのでメモです。
コードサンプルはこちらです。
環境
- macOS: 12.6
- IntelliJ IDEA: 2022.2.3 (Community Edition)
- Gradle: 7.5
- Java: temurin 17.0.3
- Spring Boot: 2.7.10-SNAPSHOT
手順
プロジェクトの作成
spring initializrでプロジェクト作成
https://start.spring.io/でプロジェクトの雛形を作成します。
以下の画像のような構成にしています。
GENERATEボタンを押してダウンロードしてきます。それをIDEツールで開きます。
コントローラー作成
http://localhost:8080/api/datetime
にアクセスすることでレスポンスが返却されるAPIを作成しました。
LocalDateTime.now()
の代わりに今回作成するCustomLocalDateTime.customLocalDateTime()
等を使用しています。
@RestController
@RequestMapping("/api/datetime")
public class DatetimeController {
@Data
@Builder
public static class Response {
private LocalDateTime localDateTime;
private LocalDate localDate;
private LocalTime localTime;
}
@GetMapping
public Response getCurrentDatetime() {
return Response.builder()
.localDateTime(CustomLocalDateTime.customLocalDateTime())
.localDate(CustomLocalDateTime.customLocalDate())
.localTime(CustomLocalDateTime.customLocalTime())
.build();
}
}
ClockConfigクラス作成
Configクラスを作成します。
システム起動時にappilication.ymlから値を読み取り、時間指定されていればその時間を反映したClock、そうでなければシステム日時を反映したClockを返却します。
あらかじめZoneはAsia/Tokyo
を指定しておきます。
@Configuration
@Slf4j
public class ClockConfig {
@Value("${time-travel.specified-time}")
private String specifiedTime;
@Bean
public Clock clock() {
if(ObjectUtils.isEmpty(specifiedTime)) {
log.info("Using default clock");
return Clock.system(ZoneId.of("Asia/Tokyo"));
} else {
log.info("Using custom clock: {}", specifiedTime);
return Clock.fixed(Instant.parse(specifiedTime), ZoneId.of("Asia/Tokyo"));
}
}
}
applicaiton.ymlには以下の設定を追加します。
time-travel:
specified-time:
CustomLocalDateTimeクラス作成
beanとして用意したClockを各Component上でDIしてもいいのですが、管理が煩雑になります。そのため時間を管理するUtilクラスを作成して利用します。
staticであるUtilクラスにconfigをセットするため、setClockConfig
メソッドを用意しておきます。
public class CustomLocalDateTime {
private static ClockConfig clockConfig;
public static void setClockConfig(ClockConfig clockConfig) {
CustomLocalDateTime.clockConfig = clockConfig;
}
private CustomLocalDateTime() {}
public static LocalDateTime customLocalDateTime() {
return LocalDateTime.now(clockConfig.clock());
}
public static LocalDate customLocalDate() {
return LocalDate.now(clockConfig.clock());
}
public static LocalTime customLocalTime() {
return LocalTime.now(clockConfig.clock());
}
}
StaticContextInitializerクラス作成
staticであるUtilクラスにconfigをセットするため、アプリケーション起動時に動作するようStaticContextInitializerクラスを準備します。参考にしたのは以下のサイトです。
@Component
public class StaticContextInitializer {
@Autowired
private ClockConfig clockConfig;
@PostConstruct
public void init() {
CustomLocalDateTime.setClockConfig(clockConfig);
}
}
実行
日時を指定しない場合
applicaiton.ymlには以下の設定を追加します。
time-travel:
specified-time:
アプリケーションを起動します。
ログにはデフォルトのClockを使用するという内容が表示されます。
2023-03-05 11:34:07.851 INFO 9299 --- [ main] c.e.c.config.ClockConfig : Using default clock
http://localhost:8080/api/datetime
にアクセスします。
レスポンスには現在日時が表示されます。
{"localDateTime":"2023-03-05T11:35:16.674985","localDate":"2023-03-05","localTime":"11:35:16.675263"}
日時を指定する場合
applicaiton.ymlには以下の設定を追加します。
time-travel:
specified-time: 2025-01-01T12:00:00.000Z
アプリケーションを起動します。
ログには指定された日時のClockを使用するという内容が表示されます。
2023-03-05 11:38:07.522 INFO 9373 --- [ main] c.e.c.config.ClockConfig : Using custom clock: 2025-01-01T12:00:00.000Z
http://localhost:8080/api/datetime
にアクセスします。
レスポンスには指定された日時が表示されます。
注意が必要なのは、指定した時間はUTCで表示されるのはJSTとなる点です。こちらは各プロジェクト内で統一してください。変更する場合はClockConfigクラスのゾーンを変更してください。
{"localDateTime":"2025-01-01T21:00:00","localDate":"2025-01-01","localTime":"21:00:00"}
さいごに
アプリ内の日時を変更してテストすることが多いと思います。一つの例として参考にしていただけると幸いです。
他の方法があればぜひご共有ください!