Skip to content
Start free

How do I group sales by month and by quarter?

Group sales by month and by quarter without lumping one year's January in with the next: truncate each date to the start of its period in pandas and DuckDB.

Free course. Your Maestro, an AI, .

Sales for every day

For this module, Café Altura hands you ventas_diarias (daily sales): what each shop sold each day, from January 2025 to June 2026. That's 1,598 synthetic rows, and each row is one shop on one day: that's the table's . The fecha column is already a date.

Almost nobody reads a report by day. Management wants months and quarters. To get there, you give each date the label of its period and add up by label. The question is which label. Make a prediction.

Four sales across two years and two ways to group them by month. Write what you think each program prints and why.

Four sales across two years and two ways to group them by month. Write what you think each program prints and why.

Grouping by dt.month

Example 1 of 2

numero_de_mes.py
import pandas as pd

ventas = pd.DataFrame({
    "fecha": pd.to_datetime(["2025-01-15", "2025-02-10", "2026-01-20", "2026-02-05"]),
    "ventas": [100, 200, 300, 400],
})
print(ventas.groupby(ventas["fecha"].dt.month)["ventas"].sum())

A guess is fine: it's kept as you wrote it, so you can compare. Only you and your Maestro see your predictions.

Example 2 of 2, opens once you explain this one

Make your prediction

A month belongs to a year

The first program makes a mistake you won't notice with one year of data, and it shows up as soon as the table crosses December. In ventas_diarias, grouping by month number lumps January 2025 in with January 2026, and so on through June. Grouping by quarter with quarter(fecha) does the same thing: Q1 2025 and Q1 2026 add up to 6,529,310 pesos in a single group.

The label that works is the whole period. In pandas, to_period does it. In SQL you truncate: cut the date back to the first day of its period. March 17, 2026 truncated to the month is 2026-03-01; May 17 truncated to the quarter is 2026-04-01, the first day of Q2. Every date in the same period gets the same label, and the label is still a date that sorts correctly. Ask your Maestro to truncate a date with you, to the month and to the quarter, step by step.

Python
data["mes"] = data["fecha"].dt.to_period("M")
data["trimestre"] = data["fecha"].dt.to_period("Q")
por_mes = data.groupby("mes")["ventas"].sum()

A quarter prints as 2025Q1. If you need a date instead of a period, .dt.to_timestamp() gives you the first day.

SQL
SELECT
  date_trunc('month', fecha)::DATE AS mes,
  sum(ventas) AS ventas
FROM ventas_diarias
GROUP BY mes
ORDER BY mes;

date_trunc always returns a TIMESTAMP; ::DATE drops the 00:00:00 time. For quarters, use date_trunc('quarter', fecha).

Try it

The query adds up sales by quarter with quarter(fecha), which is just the quarter number. Change it so each quarter of each year is its own group, with a trimestre (quarter) column holding the date of its first day. A good answer has six rows, from 2025-01-01 to 2026-04-01.

Add up sales by calendar quarter, with trimestre as the date of the first day of each quarter.

Your turn

Add up sales by calendar quarter, with trimestre as the date of the first day of each quarter.

Tables: ventas_diarias (fecha, sucursal, ventas)

ventas_diarias · 1,598 rows

ColumnType
fecha El día de la venta.DATE
sucursal Roma, Coyoacán o Del Valle.VARCHAR
ventas Ventas del día en pesos.BIGINT

First rows

fechasucursalventas
2025-01-02Roma12120
2025-01-02Coyoacán10650
2025-01-02Del Valle8880

Every run starts from fresh copies of the course's tables, so try anything.

Ready to run your query.

Run it yourself

Try it on your own

Now in pandas, from scratch: add up the whole chain's sales by month and print the month with the most sales and how much it sold. A good answer gives December 2025. If you get January or a number from 1 to 12, share your code with your Maestro.

Add up the whole chain's sales by calendar month and print the month with the most sales and its total.

Add up the whole chain's sales by calendar month and print the month with the most sales and its total.

Run your code to see what it prints and the value of its last expression. Every run starts fresh.

Ready to run your code.

Run your code to see its output here.

Data: ventas-diarias, 1,598 rows

Enter saves a cell and Escape leaves it as it was. Leave a cell empty for a missing value.

The exercise's data, "ventas-diarias". 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 80

Run it yourself

Check yourself: ventas_diarias runs from January 2025 to June 2026. If you group with GROUP BY month(fecha), how many groups come out?