Skip to content

pandas to_datetime Errors: Unable to Parse, Format Mismatch, Timezones

Tested with: pandas 2.2.3 and pandas 3.0.6 (numpy 2.5.3, python-dateutil 2.9.0.post0), Python 3.12.3, Linux. Every error message, warning and output below was copied from those runs. Last run 2026-09-27.

TL;DR, match the message you got:
  1. DateParseError: Unknown datetime string format, unable to parse: N/A: a value is not a date at all. Use pd.to_datetime(s, format="%Y-%m-%d", errors="coerce") with your real format, then inspect the NaT rows.
  2. ValueError: time data "15/01/2024" doesn't match format "%Y-%m-%d", even with no format argument: pandas guessed the format from the first row. Pass the right format, or format="ISO8601" for ISO strings of varying precision, or format="mixed" for genuinely mixed columns.
  3. Day-first data (15/01/2024): pass dayfirst=True or format="%d/%m/%Y". But do not use dayfirst=True on ISO 2024-01-02 strings: it turned them into 1 February on both versions.
  4. OutOfBoundsDatetime: Out of bounds nanosecond timestamp: 9999-12-31 (pandas 2.2 only): use s.astype("datetime64[s]"), or upgrade; pandas 3.0 parses it.
  5. tz-naive vs tz-aware errors: .dt.tz_localize("UTC") the naive side, or parse with utc=True.
What changes in pandas 3.0: parsed strings are datetime64[us], not [ns] (so .astype("int64") returns microseconds), mixed UTC offsets raise instead of warning, and infer_datetime_format, date_parser and errors="ignore" are gone.

Most pd.to_datetime failures come down to one fact that changed in pandas 2.0: the parser looks at the first non-null value, picks a format, and then holds every other row to that format. That is why a column that "obviously" contains dates raises on row 1, and why the same code can behave differently on pandas 2.2 and 3.0. Every case below was run on both versions.

pip install pandas

Error 1: DateParseError: Unknown datetime string format, unable to parse

import pandas as pd

s = pd.Series(["N/A", "2024-01-15"])
pd.to_datetime(s)
# pandas 2.2.3
UserWarning: Could not infer format, so each element will be parsed individually, falling back to `dateutil`. To ensure parsing is consistent and as-expected, please specify a format.
pandas._libs.tslibs.parsing.DateParseError: Unknown datetime string format, unable to parse: N/A, at position 0

# pandas 3.0.6: same warning, and the message drops ", at position 0"
DateParseError: Unknown datetime string format, unable to parse: N/A

This is the "unable to parse date" error. It means a value is not a date in any format pandas knows: "N/A", "not-a-date", "TBD". You get it when:

  • The junk value is the first row, so pandas cannot infer a format and falls back to parsing each element with dateutil (hence the UserWarning).
  • You parse a single string: pd.to_datetime("not-a-date") and pd.Timestamp("not-a-date") both raise it.
  • You pass format="mixed" or call s.astype("datetime64[ns]") on a column that contains junk.

If the junk is not in the first row, the same column raises a different message instead: ValueError: time data "N/A" doesn't match format "%Y-%m-%d" (Error 2). Empty strings and None are fine; both become NaT without an error.

import pandas as pd

s = pd.Series(["2024-01-15", "not-a-date", "2024-03-05", None])

# Fix: state the format and turn unparseable values into NaT
parsed = pd.to_datetime(s, format="%Y-%m-%d", errors="coerce")

# Then look at what failed instead of silently dropping it
print(s[parsed.isna() & s.notna()].tolist())
# ['not-a-date']

Passing format also removes the "Could not infer format" warning. errors="coerce" without a format works too, but it still warns and still guesses per element.


Error 2: ValueError: time data doesn't match format

import pandas as pd

dates = pd.Series(["2024-01-15", "2024-02-20", "2024-03-05"])
parsed = pd.to_datetime(dates, format="%d/%m/%Y")
# pandas 2.2.3
ValueError: time data "2024-01-15" doesn't match format "%d/%m/%Y", at position 0. You might want to try:
    - passing `format` if your strings have a consistent format;
    - passing `format='ISO8601'` if your strings are all ISO8601 but not necessarily in exactly the same format;
    - passing `format='mixed'`, and the format will be inferred for each element individually. You might want to use `dayfirst` alongside this.

# pandas 3.0.6: identical, without ", at position 0"
ValueError: time data "2024-01-15" doesn't match format "%d/%m/%Y". You might want to try: ...

The format string does not match the data. Here the data is YYYY-MM-DD but the format says DD/MM/YYYY. The match must cover the whole string, separators included. A close relative is unconverted data remains, which means the format matched the start of the string but not the end:

pd.to_datetime(pd.Series(["2024-01-15 10:30"]), format="%Y-%m-%d")
ValueError: unconverted data remains when parsing with format "%Y-%m-%d": " 10:30", at position 0. You might want to try: ...

pd.to_datetime(pd.Series(["2024-01-15 03:45 PM"]), format="%Y-%m-%d %H:%M")
ValueError: unconverted data remains when parsing with format "%Y-%m-%d %H:%M": " PM", at position 0. You might want to try: ...

Common mismatches:

  • Dashes vs slashes: 2024-01-15 vs %d/%m/%Y
  • A time part the format leaves out: 2024-01-15 10:30 vs %Y-%m-%d
  • 12-hour vs 24-hour: 03:45 PM vs %H:%M (needs %I:%M %p, which parsed to 15:45:00)

Zero padding is not a problem: ["1/5/2024", "12/25/2024"] parsed fine with format="%m/%d/%Y" on both versions.

import pandas as pd

dates = pd.Series(["2024-01-15", "2024-02-20", "2024-03-05"])

# Fix 1: correct the format string
parsed = pd.to_datetime(dates, format="%Y-%m-%d")
print(parsed)
# 0   2024-01-15
# 1   2024-02-20
# 2   2024-03-05
# dtype: datetime64[ns]    (pandas 3.0: datetime64[us])

# Fix 2: errors='coerce' turns rows that don't fit into NaT
mixed = pd.Series(["2024-01-15", "not-a-date", "2024-03-05"])
parsed = pd.to_datetime(mixed, format="%Y-%m-%d", errors="coerce")
print(parsed)
# 0   2024-01-15
# 1          NaT
# 2   2024-03-05
print(f"Failed to parse: {parsed.isna().sum()} values")
# Failed to parse: 1 values

Format codes you will use most:

# %Y  4-digit year         (2024)
# %y  2-digit year         (24)
# %m  month                (01-12)
# %d  day                  (01-31)
# %H  hour, 24h            (00-23)
# %I  hour, 12h            (01-12)
# %M  minute               (00-59)
# %S  second               (00-59)
# %f  microseconds         (000000-999999)
# %p  AM/PM
# %z  UTC offset           (+0000, -0500)
# %B  full month name      (January)

pd.to_datetime(s, format="%Y-%m-%dT%H:%M:%S")   # ISO 8601 without tz
pd.to_datetime(s, format="%d/%m/%Y %H:%M")      # UK datetime
pd.to_datetime(s, format="%b %d, %Y")           # Jan 15, 2024
pd.to_datetime(s, format="%Y%m%d")              # 20240115 (compact)

Error 3: Mixed Date Formats and dayfirst in One Column

import pandas as pd

# One column, four source systems
dates = pd.Series([
    "2024-01-15",      # ISO 8601
    "15/01/2024",      # European DD/MM/YYYY
    "January 15 2024", # Long form
    "01-15-2024",      # US MM-DD-YYYY
])

parsed = pd.to_datetime(dates)   # note: no format passed
ValueError: time data "15/01/2024" doesn't match format "%Y-%m-%d", at position 1. You might want to try: ...

No format was passed, yet the error names one. pandas inferred %Y-%m-%d from row 0 and applied it to row 1. Older answers that say "without a format pandas falls back to dateutil" describe pandas 1.x; on 2.2 and 3.0 dateutil is only used per element when the first value gives no usable format (Error 1) or when you ask for format="mixed".

The same inference causes the day-first trap:

pd.to_datetime(pd.Series(["01/02/2024", "13/02/2024"]))
ValueError: time data "13/02/2024" doesn't match format "%m/%d/%Y", at position 1. You might want to try: ...

pd.to_datetime(pd.Series(["13/02/2024", "01/03/2024"]))   # parses, but warns:
UserWarning: Parsing dates in %d/%m/%Y format when dayfirst=False (the default) was specified. Pass `dayfirst=True` or specify a format to silence this warning.

In the first case pandas read 01/02/2024 as month-first and every later day above 12 fails. In the second, the first row forced day-first and pandas warns because you did not ask for it. Both versions behave the same here.

import pandas as pd

dates = pd.Series(["2024-01-15", "15/01/2024", "January 15 2024", "01-15-2024"])

# Fix 1 (pandas 2.0+): infer the format per element
parsed = pd.to_datetime(dates, format="mixed")
print(parsed)
# 0   2024-01-15
# 1   2024-01-15
# 2   2024-01-15
# 3   2024-01-15

# Fix 2: day-first data in one format
pd.to_datetime(pd.Series(["01/02/2024", "13/02/2024"]), dayfirst=True)
# 0   2024-02-01
# 1   2024-02-13

# Fix 3: ISO 8601 strings with different precision
iso = pd.Series(["2024-01-15", "2024-01-15 10:30:00", "2024-01-15T10:30:00.123"])
pd.to_datetime(iso, format="ISO8601")
# 0   2024-01-15 00:00:00.000
# 1   2024-01-15 10:30:00.000
# 2   2024-01-15 10:30:00.123
# (without format="ISO8601" this raised: unconverted data remains ... " 10:30:00")

# Fix 4: you know the formats; try each explicitly and fill the gaps
parsed = (
    pd.to_datetime(dates, format="%Y-%m-%d", errors="coerce")
    .fillna(pd.to_datetime(dates, format="%d/%m/%Y", errors="coerce"))
    .fillna(pd.to_datetime(dates, format="%B %d %Y", errors="coerce"))
    .fillna(pd.to_datetime(dates, format="%m-%d-%Y", errors="coerce"))
)
# all four rows -> 2024-01-15 on 2.2.3 and 3.0.6
dayfirst=True swaps ISO dates. pd.to_datetime(pd.Series(["2024-01-02", "2024-03-04"]), dayfirst=True) returned 2024-02-01 and 2024-04-03 on both versions. With format="mixed", dayfirst=True the result depends on the version: pandas 2.2.3 kept 2024-01-02, pandas 3.0.6 returned 2024-02-01. If a column mixes ISO and day-first strings, parse ISO first with format="ISO8601", errors="coerce" and only apply dayfirst=True to the rows still missing (the robust parser below does this). Fix 4 is the most predictable option: every format is explicit, so nothing is guessed.

infer_datetime_format=True, which many older answers recommend, is not a fix any more: pandas 2.2.3 accepts it with a UserWarning: The argument 'infer_datetime_format' is deprecated and will be removed in a future version. A strict version of it is now the default, and pandas 3.0.6 raises TypeError: to_datetime() got an unexpected keyword argument 'infer_datetime_format'. Delete the argument.


Error 4: Out of bounds nanosecond timestamp

import pandas as pd

s = pd.Series(["2024-01-15", "9999-12-31"])   # 9999-12-31: a common "no end date" sentinel
pd.to_datetime(s)
# pandas 2.2.3
pandas._libs.tslibs.np_datetime.OutOfBoundsDatetime: Out of bounds nanosecond timestamp: 9999-12-31, at position 1. You might want to try: ...

# pandas 3.0.6: no error
0   2024-01-15
1   9999-12-31
dtype: datetime64[us]

On pandas 2.2, strings are parsed to datetime64[ns], which only spans 1677-09-21 00:12:43.145224193 to 2262-04-11 23:47:16.854775807. Years like 1500, 2300 and 9999 raise. pandas 3.0 parses strings to microsecond resolution, so the same call succeeds. It raises again on 3.0 only if you force nanoseconds: .dt.as_unit("ns") or .astype("datetime64[ns]") gave OutOfBoundsDatetime: Out of bounds nanosecond timestamp: 9999-12-31 00:00:00.

# Keep the dates (works on 2.2.3 and 3.0.6)
s.astype("datetime64[s]")
# 0   2024-01-15
# 1   9999-12-31
# dtype: datetime64[s]

# Or drop them: errors="coerce" gives NaT on 2.2.3
# (on 3.0.6 the value is in range, so it is kept, not coerced)
pd.to_datetime(s, errors="coerce")

The other common source is a wrong unit. Millisecond epochs parsed as seconds, pd.to_datetime(pd.Series([1705312800000]), unit="s"), raised OutOfBoundsDatetime: Out of bounds nanosecond timestamp: 56009-03-18 16:00:00 on 2.2.3. On 3.0.6 it silently returned the year 56009. Use unit="ms", which gave 2024-01-15 10:00:00 on both.


Error 5: TypeError: tz-naive vs tz-aware

import pandas as pd

api_dates = pd.to_datetime(["2024-01-15T10:00:00Z", "2024-02-20T14:30:00Z"])  # UTC from an API
csv_dates = pd.to_datetime(["2024-01-10", "2024-02-25"])                    # naive, from a CSV

api_dates > csv_dates[0]

The exact message depends on the operation. All of these were raised on both versions (3.0.6 prints us where 2.2.3 prints ns):

# DatetimeIndex or Series vs a naive Timestamp
TypeError: Invalid comparison between dtype=datetime64[ns, UTC] and Timestamp

# Series vs Series
TypeError: Invalid comparison between dtype=datetime64[ns, UTC] and DatetimeArray

# two scalars
TypeError: Cannot compare tz-naive and tz-aware timestamps
TypeError: Cannot subtract tz-naive and tz-aware datetime-like objects.

# join on the index
TypeError: Cannot join tz-naive with tz-aware DatetimeIndex

# merge on a column
ValueError: You are trying to merge on datetime64[ns, UTC] and datetime64[ns] columns for key 't'. If you wish to proceed you should use pd.concat

One case does not raise: == between an aware Series and a naive Timestamp just returned False. A filter built on it silently matches nothing.

Mixed UTC offsets are where the versions split. pd.to_datetime(pd.Series(["2024-01-15T10:00:00+00:00", "2024-01-15T05:00:00-05:00"])) on 2.2.3 returned an object Series with FutureWarning: In a future version of pandas, parsing datetimes with mixed time zones will raise an error unless `utc=True`. On 3.0.6 it raises:

ValueError: Mixed timezones detected. Pass utc=True in to_datetime or tz='UTC' in DatetimeIndex to convert to a common timezone.
import pandas as pd

api_dates = pd.to_datetime(["2024-01-15T10:00:00Z", "2024-02-20T14:30:00Z"])
csv_dates = pd.to_datetime(["2024-01-10", "2024-02-25"])

# Fix 1: localize the naive side. On a DatetimeIndex call .tz_localize directly;
# on a Series use .dt.tz_localize (a DatetimeIndex has no .dt and raises AttributeError)
csv_utc = csv_dates.tz_localize("UTC")
print((api_dates > csv_utc[0]).tolist())   # [True, True]

# Fix 2: drop the zone from the aware side (values stay in UTC wall time)
api_naive = pd.Series(api_dates).dt.tz_localize(None)

# Fix 3: normalize at parse time. With offsets and plain dates in one column,
# add format="ISO8601": utc=True alone raised
# ValueError: time data "2024-01-10" doesn't match format "%Y-%m-%dT%H:%M:%S%z"
all_dates = pd.to_datetime(
    pd.Series(["2024-01-15T10:00:00Z", "2024-02-20T14:30:00+05:30", "2024-01-10"]),
    format="ISO8601", utc=True,
)
print(all_dates)
# 0   2024-01-15 10:00:00+00:00
# 1   2024-02-20 09:00:00+00:00
# 2   2024-01-10 00:00:00+00:00
# dtype: datetime64[ns, UTC]    (pandas 3.0: datetime64[us, UTC])

In a DataFrame, fix it per column, and do the same before a merge:

import pandas as pd

df = pd.DataFrame({
    "created_at": ["2024-01-15T10:00:00Z", "2024-02-20T14:30:00Z"],
    "local_date": ["2024-01-10", "2024-02-25"],
})

df["created_at"] = pd.to_datetime(df["created_at"], utc=True)
df["local_date"] = pd.to_datetime(df["local_date"]).dt.tz_localize("UTC")

print((df["created_at"] > df["local_date"]).tolist())   # [True, False]

read_csv: parse_dates and date_format

import io
import pandas as pd

csv = "id,when,amount\n1,15/01/2024,10\n2,20/02/2024,20\n3,N/A,30\n"

pd.read_csv(io.StringIO(csv), parse_dates=["when"])
# UserWarning: Parsing dates in %d/%m/%Y format when dayfirst=False (the default) was specified. ...

pd.read_csv(io.StringIO(csv), parse_dates=["when"], date_format="%d/%m/%Y")["when"].tolist()
# [Timestamp('2024-01-15 00:00:00'), Timestamp('2024-02-20 00:00:00'), NaT]
  • date_format="..." (pandas 2.0+) or dayfirst=True fixes the warning on both versions. "N/A" is a default missing-value marker, so it became NaT.
  • date_parser= is gone: 2.2.3 warned FutureWarning: The argument 'date_parser' is deprecated, and 3.0.6 raised TypeError: read_csv() got an unexpected keyword argument 'date_parser'.
  • read_csv does not raise on junk. With a row containing garbage, parse_dates (even with date_format) left the whole column unparsed: object dtype on 2.2.3, str dtype on 3.0.6. The error then shows up later, in a .dt accessor or a comparison. Check df.dtypes, or read the column as text and parse it yourself:
df = pd.read_csv(io.StringIO(csv))
df["when"] = pd.to_datetime(df["when"], format="%d/%m/%Y", errors="coerce")
# [Timestamp('2024-01-15 00:00:00'), Timestamp('2024-02-20 00:00:00'), NaT]  on 2.2.3 and 3.0.6

Reproduced: pandas 2.2 vs 3.0

Each call ran in a fresh virtualenv on Linux (Python 3.12.3, numpy 2.5.3). s(...) is shorthand for pd.Series([...]).

Input / callpandas 2.2.3pandas 3.0.6Fix (verified on both)
to_datetime(s("N/A", "2024-01-15"))DateParseError: Unknown datetime string format, unable to parse: N/A, at position 0same, without positionformat="%Y-%m-%d", errors="coerce"
to_datetime(s("2024-01-15", "N/A"))ValueError: time data "N/A" doesn't match format "%Y-%m-%d", at position 1same, without positionerrors="coerce"
to_datetime(s("2024-01-15", "15/01/2024"))ValueError: time data "15/01/2024" doesn't match format "%Y-%m-%d"sameformat="mixed" or explicit formats + fillna
to_datetime(s("01/02/2024", "13/02/2024"))ValueError: ... doesn't match format "%m/%d/%Y"samedayfirst=True
to_datetime(s("2024-01-02"), dayfirst=True)2024-02-01 (swapped)2024-02-01 (swapped)drop dayfirst for ISO rows
format="mixed", dayfirst=True on "2024-01-02"2024-01-022024-02-01 (swapped)parse ISO first, then day-first
to_datetime(s("2024-01-15", "2024-01-15 10:30:00"))ValueError: unconverted data remains ... " 10:30:00"sameformat="ISO8601"
to_datetime(s("9999-12-31"))OutOfBoundsDatetime: Out of bounds nanosecond timestampparses, datetime64[us].astype("datetime64[s]")
to_datetime(s(1705312800000), unit="s")OutOfBoundsDatetimeyear 56009, no errorunit="ms"
dtype of to_datetime(s("2024-01-15"))datetime64[ns]datetime64[us]check before .astype("int64")
.astype("int64") of 2024-01-151705276800000000000 (ns)1705276800000000 (us).dt.as_unit("ns").astype("int64")
mixed offsets, no utcobject dtype + FutureWarningValueError: Mixed timezones detectedutc=True
aware vs naive comparisonTypeError: Invalid comparison between dtype=datetime64[ns, UTC] and Timestampsame, with us.dt.tz_localize("UTC")
infer_datetime_format=TrueUserWarning (deprecated)TypeError: unexpected keyword argumentdelete it
read_csv(date_parser=...)FutureWarning (deprecated)TypeError: unexpected keyword argumentdate_format=
errors="ignore"FutureWarning, returns object dtypebare AssertionErrorerrors="coerce"

Excel Serials, Unix Epochs and ISO Offsets

Excel Serial Dates

Excel stores dates as a day count. If pd.read_excel() (or a CSV export) gives you values like 45306, you have serial dates.

import pandas as pd

excel_serials = pd.Series([45306, 45352, 45385])
parsed = pd.to_datetime(excel_serials, unit="D", origin="1899-12-30")
print(parsed.tolist())
# [Timestamp('2024-01-15 00:00:00'), Timestamp('2024-03-01 00:00:00'), Timestamp('2024-04-03 00:00:00')]

The origin is 1899-12-30 rather than 1900-01-01 to absorb Excel's 1900 leap-year bug. If your dates come out a day or two off, check the origin first.

Unix Timestamps

import pandas as pd

unix_seconds = pd.Series([1705312800, 1708430400])
parsed = pd.to_datetime(unix_seconds, unit="s")
print(parsed.tolist())
# [Timestamp('2024-01-15 10:00:00'), Timestamp('2024-02-20 12:00:00')]
# dtype: datetime64[ns] on 2.2.3, datetime64[s] on 3.0.6

# Milliseconds (JavaScript, many APIs): unit="ms"; microseconds: unit="us"

Epochs stored as text need unit too: pd.to_datetime(pd.Series(["1705312800"])) raised DateParseError: year 1705312800 is out of range: 1705312800. Convert with pd.to_numeric first, then pass unit="s".

ISO 8601 with Timezone Offsets

import pandas as pd

iso_dates = pd.Series([
    "2024-01-15T10:00:00Z",
    "2024-01-15T05:00:00-05:00",   # US Eastern, same instant
    "2024-01-15T18:30:00+08:30",   # +08:30, same instant
])

parsed = pd.to_datetime(iso_dates, utc=True)
print(parsed)
# 0   2024-01-15 10:00:00+00:00
# 1   2024-01-15 10:00:00+00:00
# 2   2024-01-15 10:00:00+00:00

print(parsed.dt.tz_convert("America/New_York"))
# 0   2024-01-15 05:00:00-05:00
# ...

A Parser for Columns You Do Not Trust

When you cannot trust the input, handle each kind of value on purpose. This version parses ISO strings before day-first strings, for the dayfirst reason above. The earlier version of this post let 15/01/2024 fall through to NaT; this one was run on both pandas versions with identical output and no warnings.

import pandas as pd

def parse_dates_robust(series: pd.Series, timezone: str = "UTC") -> pd.Series:
    """Unix seconds, Excel serials, ISO 8601 and day-first strings -> tz-aware; failures -> NaT."""
    num = pd.to_numeric(series, errors="coerce")
    out = pd.Series(pd.NaT, index=series.index, dtype="datetime64[ns, UTC]")

    unix = num > 100_000                    # ~1.7e9 for 2024; Excel serials are ~45,000
    excel = num.notna() & ~unix
    if unix.any():
        out[unix] = pd.to_datetime(num[unix], unit="s", utc=True)
    if excel.any():
        out[excel] = pd.to_datetime(num[excel], unit="D", origin="1899-12-30").dt.tz_localize("UTC")

    strs = num.isna() & series.notna()
    if strs.any():
        s = series[strs].astype(str)
        # ISO first: dayfirst=True would swap 2024-01-02 into 1 February
        iso = pd.to_datetime(s, format="ISO8601", utc=True, errors="coerce")
        rest = pd.to_datetime(s[iso.isna()], format="mixed", dayfirst=True, utc=True, errors="coerce")
        out[strs] = iso.fillna(rest)
    return out.dt.tz_convert(timezone)

df = pd.DataFrame({"date_col": [
    "2024-01-15T10:00:00Z", "2024-01-02", "15/01/2024", 1705312800, 45306, "bad date", None,
]})
df["parsed"] = parse_dates_robust(df["date_col"])
print(df)
print("failures:", int(df["parsed"].isna().sum()))
               date_col                    parsed
0  2024-01-15T10:00:00Z 2024-01-15 10:00:00+00:00
1            2024-01-02 2024-01-02 00:00:00+00:00
2            15/01/2024 2024-01-15 00:00:00+00:00
3            1705312800 2024-01-15 10:00:00+00:00
4                 45306 2024-01-15 00:00:00+00:00
5              bad date                       NaT
6                  None                       NaT
failures: 2

Quick Reference: errors Parameter Values

import pandas as pd

s = pd.Series(["2024-01-15", "not-a-date", "2024-03-01"])

# errors="raise" (default): raises on the first failure
# pd.to_datetime(s, format="%Y-%m-%d")  -> ValueError: time data "not-a-date" doesn't match format ...

# errors="coerce": failures become NaT
pd.to_datetime(s, format="%Y-%m-%d", errors="coerce")
# 0   2024-01-15
# 1          NaT
# 2   2024-03-01

errors="ignore" returned the input unchanged as an object Series on pandas 2.2.3, with FutureWarning: errors='ignore' is deprecated and will raise in a future version. Use to_datetime without passing `errors` and catch exceptions explicitly instead. On pandas 3.0.6 it failed with a bare AssertionError and no message, which is hard to trace back to this argument. Replace it with errors="coerce" plus an explicit check of the NaT rows, or a try/except ValueError.


The pattern underneath all of these

Nearly every case above is pandas guessing: a format from the first row, month-first vs day-first, a time zone, a unit. On pandas 2.2 a wrong guess usually raises. On pandas 3.0 a few of them (the year 56009 from a wrong unit, int64 values in microseconds) now pass without an error, which is worse. State the format, dayfirst, unit and utc you actually mean.

In a pipeline, pair errors="coerce" with a check such as assert df["date"].isna().sum() == 0 (or an acceptable NaT threshold) so bad rows are counted instead of silently dropped.