Backend/Database

[Oracle] add_months()의 날짜 계산에 대한 고찰

mopil 2023. 6. 18. 13:03
반응형

회사에서 오라클 디비를 사용하는데, 날짜를 계산하는 비즈니스 로직이 대부분 오라클 내장함수인 add_months()함수를 통해서 이루어지고 있었다. 이 함수는 날짜를 정확하게 계산하지 못 하는 문제가 있었는데 이를 개선했던 경험을 공유하고자 한다.

 

# 계산 일이 말일일 경우 발생하는 오류

우선 비즈니스 요구사항이 6개월후를 의미하는 건, 정확히 응당일로 결과나 나와야 하는 것이였다. 

쉽게말해 2023.02.28 -> 6개월 후 -> 2023.08.28로 결과가 나와야 했다.

 

add_months()함수는 이 부분을 충족하지 못하고 있었는데, 

'yyyymmdd'포맷의 날짜의 6개월 후를 add_months()함수를 사용해서 나오는 결과를 살펴보자


1월 (31) → 7월 (31) 정상


2월 (28) → 8월 (28) 나와야하는데 8월 (31)

3월 (31) → 9월 (30) 정상


4월 (30) → 10월 (30) 나와야하는데 10월 (31)


5월 (31) → 11월 (30) 정상


6월 (30) → 12월 (30)이 나와야하는데 12월 (31)


7월 (31) → 1월 (31) 정상


8월 (31) → 2월 (28) 정상, 24 윤년(2월 29)도 잘 나옴


9월 (30) → 3월 (30) 나와야하는데 3월 (31)


10월 (31) → 4월 (30) 정상


11월 (30) → 5월 (30) 나와야하는데 5월 (31)


12월 (31) → 6월 (30) 정상

 

 

 

즉, 계산기준월 말일이 30일이고 계산결과월 말일이 30일이 아니면, 함수는 계산결과월 말일 (31)로 출력하고 있었다.

 

추가로 윤년이 포함된 응당일 계산도 정확하지 않았다.

2024-02-28이 나와야함

 

왜 이러는 걸까?

혹시라도 문자열을 그대로 사용해서 그런가 싶어서 to_date함수로 감싸봤지만, 똑같다.

찾아보니 그냥 오라클 add_months()함수의 특징이라 그렇다고 한다.

주어진 날짜가 말일이면, 결과도 말일로 출력한다고 한다.

 

GPT 설명 첨부

응당일 계산이 중요한 비즈니스 로직에서 이는 문제를 야기할 수 있었기 때문에 개선이 필요했다.

 

# interval 함수 활용?

오라클의 interval 함수를 활용하면 다음과 같이 작성할 수 있다.

이러면 응당일 계산이 정확하게 이루어진걸 볼 수 있다. 하지만...

 

윤년계산이 불가하다. (2025.02.29는 존재하지 않기 때문)

 

 

# 결론

결과적으로 add_months()를 사용하면 응당일이 문제고, interval을 사용하면 윤년이 문제다.

 

따라서 해당 날짜 계산 로직을 SQL에서 처리하는 것이 아닌, 어플리케이션 레벨에서 처리하도록 개선을 진행했다. (사실 애초부터 이러면 되었는데 비즈니스 로직이 SQL레벨에 있다보니 생각을 처음부터 갇히게 했던 것 같다.)

 

SQL에 비즈니스 로직이 녹아있는 레거시 코드의 불편함을 몸소 느낄 수 있었고, 데이터베이스 내장함수의 문제점(?)을 알 수 있었다.

반응형