Timestamp 와 Datetime

Timestamp와 Datetime 이슈

TimestampDatetime의 가장 큰 차이점은 timezone의 정보의 유무이다.

우리 팀이 구현한 API 서버의 로직은 Java 코드에서 LocalDateTime.now()를 호출하여 API 서버 컴퓨터의 timezone의 시간 정보를 이용하여 LocalDateTime 객체를 생성하고, timestamp 타입의 created_at 컬럼에 데이터를 넣는 방식으로 구현되어 있다.

AWS에 API 서버를 배포하고 테스트하니, created_at에 데이터가 기대했던 값과 달리 -9시간으로 처리되어 보이는 문제가 발생했다.

이는 AWS에 만든 인스턴스의 기본 timezone 환경 변수가 UTC 로 설정되어 있었기 때문이다.

ubuntutimezone 설정을 여러가지 방법으로 바꿔보고, terminal창에서 date 명령어를 입력하여 KST로 변경된 것을 확인하고, 계속 시도해 보았으나 해결에 어려움을 겪었다.

정규 시간이 끝나고 테스트 하며 알아보니, timezone 변수를 수정했던 작업들이 ubuntu OS상에서 표시 되는 설정만 건드렸을 뿐, 실제 java 코드가 사용하는 시스템 환경변수는 변경되지 않았던 것이 문제 였던 것 같다.

Java 코드에서 LocalDateTime은 해당 실행 환경 컴퓨터의 timezone 설정을 따라가는데, timezone 설정을 KST로 변경했지만, Java가 바라보는 timezone 설정은 계속 UTC로 되어 있어, Java 단에서 잘못 된 시간으로 쿼리문이 만들어졌던 것이다.

## 테스트 과정..

우선 위와 같이 테스트용 java 코드를 만들고, ubuntu 서버의 timezone 환경 변수를 변경하며 테스트를 진행했다.

1. tzselect 설정 방법

$ sudo tzselect

Asia/Seoul로 변경 했음에도 java가 바라보는 timezoneUTC인 것을 확인할 수 있다.

하지만 date 명령어를 입력하면?

KST 시간으로 나오고 있다. 이 때문에 환경 변수가 제대로 변경 되었다고 착각하게 되었고, 어려움을 겪었다.

2. ln -sf /usr/share/zoneinfo/Asia/Seoul /etc/localtime 설정 방법

$ sudo ln -sf /usr/share/zoneinfo/Asia/Seoul /etc/localtime

마찬가지로, java는 아직 UTC로 인식하고 있다.

3. timedatectl set-timezone 'Asia/Seoul' 설정 방법

$ sudo timedatectl set-timezone 'Asia/Seoul'


생각이 꼬여 어려웠던 부분

며칠 전 TimestampDatetime의 차이에 대해서 학습할 때, 가장 큰 차이는 timezone의 반영유무 이다. 라는 말을, timestamp는 저장되는 data 자체에 timezone의 정보가 들어있는 것이라 생각을 하고 테스트를 진행하다가 안맞는 부분들이 너무 많아서 한참을 헤맸다. 이는 틀린 생각 이였고,

DB는 단순히 timestamp 타입의 컬럼 데이터를 저장할 땐, 쿼리로 들어온 문자열 값을 UTC형태로 변환하여 저장하고, 읽어들일 땐 저장된 UTC형태의 데이터에 호출 시점의 DB timezone 시간을 반영하여 반환하는 작업을 할 뿐이다.

그렇기 때문에 테이블 하나에 전 세계 사람들의 게시글 data와 작성 된 시간을 저장해놓고, 나라마다 알맞은 시간으로 보일 수 있게끔 반환 한다는 건 timestamp 컬럼 하나 만으로는 불가능한 일 이였다.


생각해 본 예제, timestamp를 적용하여 만들 수 있는 서비스

  • DB는 1개로 두고, timezone 설정은 UTC 로 설정한다.

  • 테이블을 나라별로 구분하여, 한국에서 쓴 글을 모아둔 테이블, 미국에서 쓴 글을 모아둔 테이블 ... 형태로 만들어 각 나라에서 글을 작성한 시간을 저장해둔다.

서버에서 DB로 연결할 때 각각의 연결마다 별도의 timezone을 설정하면 테이블에 저장되어 있는 글 작성 시간을 각 나라에 맞는 시간으로 제공할 수 있을 것이다.

결국 우리가 신경써야 할 점은, 쿼리문을 전달하여 timestamp 컬럼에 데이터를 넣을 때, 시간을 '2022-04-12 22:15:00'의 형태로 만들어진 것을 넣어주느냐, 아니면 쿼리문에서 now()를 호출하여 DB 서버 자체에 설정 된 timezone을 이용하여 시간을 넣어줄 것이냐만 신경쓰면 된다.

전자의 경우, java 단에서 각 나라별 timezone에 맞는 현재 시간을 생성하여 쿼리문에 넣어주기만 하면 깔끔하게 처리가 가능하다.

후자의 경우 now()를 사용하게 되면, DB 서버의 timezone 설정을 신경써서 시차에 맞게끔 쿼리문에 들어갈 시간 오차를 넣어주는 처리를 추가 해야함을 신경써야 한다. 아래와 같은 형태처럼 말이다.

insert into task (..., created_at) values (... ,CONVERT_TZ(now(),'+00:00','+09:00'));

결국 글로벌로 제공해야 하는 서비스를 만들 때 timestamp 형식을 채택한다면

좋은 웹페이지 즐겨찾기