-
[PostgreSQL] Date/Time TypesCS지식/데이터베이스 2022. 8. 6. 11:59
오늘은 회사 내에서 사용 중인 RDBMS, 그 중에서 PostgreSQL에서 제공하는 Date/Time Type들에 대해 정리해보려고 한다.
1. Date/Time Type 종류
PostgreSQL에서는 아래와 같이 6개의 타입을 제공한다.
여기서 p는 seconds(초)를 표현할 때에 소수점아래로 어디까지 표현할 것인가를 의미한다.
0~6까지의 값을 가질 수 있다.
그리고 interval에 보면 fields라는 값을 받는데 여기서 fields와 p 둘 다 명시하면 fields는 무조건 second를 포함한 값여야만 한다.
<fields에 명시할 수 있는 값>
YEAR, MONTH, DAY, HOUR, MINUTE, SECOND, YEAR TO MONTH, DAY TO HOUR, DAY TO MINUTE,
DAY TO SECOND, HOUR TO MINUTE, HOUR TO SECOND, MINUTE TO SECOND2. Date/Time input
PostgreSql에서는 input값으로 거의 대부분의 포맷을 받을 수 있다. (ISO 8601, SQL-compatible, traditional POSTGRES 등등...)
몇몇의 포맷들에는 년, 월, 일의 순서가 애매모호할 수 있기때문에 이상적인 순서를 제시하고 있다.
PostgreSQL의 장점은 유연하게 Date/Time을 핸들링하는 것인데 정확한 파싱을 통해 인풋을 인식하고 months, days of the week, time zones을 포함한 텍스트 필드를 인식한다.
주의해야할 점은 Date/Time input은 single quotes(작은 따옴표)로 묶여서 입력되야한다는 것이다.
input 예시들은 아래와 같다.
3. Date/Time output
date/time의 outputds ISO 8601, SQL (Ingres), traditional POSTGRES (Unix date format), or German 중 하나로 표현된다.
기본으로 ISO format을 사용한다.
위 4가지 스타일은 아래와 같다.
[번외] 왜 이 글을 정리하게 되었는가?
이번에 회사에서 제공 중인 기능 중에 고객들에게 메시지를 예약된 시간에 전송하는 기능에 시차를 적용하는 개발을 담당하게 됐다.
현재는 Asia/Seoul시간대로만 동작하고 있었고 회사가 점점 성장하면서 해외 end-user도 고려해야하기에 시차 적용이 필요한 시기가 왔다.
예를 들어, 발신자가 오후 8시에 메시지를 보내고 싶은데 오후 8시가 발신자 시간대로 보내고 싶을 수도 있고 메시지를 받는 유저의 시간대로 보내고 싶을 수 있기 때문이다.
그리고 현재는 한국, 일본이 주요 고객사여서 Asia/Seoul시간대로 동작해도 문제가 없지만 미국 진출도 계획 중이기에 시차 적용은 필수적이였다.
시차 적용이라는 문제를 해결하기 위해 로직을 구상해봤다.
일단은 현재 예약 전송 시간은 Instant타입(java)으로 가지고 있고 이는 timestamp이다.
(timestamp는 UTC기준 1970년 01월 01일으로부터 얼마의 시간이 지났는지를 milliseconds로 저장하고 있는 값)
java에서는 ZonedDateTime이라는 timeZoneOffset이 적용된 값을 가질 수 있는 클래스를 제공 중이였고 ZonedDateTime클래스에는 ZoneId만 알고 있다면 Instant를 ZonedDateTime으로 converting해주는 메서드도 제공 중이였다.
'쉽게 문제를 해결할 수 있겠구나!'라고 생각을 했지만 시간차이를 구하는 것에서 막혔다.
현재 시간과 예약 전송 시간의 차이를 구하기 위해 Duration.between()을 사용할 수 있고 나는 파라미터로 Instant.now()와 ZonedDateTime(타임존offset이 적용된 예약 전송 시간을 넣어주었다.
하지만, 예상한 시간 차이가 나오지 않았고 디버깅을 했다.
문제는 between()메서드 내부에 시간 차이를 구하는 until이라는 추상메서드가 존재했고 이 추상메서드는 java에서 제공 중인 date와 관련된 모든 클래스에서 구현을 하고 있다.
문제원인이 until메서드를 구현하고 있는 것이 아니라 Instant와 ZoneDatetime을 파라미터로 넣어주면 Instant에서 구현한 until이 동작하는 것이다.
Instant클래스에서 제공 중인 until을 보면 아래와 같다.
첫 번째 arg인 endExclsive는 ZoneDateTime이였고 이를 Instant.from(endExclusive)을 걸쳐 Instant로 변환, 즉 시차적용 전의 date로 돌아가는 것이다.
첫 번째 해결방안, Instant타입을 ZoedDateTime으로 변환하여 계산해주기는 실패로 남았다.
두 번째 해결방안으로 그러면 Instant.now()도 ZoneDateTime으로 바꿔서 Duration.between()의 파라미터로 ZoneDateTime, ZoneDateTime으로 넣어주면 되지 않나?라고 생각했다.
역시나 문제는 해결되지 않았다.
이유는 timeZone이 서로 다른 ZoneDateTime일 경우에는 서로 timeZone을 맞추는 작업을 거친다.
즉, 미국 발신자가 한국 유저의 시간대로 예약 전송을 하고 싶다해도 이 로직을 사용하면 안된다는 것이다.
세 번째 해결방안으로 직접 offset을 구해서 더해주는 방안을 생각했다.
현재는 Asia/Seoul시간대를 기준으로 동작을 한다.
만약에 미국시간대 기준으로 동작하도록 하게 하고 싶다면 기존에 Asia/Seoul시간대로 계산된 시간차이에 offset을 더해주기만 하면된다.
테스트코드 작성과 로컬테스트를 통해 원하는 방식으로 동작하는 것을 확인했고 PR을 올렸다.
하지만, 리뷰과정 중에 셀장님이 이 방안이 지속가능한 코드인지 유지보수하기 쉬운 코드인지에 대한 의문이 든다고 하셨고 그 전에 PostgreSQL에서 제공 중인 Date/Time Types에 대해 더 자세히 알아보고 다시 로직을 설계해달라고 하셨다.
PostgreSQL에서 제공 중인 Date/Time Types를 알아보면서 추가적으로 두 가지 방안이 더 떠올랐다.
원하는 동작을 위한 코드 작성은 많은 방법으로 작성을 할 수 있지만 가장 중요한 것은 지금 당장의 문제 해결(원하는 동작이 되도록 함)보다는 유지보수가 쉬운, 다른 사람들이 납들할만한 논리적인 이유 그리고 지속가능한 코드가 중요하다고 생각한다.
[참고자료]
https://www.postgresql.org/docs/current/datatype-datetime.html
'CS지식 > 데이터베이스' 카테고리의 다른 글
MySQL 새로 알게 된 쿼리 (0) 2021.12.21 기초가 튼튼한 데이터베이스(저자 이종만) 후기 (0) 2021.06.22 OLAP란 무엇인가? (기초가 튼튼한 데이터베이스 완독!!) (0) 2021.06.22 데이터 웨어하우스란 무엇인가 (0) 2021.06.19 트랜잭션이란 무엇인가? (0) 2021.06.16