본문 바로가기
기타

MySQL DATE INTERVAL 함수 함정

by 초특급하품 2019. 12. 13.

MySQL은 날짜와 시간 연산을 지원하는 Date Function이 많이 있다. 그중에 날짜를 unit 단위로 더하고 빼는 DATE_ADDDATE_SUB 함수를 자주 사용했는데, 당연하다고 생각했던 로직에 문제가 있었다.

NOW()는 현재 시간을 반환하는 함수로 시간이 지날수록 증가할 텐데, NOW()에 임의의 값을 더한 시간은 그러지 않은 경우가 있다. 날짜 연산에 사용한 MONTH 단위가 문제였다.

 

DATE_ADD(NOW(), INTERVAL 1 MONTH)

 

NOW()가 증가하기 때문에 여기에 한 달을 더한 값도 당연히 증가할 거라 생각하고, 이에 기반한 로직이 있었는데 그렇지 않았다. 달이란 항상 일정한 상수가 아니라 현재 속한 월에 따라 개념이 달라지기 때문이다.


1월 15일에 한 달을 더하면 2월 15일이 되고, 2월 15일에 한 달을 더하면 3월 15일이 되는데 전자가 31일이 더해졌다면 후자는 그렇지 않다. 여기까지는 그래도 역행할 여지는 없어 보이지만 1월 마지막 날로 옮겨보면 더 큰 문제가 발생한다.

 

select
  DATE_ADD('2019-01-30 12:00:00', INTERVAL 1 MONTH),
  DATE_ADD('2019-01-31 11:00:00', INTERVAL 1 MONTH)

 

실행하면 다음과 같은 값이 나온다.

 

2019-02-28 12:00:00
2019-02-28 11:00:00

 

1월 31일 11시가 30일 12시보다 더 뒤임에도 불구하고 한 달을 더했더니 역행한다.

DATE_SUB도 마찬가지 문제가 발생할 수 있다.

 

select
  DATE_SUB('2019-03-30 12:00:00', INTERVAL 1 MONTH),
  DATE_SUB('2019-03-31 11:00:00', INTERVAL 1 MONTH)

 

별거 아닌 문법이지만 이로 인해 문제가 발생할 때 생기는 영향은 상상하기 무섭다. 매달 결제하는 정기결제 관리하는 부분도 깊숙이 살펴보면 굉장히 다양한 case 때문에 고려할게 많았는데 쿼리 하나에도 이런 문제가 발생할 줄 몰랐다. 이 경우는 한 달을 30일로 처리하기로 쉽게 우회했지만 의사소통 단계에서부터 명확히 하고 늘 고민하며 코딩해야 함을 또 느꼈다.

'기타' 카테고리의 다른 글

[bash] screen 사용 설명서  (0) 2019.12.26
간단한 파일 대칭키 암호화/복호화  (0) 2019.12.24
[bash] 간단한 부하테스트 script  (0) 2019.12.12
[bash] sed 사용 설명서  (0) 2019.12.01
[bash] awk 사용 설명서  (0) 2019.11.21

댓글