2025, Oct 20 15:00

Why pandas to_csv date_format fails with Python date objects and how to export formatted dates

Learn why pandas to_csv date_format is ignored for Python date objects and how to fix it by converting to datetime or using Arrow-backed date types. Examples.

Exporting dates from pandas to CSV and expecting date_format to kick in can be disappointing when the data is made of pure Python date objects. The formatter silently does nothing, and you end up with ISO-like dates. Here is why this happens and how to fix it without changing your data pipeline semantics.

The symptom

You ask pandas to format dates on export, but the output doesn’t reflect the requested pattern:

import pandas as p
import datetime as dt
sheet = p.DataFrame([dt.datetime.now().date()])
text_csv = sheet.to_csv(date_format="%Y %b")
print(text_csv)
# Output
#,0
#0,2025-07-31

The CSV shows the raw date: 2025-07-31, not the expected 2025 Jul.

What actually happens under the hood

Pandas doesn’t natively support the standalone date type yet. It is built on top of NumPy, which has a single 64-bit datetime type, datetime64[ns]. Plain date values are therefore stored as Object. That is the key reason the datetime-aware features, including the .dt accessor and date_format in to_csv, don’t apply to such columns.

Reproducing the type mismatch

If you probe the dtype, you’ll see the mismatch immediately. A date ends up as object, while datetime lands as datetime64[ns]. This difference is exactly what blocks the formatter.

import pandas as p
from datetime import date
col = p.Series([date.today()])
print(col.dtype)
# Output
# object

Trying to format it with .dt confirms it isn’t recognized as datetimelike:

col.dt.strftime("%Y %b")
# ...
# AttributeError: Can only use .dt accessor with datetimelike values. Did you mean: 'at'?

Solution and working examples

The fix is to convert the object-based values into a datetime-aware dtype first, and then format. Once you have a datetimelike series, strftime works as expected. You can then write the already formatted strings to CSV.

import pandas as p
from datetime import date
raw_dates = p.Series([date.today()])
formatted = p.to_datetime(raw_dates).dt.strftime("%Y %b")
print(formatted)
# Output
# 0    2025 Jul

If you prefer a type that natively understands dates, you can use an Arrow-backed series and still apply strftime directly.

import pandas as p
from datetime import date
arrow_dates = p.Series([date.today()], dtype="date32[pyarrow]")
pretty = arrow_dates.dt.strftime("%Y %b")
print(pretty)
# Output
# 0    2025 Jul
# dtype: string[pyarrow]

Why it matters

CSV exports sit at the boundary between systems. If your pipeline relies on consistent date formatting, silently writing object-based dates can lead to downstream parsing surprises. Knowing that plain date values are stored as object, not datetimelike, helps you avoid brittle exports and unexpected errors when using .dt operations.

Takeaways

If date_format in to_csv doesn’t apply, check the dtype first. When you see object, convert to a datetime-aware type, format via strftime, and export. Alternatively, opt into an Arrow-backed date series to get date semantics from the start. Either path restores predictable, explicit control over how your dates look in CSV.

The article is based on a question from StackOverflow by Hugo Trentesaux and an answer by Panagiotis Kanavos.