Spring Boot에서 Java8 java.time 패키지(LocalDateTime, ZonedDateTime) 사용

이전의 Spring 환경에서는 시간을 다루는 클래스를 가지고 데이터베이스에 매핑해 사용할 때 문자열로 치환해서 사용하거나 Joda Time을 사용해 TypeHandler로 연결하였으나 최신의 Spring Boot는 java.time 패키지에 대한 내장 핸들러를 지원하므로 최대한 간단한 구현구조를 이루는데 집중해 해당 내용을 살펴본다.

통상적으로 국제적인 처리를 목적으로 하는 경우 mysql 서버는 UTC기준으로 세팅하고 datetime을 UTC 기준으로 사용하므로 여기에서는 웹서버의 Timezone을 UTC로 하는지 아니면 KST로 하는지에 집중해서 살펴본다.

아래의 내용을 살펴보기 이전에 미리 알아봐야 할 사항을 간단히 정리한다.

  • 최신의 Spring Boot는 java.time패키지에 대해서 TypeHandler를 지원하므로 별도의 Mybatis에 대한 TypeHandler가 필요하지 않다.
  • LocalDateTime 및 ZonedDateTime은 모두 @JsonFormat으로 원하는대로 포맷팅이 가능하다. 
  • LocalDateTime은 timezone에 대한 offset 정보가 없기 때문에 서버의 timezone 설정에 따라간다

아래의 표는 클라이언트에서 웹서버로 웹서버에서 DB로 DB에서 웹서버를 거쳐 클라이언트로 가는 과정에서 값이 어떻게 세팅되는지 확인하는 표이다.

LocalDateTime

입력 문자열
서버바인딩(UTC)
서버바인딩(KST)
DB저장(UTC)
DB저장(KST)
DB에 가져와서 Response출력(UTC)
DB에 가져와서 Response출력(KST)
2020-02-02T20:20:202020-02-02T20:20:202020-02-02T20:20:202020-02-02 20:20:202020-02-02 11:20:202020-02-02T20:20:202020-02-02T20:20:20
  • LocalDateTime은 별도의 timezone offset이 없으므로 클라이언트에서 보내는 시간이 서버의 timezone과 동일하다고 생각하고 값을 받아들인다.
  • 서버의 timezone과 DB의 timezone이 다른경우 해당 시간 만큼 offset을 적용하여 DB의 timezone 기준으로 DB에 저장된다.
  • DB저장과 동일하게 DB에서 값을 가져오는 경우에는 DB의 timezone과 서버의 timezone의 offset 만큼 변환하여 설정된다.

ZonedDateTime

입력 문자열
서버바인딩(UTC)
서버바인딩(KST)
DB저장(UTC)
DB저장(KST)
DB에 가져와서 Response출력(UTC)
DB에 가져와서 Response출력(KST)
2020-02-02T20:20:20+00:002020-02-02T20:20:20Z[UTC]2020-02-03T05:20:20+09:00[Asia/Seoul]2020-02-02 20:20:202020-02-02 20:20:202020-02-02T20:20:20Z2020-02-03T05:20:20+09:00
2020-02-02T20:20:20+09:002020-02-02T11:20:20Z[UTC]2020-02-02T20:20:20+09:00[Asia/Seoul]2020-02-02 11:20:202020-02-02 11:20:202020-02-02T11:20:20Z2020-02-02T20:20:20+09:00
  • ZonedDateTime은 timezone에 대한 offset이 있으므로 서버에도 동일한 형식으로 저장된다. 다만 서버의 timezone에 따라서 표시되는 표현만 달라진다.
  • DB에 저장될 때는 LocalDateTime과 동일하게 서버와 DB의 timezone 차이를 반영하여 UTC 기준으로 시간이 설정된다.
  • DB에서 값을 가져올때도 LocalDateTime과 동일하게 서버와 DB의 timezone 차이를 반영하여 UTC 기준으로 시간이 설정된다.

결론적으로 다음처럼 생각해 볼 수 있다.

  • 웹서버의 timezone을 UTC로 설정할 수 있고 Request, Response의 기준을 UTC로 할 수 있다면 웹서버, DB를 모두 UTC로 하고 LocalDateTime으로 하는게 일관성있고 편하다.
  • 클라이언트에서 Response값을 받아 변환할 수 없는 구조라면 ZonedDateTime을 쓰고 get 메서드에서 변환하는 등의 작업을 하는것이 좋다.
  • Joda Time이나 TypeHandler 없이도 일관성 있게 변환이 이루어지므로 Spring Boot에서 지원하는 구조를 사용하자.
  • 최신의 Spring Boot가 아닌경우 Java8 패키지에 대한 지원이 없을 수 있으므로 이 때는 Joda Time을 사용하기 보다 LocalDateTime, ZonedDateTime을 사용하고 TypeHandler로 JSR-310 구현체를 사용한다.(http://bluesky-devstudy.blogspot.com/2016/10/mybatis-java-8-typehandler.html)

위 작업에서 웹서버의 timezone을 설정하기위해 다음의 코드를 사용하였다.(정황상 config등에서 웹서버의 timezone을 지정하는 방법이 있을것 같다.)

@EnableScheduling
@SpringBootApplication
public class Application {
  public static void main(String[] args) {
    TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
    SpringApplication.run(Application.class, args);
  }
}

데이터 처리를 위한 Model 클래스에는 특별한 처리를 하지 않았으며 이에 대한 결과는 위 표와 같다. 필요에 따라서는 @JsonFormat으로 입/출력되는 포맷을 변경할 수 있다.

@Data
public class TimezoneTest {
  LocalDateTime localDateTime;
  ZonedDateTime zonedDateTime;
}

mybatis에도 별다른 처리 없이 DateTime type의 컬럼에 INSERT/SELECT를 실행하였다.

int insertTimezoneTest(TimezoneTest timezoneTest);
TimezoneTest selectTimezoneTest();
 
<insert id="insertTimezoneTest" parameterType="com.preludeb.model.TimezoneTest">
  INSERT INTO timezone_test
  (local_date_time, zoned_date_time)
  VALUES
  (#{localDateTime}, #{zonedDateTime})
</insert>
 
<select id="selectTimezoneTest" resultType="com.preludeb.model.TimezoneTest">
  SELECT * FROM timezone_test
  ORDER BY idx DESC
  LIMIT 0, 1
</select>

덧글

댓글 입력 영역