PostgreSQL Error 22007: invalid datetime format
PostgreSQL error code 22007 (invalid_datetime_format) is thrown when a string value cannot be parsed into a date/time type because its format doesn't match what PostgreSQL expects. This commonly happens during data ingestion, ETL pipelines, or application inserts where date strings aren't normalized before being passed to the database. PostgreSQL defaults to ISO 8601 (YYYY-MM-DD), so any deviation without explicit formatting instructions will trigger this error.
Top 3 Causes
1. Inserting Non-Standard Date Strings Directly
Passing date strings in formats like DD/MM/YYYY or MM-DD-YYYY directly into a DATE or TIMESTAMP column without conversion is the most common cause.
-- This will fail
INSERT INTO orders (order_date) VALUES ('15/03/2024');
-- ERROR: invalid input syntax for type date: "15/03/2024"
-- Fix: use TO_DATE() with the correct format mask
INSERT INTO orders (order_date) VALUES (TO_DATE('15/03/2024', 'DD/MM/YYYY'));
-- Or normalize to ISO 8601 first
INSERT INTO orders (order_date) VALUES ('2024-03-15');
2. Mismatched Format Mask in TO_DATE() / TO_TIMESTAMP()
Using a format mask that doesn't match the actual structure of the input string will also raise 22007. The delimiters, field order, and separators must all match exactly.
-- This will fail: delimiters don't match
SELECT TO_DATE('2024-03-15', 'MM/DD/YYYY');
-- ERROR: invalid value "03-" for "MM/"
-- Fix: align the format mask with the actual data
SELECT TO_DATE('2024-03-15', 'YYYY-MM-DD'); -- correct
SELECT TO_DATE('03/15/2024', 'MM/DD/YYYY'); -- correct (US style)
SELECT TO_TIMESTAMP('2024-03-15 14:30:00', 'YYYY-MM-DD HH24:MI:SS'); -- correct
3. Timezone Mismatch Between String and Column Type
Inserting a timezone-aware string (e.g., '2024-03-15 10:30:00+09') into a TIMESTAMP WITHOUT TIME ZONE column, or vice versa, can cause parsing failures or unexpected behavior.
-- Potential issue: timezone offset in a non-tz column context
INSERT INTO local_events (event_time) VALUES ('2024-03-15 10:30:00+09');
-- Fix: strip the timezone offset for TIMESTAMP columns
INSERT INTO local_events (event_time) VALUES ('2024-03-15 10:30:00'::TIMESTAMP);
-- For TIMESTAMPTZ columns, use explicit casting
INSERT INTO global_events (event_time)
VALUES ('2024-03-15 10:30:00+09:00'::TIMESTAMPTZ);
-- Or use AT TIME ZONE for clarity
INSERT INTO global_events (event_time)
VALUES ('2024-03-15 10:30:00' AT TIME ZONE 'Asia/Seoul');
Quick Fix Solutions
If you're dealing with a bulk load of mixed-format dates, use a staging table and classify formats before converting:
-- Classify date formats in a staging table
SELECT
CASE
WHEN raw_date ~ '^\d{4}-\d{2}-\d{2}$' THEN TO_DATE(raw_date, 'YYYY-MM-DD')
WHEN raw_date ~ '^\d{2}/\d{2}/\d{4}$' THEN TO_DATE(raw_date, 'MM/DD/YYYY')
WHEN raw_date ~ '^\d{8}$' THEN TO_DATE(raw_date, 'YYYYMMDD')
ELSE NULL
END AS parsed_date,
raw_date
FROM staging_table;
Prevention Tips
Always use ISO 8601 format at the application layer. Bind native date/time objects from your programming language (Python
datetime, JavaLocalDate, etc.) rather than constructing raw date strings. This eliminates format ambiguity entirely and is the single most effective prevention strategy.Profile your data before bulk loads. Run a format-detection query on staging data before committing to production tables. Add a pre-load validation step to your ETL pipeline that rejects or flags rows with unrecognized date patterns, preventing cascading failures on large datasets.
Related Errors
-
22008
datetime_field_overflow— Fired when a date value is logically out of range (e.g., month 13, day 32). -
22P02
invalid_text_representation— Occurs when a string cannot be interpreted as any valid type at all, a more fundamental casting failure than 22007. -
42883
undefined_function— Can appear when attempting workarounds for date conversion using functions with incompatible argument types.
📖 Want a more detailed guide?
Check out the full in-depth version (Korean) on oraerror.com — includes detailed analysis, additional SQL examples, and prevention tips.
Top comments (0)