본문 바로가기
프로그래밍/Spring Boot

LocalDateTime 사용 시 주의할 몇몇 오류사례

by 카프카뮈 2021. 10. 27.

오늘은 프로젝트를 진행하다가 당황스러운 실수를 해서, 블로그에 간단히 기록해보려고 한다.

요약하자면 다음과 같다.

  • LocalDateTime.MIN / LocalDateTime.MAX 값이 얼마인지 미리 알아두자
  • MySQLtimestamp의 범위를 미리 숙지하자

LocalDateTime의 MIN/MAX

전기차 충전소 정보 프로젝트를 진행하던 중, 문자열로 된 날짜/시간 정보를 받을 일이 생겼다.

전기차 충전기의 최근 충전 시간 정보였는데, LocalDateTime.parse로 파싱하다 보니 에러가 났다.

데이터...제발...관리좀 잘해주세요

알고 보니 공공 API의 해당 필드에 빈 값이 들어가는 경우가 존재했던 것이다.

찜찜하지만 그렇다고 API를 바꿀 수는 없으니...임시변통으로 다음과 같은 방법을 취했다.

(...)
if(Objects.isNull(dataTime) || dateTime.isBlank()) {
	// 만약 날짜 문자열이 null이거나 빈 값이면 적절히 작은 값을 던져준다.
    return LocalDateTime.MIN;
}

나는 이렇게 하면 대충 1970년 1월 1일이 들어가거나, 아니면 그와 비슷한 작은 값이 들어갈 줄 알았다.

이에 따른 결과는 아래와 같다.

값이 -999999999-01-01T00:00:00이 들어갔다!

이런 값은 당연히 저장 과정에서 오류가 날 수밖에 없고, 애초에 내가 의도한 값도 아니었다.

그래서 급하게 LocalDateTime JAVA 공식 문서를 확인해 봤다.

그렇다. LocalDateTime의 MIN과 MAX는, 엄청나게 극단적인 값이 들어간다.

해당 값은 특정한 상황에서 쓰는 매직 넘버가 아니다. 

추측하기에는 비교의 용도 등에서 쓸수는 있겠으나...애초에 어떻게 활용할 지 감이 잘 안온다.

교훈 1: 클래스의 상수 값을 활용할 때는 미리 문서를 읽어보자.


timestamp의 범위

일단 위의 에러를 확인한 뒤, 적절히 작은 값을 넣어서 해결했다.

이제 괜찮겠지 했는데, 돌려보니 또 오류가 났다.

이미지가 작은데, 간단히 정리하면 다음 상황이다.

  • 공공 API 관리자의 실수로, 2020년이 2080년으로 표기되었다.
  • 그런데 2080년도 엄연히 시간인데, 갑자기 jdbc에서 예외를 발생시켰다.

잘못된 데이터니까 고쳐야 하는 건 이해가 가는데, 왜 예외가 발생했을까?

나는 로컬에서 MySQL을 사용하고 있으므로, 관련 공식 문서를 찾아보았다.

 

MySQL :: MySQL 8.0 Reference Manual :: 11.2.2 The DATE, DATETIME, and TIMESTAMP Types

11.2.2 The DATE, DATETIME, and TIMESTAMP Types The DATE, DATETIME, and TIMESTAMP types are related. This section describes their characteristics, how they are similar, and how they differ. MySQL recognizes DATE, DATETIME, and TIMESTAMP values in several f

dev.mysql.com

공식 문서에는 다음과 같은 문구가 있었다.

the range for DATETIME values is '1000-01-01 00:00:00.000000' to '9999-12-31 23:59:59.999999'
and the range for TIMESTAMP values is '1970-01-01 00:00:01.000000' to '2038-01-19 03:14:07.999999'

timestamp로 시간을 저장할 경우, 4바이트의 공간을 사용하므로 사이즈의 제약이 발생한다.

그러한 탓에, 2038년까지밖에 저장이 되지 않았던 것이다. 

이에 대해서 더 궁금하면, 나무위키의 2038년 문제 문서를 추천한다.

 

만약 도메인상의 이유로 정말 2038년 이후 시간값을 넣어야 한다면, datetime을 활용해야 한다.

물론 내 서비스는 그럴 필요가 없었으므로, 이에 대한 자잘한 예외처리를 추가했다.


액운이 끼었는지 아니면 숙련도가 부족한 건지, 연달아 에러가 나서 정신이 없었다.

그래도 미리 겪는 게 훨씬 낫다 싶다. 이참에 포스팅도 하고 트러블슈팅 경험도 쌓고...

비슷한 에러를 겪는 분이라면, 이 글을 보고 빠르게 해결하시길 기원한다.

 

잘못된 내용이 있다면 댓글 부탁드립니다.

반응형

댓글