【完全ガイド】ORA-01830: date format picture ends before converting の原因と解決方法|TO_TIMESTAMP・ISO 8601・タイムゾーンまで徹底解説
- 作成日 2026.07.22
- Oracle Database その他
Oracle で日付変換を扱う際、必ず遭遇するエラー:
SELECT TO_DATE('2026-06-15 14:30:45', 'YYYY-MM-DD') FROM DUAL;
ORA-01830: date format picture ends before converting entire input string
翻訳: 「フォーマット指定が終わったのに、入力文字列にまだ残りがある」
つまり、入力に余分な文字があるというエラー。似た日付エラーの ORA-01843: not a valid month と混同されがちですが、別の問題を示します:
- ORA-01843: 「無効な月」(月の位置に解釈できない値)
- ORA-01830: 「フォーマット終了後に余り」(余分な時刻・文字)
現場では:
- REST API から取得した ISO 8601 日付(
Tセパレータ) - SQL Server / PostgreSQL からの移行データ
- RMAN の SET UNTIL TIME 指定
- Java
LocalDateTimeからの変換 - タイムゾーン付きデータ
- ミリ秒・マイクロ秒付き
- 末尾の余分なスペース
これらすべてで発生します。特にマイクロサービス・REST API 時代では、ISO 8601 の YYYY-MM-DDTHH:MM:SS 形式が標準的で、Oracle の従来 TO_DATE では扱いにくい局面が急増しています。
さらに、多くの記事は**「フォーマットを合わせろ」**で終わっていますが、実務では:
- フォーマットが動的に変わる(複数ソース混在)
- タイムゾーン変換が必要
- ミリ秒精度の保持
- 柔軟な変換関数の設計
- NLS_DATE_FORMAT との相互作用
など、深い理解が必要です。
本記事では、ORA-01830: date format picture ends before converting entire input string の完全な原因と解決方法を、リファレンスとして実用的に整理します。ORA-01843 との違い、6大発生パターン、TO_DATE/TO_TIMESTAMP/TO_TIMESTAMP_TZ の使い分け、ISO 8601 対応、タイムゾーン変換、柔軟な変換関数、Rails/Java/Python 対応、実践シナリオ、予防策、FAQまで完全網羅。この1本で ORA-01830 を根本から解決できるようになります。
- 1. 結論:フォーマットを入力に完全一致させる
- 2. まず理解する:エラーの本質
- 3. 【原因①】時刻部分がある
- 4. 【原因②】ISO 8601 の T セパレータ
- 5. 【原因③】タイムゾーン付き
- 6. 【原因④】ミリ秒・マイクロ秒
- 7. 【原因⑤】末尾の余分な空白・文字
- 8. 【原因⑥】他 DB からのデータ取り込み
- 9. 3つの変換関数の使い分け
- 10. フォーマット文字列 完全リファレンス
- 11. 実践パターン:柔軟な変換関数
- 12. Rails / Java / Python 対応
- 13. 実践シナリオ
- 14. 予防のベストプラクティス
- 15. トラブルシューティング
- 16. よくある質問(FAQ)
- 16.1. Q1. ORA-01830 と ORA-01843 の違い
- 16.2. Q2. NLS_DATE_FORMAT との関係
- 16.3. Q3. FX モディファイアの用途
- 16.4. Q4. リテラル文字の “” は必須?
- 16.5. Q5. TIMESTAMP vs DATE
- 16.6. Q6. Autonomous DB での挙動
- 16.7. Q7. AWS RDS Oracle
- 16.8. Q8. 他 DB からの移行時の注意
- 16.9. Q9. Rails では自動処理される?
- 16.10. Q10. Java 21 の LocalDateTime
- 16.11. Q11. Python datetime.now()
- 16.12. Q12. ミリ秒がないとき
- 17. 参考リンク
- 18. まとめ
結論:フォーマットを入力に完全一致させる
時間がない方向けに、最速の対処を先に示します。
基本原則
フォーマット文字列 = 入力文字列の構造 に完全一致させる。
-- ❌ フォーマットが短い
TO_DATE('2026-06-15 14:30:45', 'YYYY-MM-DD')
-- ✅ フォーマットを完全に
TO_DATE('2026-06-15 14:30:45', 'YYYY-MM-DD HH24:MI:SS')
よくある入力パターン別対処
-- ISO 8601 (T セパレータ)
TO_DATE('2026-06-15T14:30:45', 'YYYY-MM-DD"T"HH24:MI:SS')
-- ミリ秒付き
TO_TIMESTAMP('2026-06-15 14:30:45.123', 'YYYY-MM-DD HH24:MI:SS.FF3')
-- タイムゾーン付き
TO_TIMESTAMP_TZ('2026-06-15 14:30:45 +09:00',
'YYYY-MM-DD HH24:MI:SS TZH:TZM')
-- ISO 8601 完全形(Z も含む)
TO_TIMESTAMP_TZ('2026-06-15T14:30:45.123Z',
'YYYY-MM-DD"T"HH24:MI:SS.FF3"Z"')
3つの関数の使い分け
| 関数 | 用途 | 精度 |
|---|---|---|
| TO_DATE | 秒まで | 秒 |
| TO_TIMESTAMP | 少数秒 | ナノ秒 |
| TO_TIMESTAMP_TZ | タイムゾーン付き | ナノ秒 + TZ |
ORA-01830 vs ORA-01843
| エラー | 意味 |
|---|---|
| ORA-01830 | フォーマット終了後に余り |
| ORA-01843 | 月の位置に無効な値 |
詳細は以下で解説します。
まず理解する:エラーの本質
メッセージの意味
ORA-01830: date format picture ends before converting entire input string
↑
「入力を全部変換する前に」
フォーマットピクチャが終わったのに、入力文字列にまだ処理されていない部分がある。
Oracle 公式の説明
Cause: A valid date format picture included extra data.
The first part of the format picture was converted into a valid date.
The remaining data was not required.
Action: Check the specifications for date format pictures and correct.
翻訳: 「フォーマットの最初の部分は有効な日付に変換されたが、残りのデータは不要」
具体例
入力: '2026-06-15 14:30:45'
フォーマット: 'YYYY-MM-DD'
処理:
Y Y Y Y - M M - D D | 14:30:45
[----ここまで変換----] ↑ 余分! → ORA-01830
ORA-01830 vs ORA-01843 の完全比較
-- ORA-01830: フォーマット終了後に余分
TO_DATE('2026-06-15 14:30', 'YYYY-MM-DD')
-- [変換OK] [余分]
-- ORA-01843: 月の位置に無効な値
TO_DATE('31/12/1985', 'DD-MON-RR')
-- [DD] [??] ← '12' は月名として無効
- ORA-01830: 「長すぎる」入力
- ORA-01843: 「フォーマットに合わない」入力
【原因①】時刻部分がある
症状
TO_DATE('2026-06-15 14:30:45', 'YYYY-MM-DD')
-- ORA-01830
解決
-- 完全なフォーマット指定
TO_DATE('2026-06-15 14:30:45', 'YYYY-MM-DD HH24:MI:SS')
-- または日付だけ切り出し
TO_DATE(SUBSTR('2026-06-15 14:30:45', 1, 10), 'YYYY-MM-DD')
【原因②】ISO 8601 の T セパレータ
症状
REST API や JSON からの日付:
TO_DATE('2026-06-15T14:30:45', 'YYYY-MM-DD HH24:MI:SS')
-- ORA-01830(T が余分)
解決
リテラル文字として "T" を含める:
TO_DATE('2026-06-15T14:30:45', 'YYYY-MM-DD"T"HH24:MI:SS')
ダブルクォートでくくるとリテラル文字として扱う。
タイムゾーン付き ISO 8601
-- +09:00 のようなオフセット
TO_TIMESTAMP_TZ('2026-06-15T14:30:45+09:00',
'YYYY-MM-DD"T"HH24:MI:SSTZH:TZM')
-- Z(UTC)
TO_TIMESTAMP_TZ('2026-06-15T14:30:45Z',
'YYYY-MM-DD"T"HH24:MI:SS"Z"')
-- ミリ秒 + タイムゾーン
TO_TIMESTAMP_TZ('2026-06-15T14:30:45.123+09:00',
'YYYY-MM-DD"T"HH24:MI:SS.FF3TZH:TZM')
モダン Web API の典型パターン
// JavaScript の Date.toISOString()
new Date().toISOString()
// → "2026-06-15T14:30:45.123Z"
対応する TO_TIMESTAMP_TZ:
TO_TIMESTAMP_TZ('2026-06-15T14:30:45.123Z',
'YYYY-MM-DD"T"HH24:MI:SS.FF3"Z"')
【原因③】タイムゾーン付き
症状
TO_DATE('2026-06-15 14:30:45 +09:00', 'YYYY-MM-DD HH24:MI:SS')
-- ORA-01830(+09:00 が余分)
解決
TO_TIMESTAMP_TZ を使う:
TO_TIMESTAMP_TZ('2026-06-15 14:30:45 +09:00',
'YYYY-MM-DD HH24:MI:SS TZH:TZM')
タイムゾーンの表現
| 形式 | フォーマット |
|---|---|
+09:00 | TZH:TZM |
+0900 | TZHTZM |
JST / Asia/Tokyo | TZR(Time Zone Region) |
PDT 等の略称 | TZD |
内部での保持
-- 日本時間で入力
SELECT TO_TIMESTAMP_TZ('2026-06-15 14:30:45 +09:00',
'YYYY-MM-DD HH24:MI:SS TZH:TZM') FROM DUAL;
-- Oracle 内部で TZ 情報保持
-- UTC に変換
SELECT ... AT TIME ZONE 'UTC'
【原因④】ミリ秒・マイクロ秒
症状
TO_DATE('2026-06-15 14:30:45.123', 'YYYY-MM-DD HH24:MI:SS')
-- ORA-01830(.123 が余分)
TO_DATE は少数秒サポートなし。
解決
TO_TIMESTAMP を使う:
-- ミリ秒
TO_TIMESTAMP('2026-06-15 14:30:45.123', 'YYYY-MM-DD HH24:MI:SS.FF3')
-- マイクロ秒
TO_TIMESTAMP('2026-06-15 14:30:45.123456', 'YYYY-MM-DD HH24:MI:SS.FF6')
-- ナノ秒
TO_TIMESTAMP('2026-06-15 14:30:45.123456789', 'YYYY-MM-DD HH24:MI:SS.FF9')
FF の数値
FF3: ミリ秒(1/1000 秒)FF6: マイクロ秒(1/1000000 秒)FF9: ナノ秒FF(数値なし): 最大9桁
入力の少数秒桁数に合わせる。
【原因⑤】末尾の余分な空白・文字
症状
TO_DATE('2026-06-15 ', 'YYYY-MM-DD')
-- ORA-01830(末尾のスペースが余分)
解決A: TRIM
TO_DATE(TRIM('2026-06-15 '), 'YYYY-MM-DD')
解決B: フォーマットに含める
TO_DATE('2026-06-15 ', 'YYYY-MM-DD" "')
-- " " でリテラル指定
現実的には TRIM 推奨。
RTRIM で末尾のみ
TO_DATE(RTRIM('2026-06-15 '), 'YYYY-MM-DD')
【原因⑥】他 DB からのデータ取り込み
症状
SQL Server / PostgreSQL / MySQL からの取り込みで発生:
-- SQL Server から: '2026-06-15 14:30:45.1234567'
TO_DATE('2026-06-15 14:30:45.1234567', 'YYYY-MM-DD HH24:MI:SS')
-- ORA-01830
解決
TIMESTAMP 型で受ける:
CREATE TABLE imported_data (
imported_time TIMESTAMP(7) -- 高精度
);
INSERT INTO imported_data VALUES (
TO_TIMESTAMP('2026-06-15 14:30:45.1234567', 'YYYY-MM-DD HH24:MI:SS.FF7')
);
JDBC / oracledb 経由
Java LocalDateTime / Python datetime を直接渡す:
// Java
ps.setTimestamp(1, Timestamp.valueOf(localDateTime));
# Python
cursor.execute("INSERT ... VALUES (:d)", d=datetime.now())
文字列化を避けるのが根本策。
3つの変換関数の使い分け
TO_DATE
TO_DATE(<string>, <format>)
- DATE 型を返す
- 秒までの精度(少数秒不可)
- タイムゾーン不可
TO_TIMESTAMP
TO_TIMESTAMP(<string>, <format>)
- TIMESTAMP 型を返す
- 少数秒対応(FF)
- タイムゾーン不可
TO_TIMESTAMP_TZ
TO_TIMESTAMP_TZ(<string>, <format>)
- TIMESTAMP WITH TIME ZONE 型を返す
- 少数秒 + タイムゾーン
選択チャート
入力に何が含まれるか?
↓
少数秒あり? タイムゾーンあり?
├─ 両方 → TO_TIMESTAMP_TZ
├─ 少数秒のみ → TO_TIMESTAMP
├─ タイムゾーンのみ → TO_TIMESTAMP_TZ
└─ どちらもなし → TO_DATE
フォーマット文字列 完全リファレンス
日付部分
| コード | 意味 | 例 |
|---|---|---|
| YYYY | 4桁年 | 2026 |
| YY | 2桁年 | 26 |
| RR | Y2K対応2桁年 | 26→2026 |
| MM | 数値月 | 06 |
| MON | 月名略称 | JUN |
| MONTH | 月名フル | JUNE |
| DD | 日 | 15 |
| DDD | 年内日 | 166 |
| DAY | 曜日フル | MONDAY |
| DY | 曜日略称 | MON |
時刻部分
| コード | 意味 | 例 |
|---|---|---|
| HH | 12時間制 | 02 |
| HH24 | 24時間制 | 14 |
| MI | 分 | 30 |
| SS | 秒 | 45 |
| FF | 少数秒(最大9) | 123456789 |
| FF3 | ミリ秒 | 123 |
| FF6 | マイクロ秒 | 123456 |
| FF9 | ナノ秒 | 123456789 |
| AM/PM | 午前午後 | PM |
タイムゾーン
| コード | 意味 | 例 |
|---|---|---|
| TZH | TZ 時 | +09 |
| TZM | TZ 分 | 00 |
| TZH:TZM | TZ 時分 | +09:00 |
| TZR | TZ リージョン名 | Asia/Tokyo |
| TZD | TZ 略称 | JST |
リテラル文字
"任意の文字"
例:
'YYYY-MM-DD"T"HH24:MI:SS' -- ISO 8601 T セパレータ
'YYYY-MM-DD"Z"' -- UTC マーカー
'YYYY年MM月DD日' -- 日本語(マルチバイトも直接OK)
FX モディファイア
厳密モード、フォーマットと入力が完全一致必要:
-- 通常: 前ゼロ許容
TO_DATE('2026-6-1', 'YYYY-MM-DD') -- OK
-- FX: 前ゼロ必須
TO_DATE('2026-6-1', 'FXYYYY-MM-DD') -- ORA-01862
TO_DATE('2026-06-01', 'FXYYYY-MM-DD') -- OK
厳密な検証用。
実践パターン:柔軟な変換関数
複数フォーマット対応関数
CREATE OR REPLACE FUNCTION flexible_to_date(
p_str VARCHAR2
) RETURN DATE AS
v_formats SYS.ODCIVARCHAR2LIST := SYS.ODCIVARCHAR2LIST(
'YYYY-MM-DD"T"HH24:MI:SS.FF"Z"',
'YYYY-MM-DD"T"HH24:MI:SS',
'YYYY-MM-DD HH24:MI:SS.FF',
'YYYY-MM-DD HH24:MI:SS',
'YYYY-MM-DD',
'DD/MM/YYYY HH24:MI:SS',
'DD/MM/YYYY',
'MM/DD/YYYY HH24:MI:SS',
'MM/DD/YYYY',
'DD-MON-YYYY',
'DD-MON-YY'
);
v_result DATE;
BEGIN
IF p_str IS NULL THEN RETURN NULL; END IF;
FOR i IN 1 .. v_formats.COUNT LOOP
BEGIN
v_result := TO_DATE(TRIM(p_str), v_formats(i));
RETURN v_result;
EXCEPTION
WHEN OTHERS THEN NULL;
END;
END LOOP;
RAISE_APPLICATION_ERROR(-20001, 'No matching format: ' || p_str);
END;
/
-- 使用
SELECT flexible_to_date('2026-06-15T14:30:45Z') FROM DUAL;
SELECT flexible_to_date('06/15/2026') FROM DUAL;
Oracle 12c+ の DEFAULT ON CONVERSION ERROR
TO_DATE(input DEFAULT NULL ON CONVERSION ERROR, 'YYYY-MM-DD HH24:MI:SS')
変換失敗時に NULL、バルク処理で有用。
NLS_DATE_FORMAT との相互作用
-- セッションのデフォルト日付フォーマット
SHOW PARAMETER nls_date_format
TO_DATE(str) (フォーマット指定なし)だと NLS_DATE_FORMAT が使用される。
パラメータ確認の詳細は Oracle パラメータ確認(V$PARAMETER)の記事、暗黙変換問題は ORA-01843: not a valid month の記事も参照してください。
Rails / Java / Python 対応
Rails ActiveRecord
# Rails は自動で TIMESTAMP に変換(推奨)
Order.create!(order_date: Time.current)
# 生 SQL の場合
sql = "INSERT INTO orders (order_date) VALUES (TO_TIMESTAMP(:d, 'YYYY-MM-DD HH24:MI:SS.FF'))"
ActiveRecord::Base.connection.execute(sql, d: Time.current.iso8601)
# 初期化スクリプトで NLS 設定
Rails.application.config.after_initialize do
ActiveRecord::Base.connection.execute(
"ALTER SESSION SET NLS_DATE_FORMAT = 'YYYY-MM-DD HH24:MI:SS'"
)
ActiveRecord::Base.connection.execute(
"ALTER SESSION SET NLS_TIMESTAMP_FORMAT = 'YYYY-MM-DD HH24:MI:SS.FF'"
)
end
Rails 8 系の詳細は Rails 8 アップグレードガイドの記事、rails db:migrate 使い方の記事、Solid Queue 使い方の記事も参照してください。
Java (JDBC)
// ❌ 文字列で渡す(フォーマット問題の温床)
ps.setString(1, "2026-06-15T14:30:45.123Z");
// ✅ Timestamp 型で渡す
ps.setTimestamp(1, Timestamp.from(Instant.now()));
// ✅ OffsetDateTime(TZ 保持)
ps.setObject(1, OffsetDateTime.now());
Python (oracledb)
import oracledb
from datetime import datetime, timezone
# ✅ datetime 型を直接渡す(推奨)
cursor.execute(
"INSERT INTO orders (order_date) VALUES (:d)",
d=datetime.now(timezone.utc)
)
# ❌ 文字列で渡す
cursor.execute(
"INSERT INTO orders (order_date) VALUES (TO_TIMESTAMP(:d, 'YYYY-MM-DD HH24:MI:SS.FF'))",
d="2026-06-15 14:30:45.123"
)
実践シナリオ
シナリオ1:REST API の日付処理
-- API から: "2026-06-15T14:30:45.123Z"
INSERT INTO api_events (event_time)
VALUES (TO_TIMESTAMP_TZ(:api_time, 'YYYY-MM-DD"T"HH24:MI:SS.FF3"Z"'));
シナリオ2:CSV バルクインポート
-- 複数フォーマット混在の CSV
INSERT INTO orders (order_id, order_date)
SELECT order_id, flexible_to_date(order_date_str)
FROM staging_orders;
シナリオ3:Data Pump インポート後の整合
-- 別 DB からのインポートで日付列
SELECT COUNT(*) FROM imported_data
WHERE order_date IS NULL AND order_date_str IS NOT NULL;
-- 変換失敗行を検出
Data Pump の詳細は Oracle Data Pump 使い方の記事を参照してください。
シナリオ4:RMAN の SET UNTIL TIME
RMAN> run {
SET UNTIL TIME "TO_DATE('2026-06-15 15:15:00', 'YYYY-MM-DD HH24:MI:SS')";
RESTORE DATABASE;
RECOVER DATABASE;
}
完全なフォーマット指定、ORA-01830 回避。
シナリオ5:ETL パイプライン
INSERT INTO fact_events (event_time, event_type, amount)
SELECT
CAST(TO_TIMESTAMP_TZ(event_time_str,
'YYYY-MM-DD"T"HH24:MI:SS.FF3TZH:TZM') AS TIMESTAMP),
event_type,
amount
FROM staging_events
LOG ERRORS INTO staging_events_err REJECT LIMIT UNLIMITED;
LOG ERRORS の詳細は ORA-00001: unique constraint violated の記事も参考にしてください。
シナリオ6:Rails migration での datetime
class AddTimestampToOrders < ActiveRecord::Migration[8.0]
def change
add_column :orders, :ordered_at, :timestamp, precision: 6
end
end
precision で少数秒桁数指定。
シナリオ7:Kamal デプロイ後の初期化
# デプロイ後の初期化スクリプトで NLS 設定
env:
clear:
NLS_LANG: JAPANESE_JAPAN.AL32UTF8
NLS_DATE_FORMAT: "YYYY-MM-DD HH24:MI:SS"
NLS_TIMESTAMP_FORMAT: "YYYY-MM-DD HH24:MI:SS.FF"
Kamal 2 デプロイの詳細は Kamal 2 デプロイの記事を参照してください。
シナリオ8:Docker Oracle での動作確認
docker exec -it oracle-xe sqlplus scott/tiger <<EOF
SELECT TO_TIMESTAMP_TZ('2026-06-15T14:30:45.123+09:00',
'YYYY-MM-DD"T"HH24:MI:SS.FF3TZH:TZM')
FROM DUAL;
EOF
Docker 関連は docker daemon 接続エラーの記事、Docker no space left on device の記事も参照してください。
シナリオ9:Solid Queue ジョブ時刻管理
-- ジョブの実行時刻
SELECT job_id,
TO_CHAR(scheduled_at, 'YYYY-MM-DD"T"HH24:MI:SS.FF3"Z"') AS scheduled_iso
FROM solid_queue_jobs;
Solid Queue の詳細は Solid Queue 使い方の記事も参照してください。
シナリオ10:分析クエリ
-- 時系列分析
SELECT
TRUNC(event_time, 'HH24') AS hour,
COUNT(*) event_count
FROM events
WHERE event_time BETWEEN
TO_TIMESTAMP('2026-06-15 00:00:00', 'YYYY-MM-DD HH24:MI:SS')
AND TO_TIMESTAMP('2026-06-16 00:00:00', 'YYYY-MM-DD HH24:MI:SS')
GROUP BY TRUNC(event_time, 'HH24')
ORDER BY hour;
予防のベストプラクティス
1. 明示的なフォーマット指定
-- ❌ 暗黙変換
INSERT INTO t VALUES ('2026-06-15');
-- ✅ 明示的
INSERT INTO t VALUES (TO_DATE('2026-06-15', 'YYYY-MM-DD'));
2. アプリでは日付型を使う
// ❌ 文字列
ps.setString(1, dateStr);
// ✅ 日付型
ps.setTimestamp(1, timestamp);
文字列化を避けるのが根本策。
3. ISO 8601 標準を使う
2026-06-15T14:30:45.123Z
曖昧さのない標準形式。
4. TIMESTAMP 型を優先
-- ❌ DATE で受ける(精度不足)
CREATE TABLE t (event_time DATE);
-- ✅ TIMESTAMP で受ける
CREATE TABLE t (event_time TIMESTAMP(6));
-- ✅ タイムゾーン対応
CREATE TABLE t (event_time TIMESTAMP(6) WITH TIME ZONE);
5. セッション初期化スクリプト
-- 統一フォーマット
ALTER SESSION SET NLS_DATE_FORMAT = 'YYYY-MM-DD HH24:MI:SS';
ALTER SESSION SET NLS_TIMESTAMP_FORMAT = 'YYYY-MM-DD HH24:MI:SS.FF';
ALTER SESSION SET NLS_TIMESTAMP_TZ_FORMAT = 'YYYY-MM-DD HH24:MI:SS.FF TZH:TZM';
6. 柔軟な変換関数を用意
-- 複数フォーマット対応の関数
FUNCTION flexible_to_date(p_str VARCHAR2) RETURN DATE ...
7. LOG ERRORS でエラー分離
INSERT INTO t
SELECT TO_DATE(col, 'YYYY-MM-DD') FROM src
LOG ERRORS INTO t_err REJECT LIMIT UNLIMITED;
8. 12c+ の ON CONVERSION ERROR
TO_DATE(str DEFAULT NULL ON CONVERSION ERROR, 'YYYY-MM-DD HH24:MI:SS')
9. 入力バリデーション
if (!input.matches("\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}Z")) {
throw new IllegalArgumentException("Invalid date format");
}
10. テストデータの多様化
- 秒までのみ
- ミリ秒あり
- タイムゾーンあり
- ISO 8601(T セパレータ)
- 空白付き
- 他形式
トラブルシューティング
特定行だけエラー
-- 問題データを検出
SELECT date_str
FROM t
WHERE NOT REGEXP_LIKE(date_str, '^\d{4}-\d{2}-\d{2}$');
バルクで一部失敗
INSERT INTO target
SELECT TO_DATE(date_str, 'YYYY-MM-DD') FROM source
LOG ERRORS INTO target_err REJECT LIMIT UNLIMITED;
-- エラー行確認
SELECT * FROM target_err WHERE ora_err_number$ = 1830;
変換関数を SQL 内で
-- 12c+
SELECT TO_DATE(str DEFAULT NULL ON CONVERSION ERROR, 'YYYY-MM-DD')
FROM t;
-- 変換失敗時に NULL
タイムゾーン変換
-- UTC → JST
SELECT event_time AT TIME ZONE 'Asia/Tokyo'
FROM events;
-- 特定 TZ で保存されているものを UTC に
SELECT event_time AT TIME ZONE 'UTC'
FROM events;
RMAN / SQL*Plus での発生
-- 完全なフォーマット指定
SET UNTIL TIME "TO_DATE('2026-06-15 15:15:00', 'YYYY-MM-DD HH24:MI:SS')";
JDBC ODBC ドライバの問題
古いドライバで ORA-01830 が頻発することあり:
- 最新版に更新
- パラメータバインディングを使用(文字列化を避ける)
よくある質問(FAQ)
Q1. ORA-01830 と ORA-01843 の違い
- ORA-01830: フォーマット終了後に余り
- ORA-01843: 月の位置に無効な値
Q2. NLS_DATE_FORMAT との関係
TO_DATE(str)(フォーマット指定なし)は NLS_DATE_FORMAT に依存。明示的指定推奨。
Q3. FX モディファイアの用途
厳密な検証(前ゼロ必須、区切り文字完全一致)。
Q4. リテラル文字の “” は必須?
セパレータ文字(-, /, :)は自動認識、任意文字は “” 必須:
'YYYY-MM-DD' -- OK(- はセパレータとして認識)
'YYYY_MM_DD' -- 一部認識、環境依存
'YYYY"年"MM"月"DD"日"' -- 確実
Q5. TIMESTAMP vs DATE
- DATE: 年月日時分秒(1秒精度)
- TIMESTAMP: 少数秒
- TIMESTAMP WITH TIME ZONE: + TZ
用途で使い分け。
Q6. Autonomous DB での挙動
同じ挙動。
Q7. AWS RDS Oracle
同じ挙動。
Q8. 他 DB からの移行時の注意
- SQL Server:
datetime→ OracleTIMESTAMP 精度に注意 - PostgreSQL:
timestamptz→ TO_TIMESTAMP_TZ - MySQL:
datetime→ TIMESTAMP 使用
Q9. Rails では自動処理される?
ActiveRecord は基本的に自動変換。生 SQL を書く時のみ注意。
Q10. Java 21 の LocalDateTime
ps.setObject(1, LocalDateTime.now());
// oracle-jdbc が自動変換
文字列化不要。
Q11. Python datetime.now()
cursor.execute("... :d", d=datetime.now())
# oracledb が自動変換
Q12. ミリ秒がないとき
TO_TIMESTAMP('2026-06-15', 'YYYY-MM-DD')
-- FF なくても OK、0 で埋められる
参考リンク
Oracle 公式
- Oracle Database Error Messages: ORA-01830
- TO_DATE Function
- TO_TIMESTAMP Function
- TO_TIMESTAMP_TZ Function
- Datetime Format Models
まとめ
ORA-01830: date format picture ends before converting entire input string の要点を再整理します。
エラーの本質
入力: '2026-06-15 14:30:45'
フォーマット: 'YYYY-MM-DD'
↓
'2026-06-15' まで変換 → '14:30:45' が余分 → ORA-01830
3つの変換関数
TO_DATE(str, fmt) -- DATE 型、秒精度
TO_TIMESTAMP(str, fmt) -- TIMESTAMP 型、少数秒
TO_TIMESTAMP_TZ(str, fmt) -- TIMESTAMP WITH TZ 型
6大発生パターン
| # | パターン | 対処 |
|---|---|---|
| ① | 時刻部分あり | HH24:MI:SS 追加 |
| ② | ISO 8601 T セパレータ | "T" リテラル |
| ③ | タイムゾーン | TO_TIMESTAMP_TZ |
| ④ | ミリ秒・マイクロ秒 | FF3, FF6 |
| ⑤ | 末尾空白 | TRIM |
| ⑥ | 他 DB データ | TIMESTAMP 型で受ける |
フォーマット文字列 主要
YYYY-MM-DD 2026-06-15
YYYY-MM-DD HH24:MI:SS 2026-06-15 14:30:45
YYYY-MM-DD HH24:MI:SS.FF3 2026-06-15 14:30:45.123
YYYY-MM-DD"T"HH24:MI:SS 2026-06-15T14:30:45
YYYY-MM-DD HH24:MI:SS TZH:TZM 2026-06-15 14:30:45 +09:00
ISO 8601 の対応
-- モダン Web API 標準
TO_TIMESTAMP_TZ('2026-06-15T14:30:45.123Z',
'YYYY-MM-DD"T"HH24:MI:SS.FF3"Z"')
予防のベストプラクティス
- 明示的なフォーマット指定
- アプリで日付型を使う(文字列化を避ける)
- ISO 8601 標準採用
- TIMESTAMP 型を優先
- セッション初期化
- 柔軟な変換関数
- LOG ERRORS 活用
- 12c+ の ON CONVERSION ERROR
事故防止
- フォーマットは入力に完全一致
- リテラル文字は
""で囲む - タイムゾーンあれば TO_TIMESTAMP_TZ
- ミリ秒あれば TO_TIMESTAMP
- 末尾空白に TRIM
現代の推奨
- DATE より TIMESTAMP
- TIMESTAMP より TIMESTAMP WITH TIME ZONE(TZ 保持)
- アプリで日付型を直接渡す
- ISO 8601 を標準に
- RA-01843 との使い分けを意識
これらの知識は、Oracle での日常開発・REST API 連携・データ移行・ETL・分析クエリ・Rails / Java / Python 開発など、あらゆる場面で活用できます。本記事をブックマークしておけば、ORA-01830 に出会っても迷わず的確に対処できるようになります。
本記事は2026年6月時点の情報をもとに、Oracle Database 19c〜23ai での動作確認・公式ドキュメントに基づき作成しています。Oracle のバージョンにより挙動が異なる場合があるため、最新の情報は Oracle 公式ドキュメント(docs.oracle.com)もあわせてご確認ください。
-
前の記事
【完全ガイド】Oracle MERGE 文 使い方|UPSERT・WHEN MATCHED・DELETE 句・差分同期まで徹底解説 2026.07.21
-
次の記事
【完全ガイド】ORA-01858: a non-numeric character was found where a numeric was expected の原因と解決方法|TO_DATE の罠・NLS_DATE_FORMAT まで徹底解説 2026.07.22
コメントを書く