ORA-01861은 오라클이 문자열을 날짜·시간 타입으로 변환할 때 입력 리터럴과 포맷 마스크의 구조가 일치하지 않을 때 발생한다. TO_DATE의 두 번째 인자(마스크)가 첫 번째 인자(리터럴)의 길이·구분자·자릿수와 어긋나면 즉시 던져진다. 같은 SQL이 어제는 멀쩡히 돌다가 오늘 갑자기 실패하는 일도 있는데, 보통은 코드가 아니라 세션 NLS_DATE_FORMAT이 바뀌었기 때문이다. 본 글은 ORA-01861의 정확한 의미, 다섯 가지 핵심 원인, 진단 흐름, 그리고 NLS에 의존하지 않는 견고한 해결 패턴까지 정리한다.

주요 원인 / TO_DATE 마스크 불일치, 암시적 변환, NLS_DATE_FORMAT 차이, RR/MM/HH24 혼동, NLS_DATE_LANGUAGE 영향
근본 해법 / TO_DATE 명시, ANSI DATE 리터럴(
DATE '2026-05-15'), NLS 옵션 명시목차
즉 ORA-01861은 값의 유효성이 아니라 구조의 정합성을 검사한 결과다. '2026년 13월 32일'처럼 값이 비현실적인 경우는 ORA-01843, ORA-01847 같은 다른 에러로 분리된다. ORA-01861은 단순히 "글자 수·구분자·자릿수가 안 맞다"고 알려주는 1차 방어선이다.
1. ORA-01861이 던져지는 상황
ORA-01861이 발생하려면 두 가지 요소가 모두 충족돼야 한다. 첫째, 문자열을 날짜·시간 타입으로 변환하는 시점이 있어야 한다. 둘째, 그 변환에 사용된 포맷 마스크가 입력 리터럴과 구조적으로 어긋나야 한다.
가장 단순한 예시는 다음과 같다.
-- 실패: 입력 '2026-05-15'는 10자리, 마스크 'YYYYMMDD'는 8자리 기대
SELECT TO_DATE('2026-05-15', 'YYYYMMDD') FROM dual;
-- ORA-01861: literal does not match format string
-- 성공
SELECT TO_DATE('2026-05-15', 'YYYY-MM-DD') FROM dual;
문자열에 하이픈이 있는데 마스크는 하이픈을 비워뒀다. 길이와 구분자 모두 어긋난다. 오라클은 첫 번째 자리부터 마스크를 따라 읽다가 4번째 글자(-)가 5번째 숫자가 와야 할 자리에서 등장하자 즉시 ORA-01861을 던진다.
2. 발생 원인 다섯 가지
원인 1 / TO_DATE 마스크 불일치
가장 흔한 원인이다. 개발자가 입력 문자열의 실제 형식과 다른 마스크를 적었을 때 발생한다.
-- 흔한 실수 모음
TO_DATE('2026/05/15', 'YYYY-MM-DD') -- 슬래시 vs 하이픈
TO_DATE('26-05-15', 'YYYY-MM-DD') -- 2자리 연도 vs 4자리 마스크
TO_DATE('2026-05-15 14:30', 'YYYY-MM-DD') -- 시간 포함 리터럴 vs 날짜만 마스크
원인 2 / 암시적 변환의 함정
오라클은 문자열을 DATE 컬럼과 비교하거나 DATE 컬럼에 INSERT할 때 자동으로 TO_DATE를 호출한다. 이때 사용되는 마스크는 세션의 NLS_DATE_FORMAT이다. 코드에는 TO_DATE가 한 줄도 없는데 ORA-01861이 발생하는 경우 대부분 여기에 해당한다.
-- DB 기본 NLS_DATE_FORMAT이 'DD-MON-RR'인 경우
INSERT INTO emp(hire_date) VALUES ('2026-05-15');
-- 오라클: TO_DATE('2026-05-15', 'DD-MON-RR') 시도 → ORA-01861
암시적 변환의 무서운 점은 같은 코드가 환경마다 다르게 동작한다는 것이다. 개발 DB 세션 NLS는 YYYY-MM-DD인데 운영 DB는 DD-MON-RR이라면, 개발에서는 잘 돌던 쿼리가 운영에서만 실패한다.
원인 3 / NLS_DATE_FORMAT 차이
오라클 12c 이후 NLS_DATE_FORMAT 기본값은 NLS_TERRITORY 설정에서 파생된다. KOREA 영토는 RR/MM/DD, AMERICA 영토는 DD-MON-RR이다. 같은 DB라도 접속 클라이언트의 OS 로케일, 환경변수, JDBC URL 옵션에 따라 세션 NLS가 다르게 잡힌다.
원인 4 / RR · MM · HH24 같은 포맷 요소 혼동
MM(월 01~12) ↔MI(분 00~59) ━ M 다음 한 글자를 헷갈리면 의도와 다른 값이 들어간다HH또는HH12(1~12, AM/PM 필요) ↔HH24(0~23) ━ 14시를HH마스크로 파싱하면 ORA-01849RR(2자리 연도 라운드: 00~49→20xx, 50~99→19xx) ↔YY(현재 세기 그대로) ━ 형식 자체는 통과해도 의미가 달라짐D(요일 1~7) ↔DD(일 01~31) ━ 길이가 같다고 안심하면 안 됨
원인 5 / NLS_DATE_LANGUAGE 영향
MON, MONTH, DY, DAY 같은 텍스트 기반 포맷 요소는 세션의 NLS_DATE_LANGUAGE를 따른다. 한국어 세션에서 '15-JAN-26'을 'DD-MON-YY' 마스크로 파싱하면 오라클은 'JAN'이 아니라 '1월'을 기대하므로 ORA-01843이 발생한다. 영어로 강제하려면 TO_DATE의 세 번째 인자를 지정한다.
-- 한국어 세션에서도 영어 월 이름 파싱
SELECT TO_DATE('15-JAN-26', 'DD-MON-YY',
'NLS_DATE_LANGUAGE=AMERICAN') FROM dual;
2. 재현 시나리오 — 환경에 따라 다른 결과
다음 SQL은 세션 NLS에 따라 통과와 실패가 갈린다.
-- 케이스 A: NLS_DATE_FORMAT = 'YYYY-MM-DD' (한국 기본)
ALTER SESSION SET NLS_DATE_FORMAT = 'YYYY-MM-DD';
SELECT * FROM emp WHERE hire_date = '2026-05-15';
-- 성공
-- 케이스 B: NLS_DATE_FORMAT = 'DD-MON-RR' (미국 기본)
ALTER SESSION SET NLS_DATE_FORMAT = 'DD-MON-RR';
SELECT * FROM emp WHERE hire_date = '2026-05-15';
-- ORA-01861
세션 NLS는 다음 쿼리로 확인한다.
-- 현재 세션 NLS
SELECT parameter, value
FROM nls_session_parameters
WHERE parameter LIKE 'NLS_DATE%';
-- DB 기본 NLS
SELECT parameter, value
FROM nls_database_parameters
WHERE parameter LIKE 'NLS_DATE%';
4. 해결 방법 — 세 가지 패턴
패턴 A / TO_DATE 명시 변환
가장 직관적인 해법이다. 모든 문자열 → 날짜 변환을 TO_DATE로 명시하고, 마스크를 입력 형식에 정확히 맞춘다.
-- 비교 조건
SELECT * FROM emp
WHERE hire_date = TO_DATE('2026-05-15', 'YYYY-MM-DD');
-- INSERT
INSERT INTO emp(emp_id, hire_date)
VALUES (1001, TO_DATE('2026-05-15', 'YYYY-MM-DD'));
-- TIMESTAMP는 TO_TIMESTAMP
INSERT INTO log_t(log_time)
VALUES (TO_TIMESTAMP('2026-05-15 14:30:00.123',
'YYYY-MM-DD HH24:MI:SS.FF3'));
패턴 B / ANSI DATE·TIMESTAMP 리터럴
상수 값이라면 ANSI 표준 리터럴이 가장 안전하다. NLS 설정과 완전히 독립적이며, 항상 YYYY-MM-DD 또는 YYYY-MM-DD HH24:MI:SS[.FFFFFFFFF] 형식을 사용한다.
-- ANSI DATE 리터럴 (NLS와 무관)
SELECT DATE '2026-05-15' FROM dual;
-- ANSI TIMESTAMP 리터럴
SELECT TIMESTAMP '2026-05-15 14:30:00' FROM dual;
-- 비교 조건에도 사용 가능
SELECT * FROM emp
WHERE hire_date >= DATE '2026-01-01';
패턴 C / NLS_DATE_FORMAT 명시 설정
레거시 코드를 한꺼번에 못 고친다면 세션 진입 시점에 NLS_DATE_FORMAT을 고정한다. JDBC라면 oracle.jdbc.defaultDateFormat 같은 드라이버 옵션 또는 커넥션 풀 init SQL을 사용한다.
-- 세션 시작 시 NLS 통일
ALTER SESSION SET NLS_DATE_FORMAT = 'YYYY-MM-DD HH24:MI:SS';
ALTER SESSION SET NLS_TIMESTAMP_FORMAT = 'YYYY-MM-DD HH24:MI:SS.FF3';
ALTER SESSION SET NLS_DATE_LANGUAGE = 'AMERICAN';
이 방법은 응급 대응이며, 장기적으로는 모든 변환을 명시적으로 만드는 것이 안전하다. NLS는 언제든 환경 변경으로 다시 흔들릴 수 있다.
5. 인접 에러와의 구분
ORA-01861은 형식 검사 에러다. 값 검사에서 걸리는 에러들과 메시지가 비슷해 헷갈리기 쉽다.
| 에러 코드 | 검사 단계 | 전형적 입력 |
|---|---|---|
| ORA-01861 | 형식·구조 불일치 | '2026/05/15' + 'YYYY-MM-DD' |
| ORA-01843 | 월 값이 유효하지 않음 | '2026-13-01' + 'YYYY-MM-DD' |
| ORA-01847 | 일 값이 월 범위를 벗어남 | '2026-02-31' + 'YYYY-MM-DD' |
| ORA-01830 | 마스크가 리터럴보다 짧음 | '2026-05-15 14:30' + 'YYYY-MM-DD' |
| ORA-01840 | 리터럴이 마스크보다 짧음 | '2026-5' + 'YYYY-MM-DD' |
| ORA-01858 | 숫자 자리에 비숫자 등장 | '2026-AB-15' + 'YYYY-MM-DD' |
대부분의 경우 해결 패턴은 같다 ━ TO_DATE를 명시하고, 마스크와 리터럴을 끝까지 1:1로 맞추고, NLS·언어 의존을 제거한다.
세션 NLS_DATE_FORMAT이 변경됐을 가능성이 가장 높다. SQL 자체는 그대로지만 암시적 변환에 사용되는 마스크가 바뀌면 결과가 달라진다. NLS_SESSION_PARAMETERS를 확인하고, 가능하면 모든 변환을 TO_DATE로 명시화한다.
Q2. DATE 리터럴이 항상 더 좋은가요?
상수 값이라면 그렇다. NLS와 무관하고, 형식이 표준화돼 있어 가독성·이식성이 가장 높다. 다만 바인드 변수나 동적 값에는 적용할 수 없으므로, 그때는 TO_DATE를 쓴다.
Q3. 자바·파이썬 등 애플리케이션에서 호출할 때는 어떻게 하나요?
문자열로 넘기지 말고 드라이버의 Date·Timestamp 타입으로 바인딩한다. JDBC의
PreparedStatement.setDate, Python cx_Oracle의 datetime.date 객체 바인딩이 권장된다. 이 경우 드라이버가 직접 DATE 타입으로 전송하므로 NLS 의존이 사라진다.Q4. WHERE 절에서 인덱스 활용까지 고려하면?
컬럼 쪽에 TO_CHAR를 씌우면 인덱스를 못 탄다. 반드시 비교 값 쪽에 TO_DATE 또는 DATE 리터럴을 둬서 컬럼은 원본 그대로 두는 것이 좋다. 함수 기반 인덱스가 별도로 있는 경우가 아니라면 이 원칙은 변하지 않는다.
Q5. 23ai에서도 같은 동작인가요?
ORA-01861의 의미와 동작은 11g부터 23ai까지 동일하다. 클라우드 환경(ATP·ADW)도 동일하다. NLS 기본값이 환경마다 다를 수 있다는 점만 유의하면 된다.
6. 예방 체크리스트와 결론
ORA-01861은 SQL 표현의 일관성과 NLS 비의존성으로 거의 100% 차단할 수 있다. 새 쿼리·새 컬럼·새 모듈을 작성할 때 다음 항목을 점검한다.
- ✓모든 문자열 → 날짜 변환에 TO_DATE·TO_TIMESTAMP를 명시적으로 사용
- ✓상수 값은 ANSI
DATE 'YYYY-MM-DD'/TIMESTAMP 'YYYY-MM-DD HH24:MI:SS'리터럴 사용 - ✓커넥션 풀 초기 SQL에서 NLS_DATE_FORMAT·NLS_TIMESTAMP_FORMAT·NLS_DATE_LANGUAGE 명시
- ✓애플리케이션은 문자열이 아닌 Date·Timestamp 타입으로 바인딩
- ✓
MM↔MI,HH↔HH24,YY↔RR차이를 코드 리뷰 항목에 포함 - ✓
MON·MONTH마스크 사용 시NLS_DATE_LANGUAGE=AMERICAN명시 - ✓WHERE 절 비교 시 컬럼 쪽이 아닌 값 쪽에서 변환 수행 (인덱스 보존)
- ✓운영·개발·테스트 환경의 NLS_SESSION_PARAMETERS 동기화 점검
ORA-01861은 본질적으로 "암시적 동작에 의존하지 말라"는 경고다. 오라클이 친절하게 문자열을 날짜로 바꿔주는 것처럼 보이지만, 그 친절은 세션 NLS라는 가변 변수에 묶여 있다. 한 번이라도 환경이 바뀌면 즉시 에러로 되돌아온다. 답은 단순하다 ━ 모든 변환을 명시화하고, 상수는 ANSI 리터럴을 쓰고, 바인드는 타입을 정확히 맞춘다. 이 세 가지만 지키면 ORA-01861은 다시 만날 일이 거의 없는 에러가 된다.
#ORA01861 #literaldoesnotmatch #오라클에러 #TO_DATE #날짜형식 #NLS #DATE리터럴 #TO_TIMESTAMP #암시적변환 #NLSDATEFORMAT #NLSDATELANGUAGE #ORA01843 #ORA01830 #SQL날짜 #DB트러블슈팅
댓글