Oracle ORA-01849 오류 원인과 해결 방법 완벽 가이드

ORA-01849
2026년 08월 04일 | DBMS Error 가이드

이 글에서 다루는 내용

ORA-01849 에러의 원인 분석, 해결 SQL, 예방 방법을 실무 관점에서 정리합니다.

ORA-01849 hour must be between 0 and 23 는?

ORA-01849는 날짜 또는 타임스탬프 값을 변환하거나 입력할 때 시간(hour) 값이 유효한 범위인 0~23을 벗어났을 때 발생하는 에러입니다. Oracle은 24시간제를 기준으로 시간 값을 처리하므로, 24 이상의 값이 입력되면 즉시 이 에러를 반환합니다. 주로 TO_DATE, TO_TIMESTAMP 함수를 사용하거나 날짜 리터럴을 직접 삽입할 때 빈번하게 발생합니다.


주요 발생 원인

1. TO_DATE / TO_TIMESTAMP 함수에 잘못된 시간 값 입력

가장 흔한 원인으로, 문자열을 날짜로 변환할 때 시간 부분에 24~99 사이의 값이 포함된 경우 발생합니다. 예를 들어 외부 시스템으로부터 받은 데이터에 ‘2024-01-15 25:30:00’과 같이 잘못된 시간 값이 포함되어 있을 때 이 에러가 트리거됩니다. 배치 작업이나 ETL 파이프라인에서 데이터 정제 없이 그대로 Oracle에 넣으려 할 때 특히 자주 발생합니다.

2. 잘못된 날짜 포맷 마스크 사용 (HH vs HH24)

Oracle의 날짜 포맷에서 HH는 12시간제(1~12), HH24는 24시간제(0~23)를 의미합니다. 개발자가 오후 시간(예: 15시)을 입력하면서 HH 포맷을 사용하면 13~23 범위의 값이 12시간제를 초과하여 에러가 발생합니다. 반대로 HH24 포맷을 써야 할 자리에 HH를 잘못 사용하면 이 에러로 이어집니다.

3. 애플리케이션 또는 인터페이스에서 잘못된 시간 데이터 전달

Java, Python 등 외부 애플리케이션에서 PreparedStatement나 바인드 변수를 통해 날짜 값을 넘길 때, 시간대(timezone) 변환 오류나 로직 버그로 인해 유효하지 않은 시간이 전달될 수 있습니다. 특히 자정(midnight) 처리 로직에서 24:00:00을 다음 날 00:00:00으로 변환하지 않고 그대로 넘기는 경우가 대표적입니다. 이 경우 에러 메시지만 보고는 원인을 찾기 어려우므로 애플리케이션 로그와 함께 확인이 필요합니다.


해결 방법

원인 1 해결: 잘못된 시간 값 수정

입력 데이터 자체에 문제가 있는 경우, 먼저 해당 데이터를 확인하고 수정해야 합니다.

-- 에러 발생 예시
SELECT TO_DATE('2024-01-15 25:30:00', 'YYYY-MM-DD HH24:MI:SS') FROM DUAL;
-- ORA-01849: hour must be between 0 and 23

-- 해결: 올바른 시간 값으로 수정
SELECT TO_DATE('2024-01-15 23:30:00', 'YYYY-MM-DD HH24:MI:SS') FROM DUAL;

-- 배치/ETL 환경에서 비정상 데이터 사전 필터링
SELECT raw_datetime
FROM staging_table
WHERE REGEXP_LIKE(raw_datetime, '^\d{4}-\d{2}-\d{2} (2[4-9]|[3-9]\d):\d{2}:\d{2}$');
-- 위 쿼리로 24시 이상의 시간 데이터를 사전에 식별

-- CASE 문으로 24:00:00을 다음날 00:00:00으로 자동 변환
SELECT 
  CASE 
    WHEN SUBSTR(raw_datetime, 12, 2) = '24' 
    THEN TO_DATE(SUBSTR(raw_datetime, 1, 10), 'YYYY-MM-DD') + 1
    ELSE TO_DATE(raw_datetime, 'YYYY-MM-DD HH24:MI:SS')
  END AS corrected_datetime
FROM staging_table;

원인 2 해결: 포맷 마스크 수정 (HH → HH24)

-- 에러 발생 예시: HH 포맷으로 13시 이상 입력
SELECT TO_DATE('2024-01-15 15:30:00', 'YYYY-MM-DD HH:MI:SS') FROM DUAL;
-- ORA-01849 발생

-- 해결 방법 1: HH24 포맷 사용 (24시간제)
SELECT TO_DATE('2024-01-15 15:30:00', 'YYYY-MM-DD HH24:MI:SS') FROM DUAL;

-- 해결 방법 2: 12시간제 유지 시 AM/PM 명시
SELECT TO_DATE('2024-01-15 03:30:00 PM', 'YYYY-MM-DD HH:MI:SS AM') FROM DUAL;

-- TO_TIMESTAMP에서도 동일하게 적용
SELECT TO_TIMESTAMP('2024-01-15 15:30:00.000000', 'YYYY-MM-DD HH24:MI:SS.FF') FROM DUAL;

-- 현재 세션의 NLS_DATE_FORMAT 확인
SELECT VALUE FROM NLS_SESSION_PARAMETERS WHERE PARAMETER = 'NLS_DATE_FORMAT';

-- 세션 레벨에서 안전한 포맷으로 변경
ALTER SESSION SET NLS_DATE_FORMAT = 'YYYY-MM-DD HH24:MI:SS';

원인 3 해결: 애플리케이션 레벨 데이터 검증

-- 테이블에 CHECK 제약 조건 추가로 잘못된 데이터 원천 차단
ALTER TABLE orders 
ADD CONSTRAINT chk_order_time 
CHECK (order_time >= TO_DATE('00:00:00','HH24:MI:SS') 
       AND order_time < TO_DATE('23:59:59','HH24:MI:SS'));

-- PL/SQL에서 예외 처리로 에러 포착 및 로깅
DECLARE
  v_date DATE;
  v_raw_str VARCHAR2(30) := '2024-01-15 25:00:00';
BEGIN
  BEGIN
    v_date := TO_DATE(v_raw_str, 'YYYY-MM-DD HH24:MI:SS');
  EXCEPTION
    WHEN OTHERS THEN
      IF SQLCODE = -1849 THEN
        DBMS_OUTPUT.PUT_LINE('잘못된 시간 값 감지: ' || v_raw_str);
        -- 에러 로그 테이블에 기록
        INSERT INTO error_log (error_code, error_msg, raw_data, log_time)
        VALUES (SQLCODE, SQLERRM, v_raw_str, SYSDATE);
        COMMIT;
      ELSE
        RAISE;
      END IF;
  END;
END;
/

-- 대량 데이터 처리 시 유효성 검사 함수 활용
CREATE OR REPLACE FUNCTION is_valid_datetime(p_str IN VARCHAR2, p_fmt IN VARCHAR2)
RETURN NUMBER IS
  v_date DATE;
BEGIN
  v_date := TO_DATE(p_str, p_fmt);
  RETURN 1; -- 유효
EXCEPTION
  WHEN OTHERS THEN
    RETURN 0; -- 무효
END;
/

-- 사용 예시: 유효한 날짜만 처리
SELECT raw_datetime
FROM staging_table
WHERE is_valid_datetime(raw_datetime, 'YYYY-MM-DD HH24:MI:SS') = 1;

예방 방법

1. 날짜 포맷 표준화 및 코딩 컨벤션 수립

프로젝트 전체에서 날짜 관련 포맷을 YYYY-MM-DD HH24:MI:SS로 통일하고, 이를 개발 가이드라인에 명문화해야 합니다. DDL 작성 시 컬럼의 기본값 설정, 뷰 정의, 프로시저 내부의 날짜 변환에도 일관되게 HH24 포맷을 사용하도록 팀 전체가 공유해야 합니다. 코드 리뷰 단계에서 HH 포맷 단독 사용 여부를 체크리스트에 포함시키면 사전 예방 효과가 큽니다.

-- 세션/시스템 레벨에서 안전한 NLS 설정 (DBA 권한 필요)
ALTER SYSTEM SET NLS_DATE_FORMAT = 'YYYY-MM-DD HH24:MI:SS' SCOPE=SPFILE;

-- 또는 로그인 트리거로 세션 자동 설정
CREATE OR REPLACE TRIGGER set_nls_on_logon
AFTER LOGON ON DATABASE
BEGIN
  EXECUTE IMMEDIATE 'ALTER SESSION SET NLS_DATE_FORMAT=''YYYY-MM-DD HH24:MI:SS''';
END;
/

2. 입력 데이터 유효성 검사 레이어 구축

외부 데이터가 Oracle에 유입되기 전 단계에서 시간 값의 유효성을 반드시 검사하는 레이어를 구축해야 합니다. ETL 툴, API Gateway, 또는 Oracle의 BEFORE INSERT 트리거를 활용하여 0~23 범위를 벗어난 시간 값이 테이블에 저장되지 않도록 원천 차단하는 것이 가장 효과적인 예방책입니다.

-- BEFORE INSERT/UPDATE 트리거로 시간 값 사전 검증
CREATE OR REPLACE TRIGGER trg_validate_hour
BEFORE INSERT OR UPDATE ON orders
FOR EACH ROW
BEGIN
  IF TO_NUMBER(TO_CHAR(:NEW.order_time, 'HH24')) NOT BETWEEN 0 AND 23 THEN
    RAISE_APPLICATION_ERROR(-20001, 
      '유효하지 않은 시간 값입니다. 0~23 사이여야 합니다: ' 
      || TO_CHAR(:NEW.order_time, 'HH24'));
  END IF;
END;
/

관련 에러

  • ORA-01850: minute must be between 0 and 59 — 분(minute) 값이 0~59 범위를 벗어날 때 발생하며, ORA-01849와 함께 날짜 포맷 오류 시 연쇄적으로 나타나는 경우가 많습니다.
  • ORA-01851: seconds must be between 0 and 59 — 초(second) 값이 유효 범위를 벗어날 때 발생합니다.
  • ORA-01843: not a valid month — 월(month) 값이 유효하지 않을 때 발생하며, 날짜 문자열 파싱 오류의 대표적인 사례입니다.
  • ORA-01847: day of month must be between 1 and last day of month — 일(day) 값이 해당 월의 범위를 벗어날 때 발생합니다.
  • ORA-01830: date format picture ends before converting entire input string — 포맷 마스크와 입력 문자열의 길이가 맞지 않을 때 발생하며, 포맷 설정 오류 시 ORA-01849와 함께 자주 마주치는 에러입니다.

DBMS 에러 코드 시리즈

주요 DBMS error code를 정리하는 시리즈입니다.
블로그 홈에서 다른 에러도 확인하세요.

본 포스트는 AI가 생성한 기술 가이드입니다. 운영 환경 적용 전 충분한 검토를 권장합니다.

댓글 남기기