상황
글로벌 서비스 준비중인데, 모든 시간을 KST 로 작업하고 있었다는..
그래서 모두 UTC 기준으로 변경을 하고 싶어서 프로그래머들끼리 가볍게 이야기를 나눠봤다.
여기서 전제조건!
1. 퍼블리셔는 OS 시간을 변경해줄 수 없음
2. 기존 Code 의 변경은 최소화 (로직을 변경하면서 버그를 만들 수 있는 상황이 아님)
우선, 기준이 되는 UTC 를 사용하려면, DB 에서 쓰고있던 Procedure base logic 들도
CURRENT_TIMESTAMP() -> UTC_TIMESTAMP() 로 변경 (1) 이 필요했고,
Java Code 에서 Calendar, Date, Timestamp 를 쓰는 코드를 모두 점검 (2) 해야 했다.
(1) 은 replace 가 용이한 상황이어서 난이도 하하하
(2) 는 일일이 봐야해서 난이도가 높다고 생각했지만 생각보다 코드가 많지 않아서 중하하
라고 판단함
수정 감행
시간이 그리 많지 않아서 신속하게 결정하고, 아래와 같이 진행했다.
1. TimeZone 기반으로 Calendar 를 하나의 함수를 통해 얻어오도록 수정
기존에는 Calendar.getInstance() 를 여기저기서 호출했는데,
특정 날짜관련 클래스를 하나 만들고 거기서 getNow() 를 통해 Calendar 를 얻어가도록 수정
2. DB 의 모든 CURRENT_TIMESTAMP() 를 UTC_TIMESTAMP() 로 수정
기존에는 CURRENT_TIMESTAMP() 를 사용하고 있어서
MySQL 의 서버 시간 설정에 의한 시간값을 얻어가고 있었는데
UTC_TIMESTAMP() 를 이용함으로써, 서버 시간설정에 영향을 받지 않도록 수정
그 후, 원하는대로 값이 저장되는지 확인해봤다.
그런데, 좀 이상했다..
분명, WAS Code 에서 2015-07-01 00:00:00 을 얻었는데,
DB 에 2015-07-01 09:00:00 이 저장됨
그리고 WAS Code 에서 그 값을 읽어서 클라이언트로 전달하면서
클라이언트는 그 시간이 UTC 라고 믿고 기기가 KST 를 표시해야 하니, +09:00 를 추가로 함 -_-
서버가 클라로 줘야하는 시간이 UTC 로 약속되어있기 때문에,
서버에서 DB 의 값을 읽을 때 UTC 로 변환해야할 필요가 있는것 처럼 느껴졌었는데,
Calendar 를 얻어가는 함수 내부에서 TimeZone 을 UTC 로 설정하고 있기 때문에
코드상의 문제는 아닌것 같았고, 좀더 debugging 해서 결국 문제점을 찾았다.
핵심 문제
핵심 문제는 Timestamp 를 사용해서 DB 쪽으로 인자를 전달하는 과정에서
Timestamp 값이 Calendar의 TimeZone 에 의해 변경되지 않고
JVM의 TimeZone 에 의해 결정된 시간으로 저장되는 것을 몰랐던 것이 문제였다.
깊이 몰랐던 것이 문제여서, 이번 기회에 정리를 해두려고 한다.
Calendar 의 속성
Calendar 는 setTimeZone 에 의해 설정된대로 충실히 동작한다.
예를 들어, 2015-07-01 00:00:00 KST 인 값도 TimeZone 만 변경하면
get(Calendar.HOUR_OF_DAY) 를 했을때 설정된 TimeZone 에 의한 값을 return 한다.
set(Calendar.HOUR_OF_DAY, hour) 도, 내부적으로 설정된 TimeZone 에 의한 시간으로 set 한다.
그래서 현재 Calendar 가 무슨 TimeZone 을 갖는지 확인하고,
비교하는 데이터가 동일한 TimeZone 의 값인지 조심해야 한다.
Date 의 속성
Date 는 TimeZone 과 Independent 하다.
Calendar.getInstance().getTime() 의 Date 는, 내부적으로 fastTime 을 갖고 있고,
이 값이 TimeZone 에 의해 해석되는 형식이다.
여담인데, CallableStatement 의 인자를 setDate 로 넘기면, 날짜만 넘긴다.. -_-
MySQL 의 속성
MySQL 에도 TimeZone 이 엄연히 존재하지만,
JDBC 의 setTimestamp 를 통해 전달된 인자를 변경 없이 충실히 저장해주기 때문에
MySQL 내부에서 UTC_TIMESTAMP() 를 사용하면, 사실상 TimeZone Independent 한 작업을 할 수 있을 것 같다.
결론
여하한 이유로 OS 의 시간을 변경할 수 없다면,
JVM 에서 UTC 를 사용하고, MySQL 에서 UTC_TIMESTAMP() 를 사용하는게 좋은 것 같다.
만약, JVM 에서 UTC 를 설정하기조차 할 수 없었다면,
너무 슬펐을 것 같다. -_-
마지막으로, Tomcat6 에서 TimeZone 설정 변경법
/etc/tomcat6/tomcat6.conf
...
# Cannot resolve user database reference - naming-factory-dbcp # the real problem is a cnfe that is avoided by configuring # the -Djavax.sql.DataSource.Factory. This fixes the rpm install. JAVA_OPTS="${JAVA_OPTS} -Djavax.sql.DataSource.Factory=org.apache.commons.dbcp.BasicDataSourceFactory -Duser.timezone=GMT”
...
|