게시판 리뉴얼을 하면서 datetime으로 있던 시간을 unixtimestamp를 써서 bigint로 관리하게 되었다. 관련된 내용을 정리해보려 한다.
Coordinated Universal Time, 전세계 표준 시간대
모든 타임존은 UTC를 기준으로 오프셋 +-시간으로 정의된다.
KST 한국 표준시는 UTC+9
서버, DB, API 등에서 절대적인 시간 기준으로 가장 많이 사용된다.
1970년 1월 1일 00:00:00 UTC를 기준으로 경과한 초를 정수로 표현한 값
항상 UTC 기준으로 타임존 개념이 없다.
상대적으로 변하지 않고 절대적인 값이라는 장점이 있다.
숫자형이라 연산과 비교가 매우 효율적이고 데이터 전송 시 용량이 적어 효율적이다.
다만 가독성이 안좋고, 32비트에는 2038년에 overflow 된다는 단점이 있다.
mariadb 기준 from_unixtime()으로 이 값을 datetime으로 변환 가능하다.
MySQL 기준 비교
TIMESTAMP
내부적으로 UTC 기준으로 저장되어 일관성이 유지되고, 조회 시 세션이나 서버의 타임존에 따라 변환되어 보여진다.
따라서 사용자의 위치에 따라 시간이 다르게 보여야할 때 사용한다.
4바이트 기준 2038년에 overflow된다.
DATETIME
입력된 값을 그대로 저장해 타임존 변환 없이 항상 동일한 값으로 조회된다.
즉, 타임존이 바뀌어도 항상 동일한 시간을 보장한다.
TIMESTAMP는 DB 서버/세션 타임존에 따라 조회 시 변환이 일어나 혼란을 줄 수 있다.
DATETIME은 입력된 값을 그대로 저장하지만, 그 값이 어떤 타임존 기준인지 명시적이지 않으면 오해의 소지가 있다.
BIGINT로 저장한 Unix Timestamp는 어떤 환경에서 조회하든 절대적인 값은 변하지 않아 매우 일관적이다.
정수형이라 시간 간격 계산과 비교, 정렬이 효율적이다.
시간 변환 로직이 DB가 아니라 애플리케이션 계층에 있기 때문에 개발자가 세밀하게 제어할 수 있다.
다만 가독성이 심히 좋지 않고, FROM_UNIXTIME() 같은 함수를 써야해 쿼리가 길고 복잡해질 수 있다. DB의 NOW(), DATE_ADD() 같은 날짜 관련 함수를 쓰기 힘들다.
날짜에 대한 유효성 검증(2월 31일 같은)을 하기 힘들다.
import datetime
import time
# Unix Timestamp (초) time.time()은 float으로 반환한다.
not_ts = int(time.time())
# 로컬 DateTime
local_datetime = datetime.datetime.now()
# UTC DateTime
utc_datetime = datetime.datetime.utcnow()
// Unix Timestamp (초)
const unixTimestampSec = Math.floor(Date.now() / 1000);
// 로컬 DateTime
const localDateTime = new Date();
// UTC DateTime
const utcDateTime = new Date().toUTCString();
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
// Unix Timestamp (초)
long unixTimestampSec = Instant.now().getEpochSecond();
// 로컬 DateTime
LocalDateTime localDateTime = LocalDateTime.now();
// UTC DateTime
Instant utcInstant = Instant.now();