Skip to content
Start free

How do I convert text to dates in pandas and DuckDB?

Tell pandas and DuckDB exactly how to read your dates, and decide what to do with the ones that can't be read.

Free course. Your Maestro, an AI, .

A format is an instruction

You already know ventas_exportadas puts the day first. Now tell the program. A format describes the text piece by piece, with codes that start with %:

CodeWhat it readsExample
%dday of the month, two digits05
%mmonth, two digits02
%Yyear, four digits2026
%Hhour from 00 to 2320
%Mminute44
%Ssecond40

Anything that isn't a code is matched as is. 05/02/2026 is described as %d/%m/%Y: day, a slash, month, a slash, year. pandas and DuckDB use the same codes for these pieces.

pd.to_datetime takes the format in format:

Python
data["fecha"] = pd.to_datetime(data["fecha"], format="%d/%m/%Y")

The column goes from str to datetime64.

strptime takes the text and the format, and returns a TIMESTAMP. Since there's no time here, turn it into a DATE with ::DATE:

SQL
SELECT strptime(fecha, '%d/%m/%Y')::DATE AS fechaFROM ventas_exportadas;

Cleaning up the fecha column in ventas_exportadas

Worked example · 5 steps

Convert the fecha column from text to a date and check that the conversion came out right.

Work out the next step yourself, then open it to compare.

What doesn't fit the format

A real file almost always has some value that doesn't fit: a day that doesn't exist, a date written another way, an empty cell. With pd.to_datetime and an explicit format, a nonempty incompatible value stops conversion with ValueError. Missing values ("", None) become NaT even without coerce. Sometimes that's what you want. Other times you'd rather convert what you can and look at the rest separately. Predict what errors="coerce" does.

Five strings and an explicit format. Write what you think it prints and why.

Five values, one of each kind

coerce.py
import pandas as pdfechas = pd.Series(["28/02/2026", "31/02/2026", "1/3/2026", "2026-03-05", ""])print(pd.to_datetime(fechas, format="%d/%m/%Y", errors="coerce"))

A guess is fine. What you write stays in this browser and waits in your course.

NaT means there is no date: it may be an original absence or a value that could not be converted. Keep the original column, count original absences and new failures separately, and inspect them before moving on; a of those rows tells you whether it's an empty cell or a different format you need to convert separately. Not sure what to do with your rows without a date? Ask your Maestro.

DuckDB gives you both options as two functions: strptime stops with an error at the first value that doesn't fit (with 31/02/2026 it says Date out of range), and try_strptime returns NULL instead. An original NULL remains NULL. If you use read_csv(parse_dates=...), check the type afterward: an incompatible value can leave the entire column as text without raising that error; it does not behave the same way as to_datetime.

Warning: dayfirst is not a format

pandas also accepts dayfirst=True. The pandas documentation warns that it isn't strict: it prefers to read the day first, but doesn't guarantee it. An explicit format isn't a preference, it's an instruction.

Try it

Now with less help. The query adds up sales by day, but it groups and sorts by the text column. Change it so it converts fecha with its format, calls the result dia, and sorts by the real date.

A good answer has 22 rows, one for each day with sales, from 2026-01-02 to 2026-03-28 in order. If you converted the date and the days are still out of order, tell your Maestro what you put in GROUP BY and ORDER BY.

Your turn

Add up total sales by day, with the converted date (call it dia) in chronological order.

Tables: ventas_exportadas (folio, fecha, sucursal, total)

ventas_exportadas · 29 rows

ColumnType
folio Número de ticket del punto de venta.BIGINT
fecha La fecha tal como la exporta el punto de venta: texto en formato día/mes/año (dd/mm/aaaa).VARCHAR
sucursal Roma, Coyoacán o Del Valle.VARCHAR
total Total del ticket en pesos.BIGINT

First rows

foliofechasucursaltotal
100102/01/2026Roma460
100205/01/2026Roma120
100305/01/2026Del Valle120

Try it on your own

Now in pandas, from scratch: convert the fecha column in ventas_exportadas, then print the earliest date, the latest date, and how many rows ended up without a date. A good answer prints January 2 and March 28, 2026, and 0 rows without a date.

Then try a small column containing 28/02/2026, an empty string and 31/02/2026. Preserve the original, identify absences before conversion, use coerce and count only new failures. Distinguish one original absence from one incompatible value, and show 31/02/2026 as the text that failed.

Your turn

Convert the fecha column with its explicit format. Print the earliest date, the latest date, and how many rows ended up without a date. Then, using the three-value sample in the instructions, print original absences and conversion failures separately, and show the original that failed.

Data: ventas-exportadas, 29 rows
The exercise's data, "ventas-exportadas". Your edits run with your code.
RowRemove
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Page 1 of 2

Think of a file with dates that you use at work. What format do the dates come in, and how would you check that against the data before converting them?

Reflect: Think of a file with dates that you use at work. What format do the dates come in, and how would you check that against the data before converting them?

Only you and your Maestro read this. It's kept on your account and deleted with it.

Write your answer