MSSQL의 datetime 타입은 밀리초 단위로 정밀하게 저장되지 않는다.
datetime은 1초를 300단계로 나누는 방식(=약 3.33ms 단위)을 사용하기 때문에
0.003초, 0.007초 단위에서 반올림이 발생한다.

예를 들어 다음과 같은 경우:

입력값 실제 저장값
2025-10-28 23:59:59.996 그대로 저장
2025-10-28 23:59:59.997 반올림되어 2025-10-29 00:00:00.000 으로 저장

즉, 23:59:59.997 이후의 시각은 다음날 00:00:00 으로 반올림됩니다.
이 문제로 인해 날짜 범위 검색 시,
BETWEEN '2025-10-28 00:00:00' AND '2025-10-28 23:59:59.997'
처럼 작성해도 데이터가 누락되는 상황이 발생할 수 있습니다.


해결 방법

  1. datetime2 타입으로 변경
    • datetime2는 최대 100ns(나노초) 단위로 정밀하며, 반올림 문제가 없음.
    • 새 시스템이라면 무조건 datetime2 사용을 권장.
  2. 시간 보정 로직 추가
    • 기존 DB가 datetime이라면, 끝나는 시각을 1초 늘려 검색 범위를 안전하게 확보한다.
      LocalDateTime endDT = range.getEndDT().plusSeconds(1);
      

BETWEEN 대신 >= / < 조건을 썼을까?

<foreach collection="searchDto.startDTRanges" item="range" separator=" OR ">
    ("start_dt" >= #{range.startDT} AND "start_dt" < #{range.endDT})
</foreach>

SQL에서 날짜나 시간 범위를 조회할 때 많은 개발자들이 자연스럽게 BETWEEN을 사용한다.
하지만 실무에서는 경계값 중복 문제 때문에 BETWEEN 대신 >= / < 조합을 사용하는 것이 더 안전하다.

  1. BETWEEN은 양쪽 끝을 포함(inclusive) 한다
  2. 경계 포함 여부를 명시적으로 제어하기 위함
  3. MSSQL datetime 반올림 이슈와도 연결됨
  4. OR 조건과 함께 사용할 때도 안전
항목 BETWEEN >= / < 조합
포함 여부 양쪽 포함 (inclusive) 시작 포함 / 끝 미포함
날짜 경계 중복 발생 가능 없음
MSSQL datetime 반올림 대응 취약 안전
여러 Range OR 조건 시 중복 포함 위험 안정적
명확성 모호 (자동 포함) 명확 (의도 드러남)