ORA-01861 日期格式錯誤:Oracle 原因與完整解決方法
ORA-01861 表示輸入的文字值與日期或時間戳記的格式模型不相符;修正方式是讓輸入內容與格式模型完全一致,或改用正確型別的綁定值。先確認實際資料型別,再檢查字串的年、月、日、時間、時區與格式模型,通常就能快速定位問題。
ORA-01861 是什麼?
Oracle 對 ORA-01861 的官方說明是:文字值必須符合格式字串;若使用 FX 精確比對修飾詞,除了前導空白外,文字值必須逐字元符合格式。官方建議的處理方式是更正格式字串,使其符合輸入的文字值。可參考 Oracle ORA-01861 官方錯誤說明。
這個錯誤多半發生在字串被轉成 DATE、TIMESTAMP 或帶時區的時間戳記時,也可能源自 Oracle 自動進行的隱式轉換。重點不是只看畫面上顯示的日期,而是確認 SQL 執行當下的值、型別與格式模型。
先用 30 秒快速排查
- 印出或記錄實際輸入字串,不要只看程式碼中的預期值。確認分隔符號、年份位數、月份順序、時間、毫秒與時區是否存在。
- 把輸入逐段對照格式模型。例如
2026-07-10對應YYYY-MM-DD,而不是DD-MM-YYYY。 - 確認資料庫欄位與綁定參數的型別是
DATE、TIMESTAMP還是VARCHAR2。日期欄位不應先被當成文字再轉回日期。 - 找出是否有隱式轉換,例如日期欄位與字串常值直接比較。這類 SQL 會受到工作階段的 NLS 設定影響。
常見錯誤與正確寫法
輸入是年、月、日順序時,格式模型也必須採相同順序。以下第一行會失敗,第二行才是正確寫法:
SELECT TO_DATE('2026-07-10', 'DD-MM-YYYY') FROM dual;
SELECT TO_DATE('2026-07-10', 'YYYY-MM-DD') FROM dual;
不要用字串與日期欄位比較,因為 Oracle 可能依 NLS_DATE_FORMAT 將字串隱式轉換。查詢某一個日曆日的資料時,也不要只用等號,否則帶有時間部分的資料可能被漏掉。ANSI 日期常值配合左閉右開區間更穩定:
SELECT *
FROM orders
WHERE created_at >= DATE '2026-07-10'
AND created_at < DATE '2026-07-11';
如果 created_at 本身是 DATE,絕對不要寫 TO_DATE(created_at, ...)。TO_DATE 的用途是把字串轉成日期;套在日期欄位上可能先把日期隱式轉成字串,再轉回日期,結果依賴 NLS 設定。只有在顯示輸出時才使用 TO_CHAR:
SELECT TO_CHAR(created_at, 'YYYY-MM-DD HH24:MI:SS')
FROM orders;
包含時分秒的字串應使用對應的時間戳記格式:
SELECT TO_TIMESTAMP(
'2026-07-10 14:30:15',
'YYYY-MM-DD HH24:MI:SS'
) FROM dual;
ISO 8601 字串若帶有數字時區偏移,可使用 TO_TIMESTAMP_TZ。格式模型中的字面 T 必須加上雙引號,時區則由 TZH:TZM 接收:
SELECT TO_TIMESTAMP_TZ(
'2026-07-10T14:30:15+08:00',
'YYYY-MM-DD"T"HH24:MI:SSTZH:TZM'
) FROM dual;
FX 會啟用精確格式比對,適合輸入規格固定、需要拒絕寬鬆解析的情境。啟用後,標點符號與數字寬度必須符合格式;若還要允許省略前導零,可配合相關格式修飾詞設計,但不要把不固定的輸入誤當固定格式。
SELECT TO_DATE('2026-07-10', 'FXYYYY-MM-DD') FROM dual;
日期與時間元素、修飾詞及限制可查閱 Oracle Database 19c SQL 格式模型文件。
檢查 NLS_DATE_FORMAT
下列查詢可查看目前工作階段的日期相關設定:
SELECT parameter, value
FROM nls_session_parameters
WHERE parameter IN (
'NLS_DATE_FORMAT',
'NLS_TIMESTAMP_FORMAT',
'NLS_TIMESTAMP_TZ_FORMAT',
'NLS_DATE_LANGUAGE'
)
ORDER BY parameter;
NLS_DATE_FORMAT 是工作階段設定,不同用戶端、連線池或登入觸發器可能建立不同值。因此,依賴預設格式的 SQL 很脆弱:同一段文字在某個工作階段成功,在另一個工作階段可能得到 ORA-01861。轉換文字時應明確指定格式模型;應用程式傳參數時則優先傳送具型別的日期或時間戳記值。
JDBC/Spring 應用程式的正確處理方式
不要把日期字串串接進 SQL。JDBC 應使用預備敘述與型別綁定,例如只有日期時使用 PreparedStatement.setDate,包含時間時使用 setTimestamp;若採用現代 JDBC,也可依驅動程式支援情況以 setObject 綁定適合的 java.time 型別。Spring 的參數化查詢也應傳入明確型別,而非拼接文字。
SELECT *
FROM orders
WHERE created_at >= ?
AND created_at < ?
SQL Developer 與應用程式看似執行相同 SQL,結果卻不同,常見原因是兩者建立了不同工作階段,具有不同 NLS 設定;另一個原因是 SQL Developer 使用文字常值,而程式實際送入的是不同 JDBC 綁定型別。比較問題時,要同時記錄 SQL、綁定值、綁定型別及工作階段 NLS 參數。
排查清單
- 確認錯誤發生的 SQL 與實際綁定值。
- 確認欄位、運算式和參數的資料型別。
- 逐段比對輸入與格式模型,包括標點、寬度、時間和時區。
- 移除字串與日期之間的隱式轉換。
- 日期篩選改用具型別的常值、綁定值或半開區間。
- 檢查目前工作階段的 NLS 設定。
- 分別在 SQL 工具與應用程式記錄綁定型別後重測。
常見問題
TO_DATE 與 TO_CHAR 有什麼不同?
TO_DATE 把字串依指定格式解析成 DATE;TO_CHAR 把日期或時間戳記格式化為顯示文字。不要用 TO_DATE 格式化日期,也不要把 TO_CHAR 的結果當成日期繼續計算。
為什麼相同 SQL 在一個環境成功,另一個環境失敗?
最常見原因是工作階段 NLS 設定不同,或用戶端送入的綁定型別不同。若 SQL 依賴隱式轉換,環境差異就會改變解析結果。
建議修改 NLS_DATE_FORMAT 嗎?
不建議把它當成主要修正。修改工作階段設定只能暫時配合某種輸入,還可能掩蓋其他程式的型別錯誤。較可靠的做法是明確指定格式模型,或直接使用具型別的綁定值。
結論
處理 ORA-01861 時,依序核對資料型別、實際輸入與格式模型,並移除隱式轉換。字串解析要明確指定格式,日期條件要使用日期常值或型別綁定,輸出顯示才使用 TO_CHAR。當三者一致,錯誤通常能被穩定排除,也不會因工具、連線池或 NLS 環境不同而再次出現。















