Skip to content
Laviyx Learn

Try

Python for Data course menu

Dates and Time Series in pandas: to_datetime, dt and resample

Work with dates in pandas: parse dates, extract year, month and weekday with .dt, date arithmetic with Timedelta, date ranges, filtering by date, a DatetimeIndex, and resampling daily data to weekly or monthly totals.

Intermediate9 min readUpdated
On this page

Sales per month, sign-ups per weekday, days since last purchase: time is part of most business questions. pandas has a full set of tools for dates once a column has the datetime type.

Parsing dates#

Python
import pandas as pd

orders = pd.DataFrame({
    "ordered": ["2026-01-05", "2026-01-28", "2026-02-11", "2026-03-02", "2026-03-30"],
    "amount": [250, 120, 560, 90, 310],
})
orders["ordered"] = pd.to_datetime(orders["ordered"])
print(orders.dtypes)
Output
ordered    datetime64[ns]
amount              int64
dtype: object

ISO dates (YYYY-MM-DD) parse without a format. For anything else, pass format= (see Data Types).

The dt accessor#

.dt gives every date part as a column:

Python
import pandas as pd

orders = pd.DataFrame({
    "ordered": pd.to_datetime(["2026-01-05", "2026-01-28", "2026-02-11", "2026-03-02", "2026-03-30"]),
    "amount": [250, 120, 560, 90, 310],
})
orders["year"] = orders["ordered"].dt.year
orders["month"] = orders["ordered"].dt.month
orders["weekday"] = orders["ordered"].dt.day_name()
orders["quarter"] = orders["ordered"].dt.quarter
orders["month_label"] = orders["ordered"].dt.strftime("%b %Y")
print(orders)
print(orders.groupby("month_label", sort=False)["amount"].sum())
Output
     ordered  amount  year  month    weekday  quarter month_label
0 2026-01-05     250  2026      1     Monday        1    Jan 2026
1 2026-01-28     120  2026      1  Wednesday        1    Jan 2026
2 2026-02-11     560  2026      2  Wednesday        1    Feb 2026
3 2026-03-02      90  2026      3     Monday        1    Mar 2026
4 2026-03-30     310  2026      3     Monday        1    Mar 2026
month_label
Jan 2026    370
Feb 2026    560
Mar 2026    400
Name: amount, dtype: int64

strftime formats dates as text with the same codes used for parsing.

Date arithmetic#

Subtracting dates gives a Timedelta; adding a Timedelta or DateOffset moves dates:

Python
import pandas as pd

ordered = pd.to_datetime(pd.Series(["2026-01-05", "2026-02-11", "2026-03-30"]))
today = pd.Timestamp("2026-04-01")

print((today - ordered).dt.days.tolist())                  # days since each order
print((ordered + pd.Timedelta(days=7)).dt.date.tolist())    # due a week later
print((ordered + pd.DateOffset(months=1)).dt.date.tolist()) # same day next month
print(ordered.dt.to_period("M").tolist())
Output
[86, 49, 2]
[datetime.date(2026, 1, 12), datetime.date(2026, 2, 18), datetime.date(2026, 4, 6)]
[datetime.date(2026, 2, 5), datetime.date(2026, 3, 11), datetime.date(2026, 4, 30)]
[Period('2026-01', 'M'), Period('2026-02', 'M'), Period('2026-03', 'M')]

DateOffset(months=1) respects calendar months, which a fixed number of days cannot. to_period("M") labels each date with its month.

Date ranges#

Python
import pandas as pd

print(pd.date_range("2026-03-01", periods=5, freq="D").date.tolist())
print(pd.date_range("2026-01-01", "2026-06-30", freq="MS").strftime("%b").tolist())
print(pd.date_range("2026-03-02", periods=3, freq="W-MON").date.tolist())
Output
[datetime.date(2026, 3, 1), datetime.date(2026, 3, 2), datetime.date(2026, 3, 3), datetime.date(2026, 3, 4), datetime.date(2026, 3, 5)]
['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun']
[datetime.date(2026, 3, 2), datetime.date(2026, 3, 9), datetime.date(2026, 3, 16)]

Frequency codes: D day, W-MON weekly on Mondays, MS month start, ME month end, QE quarter end, h hour. (Older pandas used M and Q; recent versions want ME and QE for month and quarter ends.)

A DatetimeIndex and filtering#

Setting the date as the index makes time-based selection easy:

Python
import numpy as np
import pandas as pd

rng = np.random.default_rng(3)
daily = pd.Series(rng.integers(80, 160, size=90),
                  index=pd.date_range("2026-01-01", periods=90, freq="D"), name="visitors")
print(daily.head(3))
print(daily.loc["2026-02"].sum())                       # all of February
print(daily.loc["2026-03-10":"2026-03-12"])              # a date range (inclusive)
print(daily[daily.index.dayofweek >= 5].mean().round(1))  # weekends only
Output
2026-01-01    144
2026-01-02     86
2026-01-03     94
Freq: D, Name: visitors, dtype: int64
3331
2026-03-10    154
2026-03-11     96
2026-03-12    128
Freq: D, Name: visitors, dtype: int64
119.1

Resampling#

resample is groupby for time: it groups by calendar periods. Daily data can become weekly or monthly totals in one line:

Python
import numpy as np
import pandas as pd

rng = np.random.default_rng(3)
daily = pd.Series(rng.integers(80, 160, size=90),
                  index=pd.date_range("2026-01-01", periods=90, freq="D"), name="visitors")
monthly = daily.resample("ME").sum()
monthly.index = monthly.index.strftime("%b")
print(monthly)
print(daily.resample("W-SUN").mean().round(1).head(3))
Output
Jan    3566
Feb    3331
Mar    3784
Name: visitors, dtype: int64
2026-01-04    105.5
2026-01-11    112.7
2026-01-18    118.1
Freq: W-SUN, Name: visitors, dtype: float64

Grouping without a DatetimeIndex#

If the date is a regular column, group by a period instead:

Python
import pandas as pd

orders = pd.DataFrame({
    "ordered": pd.to_datetime(["2026-01-05", "2026-01-28", "2026-02-11", "2026-03-02", "2026-03-30"]),
    "amount": [250, 120, 560, 90, 310],
})
print(orders.groupby(orders["ordered"].dt.to_period("M"))["amount"].agg(["sum", "count"]))
print(orders.groupby(pd.Grouper(key="ordered", freq="QE"))["amount"].sum())
Output
         sum  count
ordered
2026-01  370      2
2026-02  560      1
2026-03  400      2
ordered
2026-03-31    1330
Freq: QE-DEC, Name: amount, dtype: int64

Common mistakes#

Practice#

Practice exercise

Sign-up dates are ["2026-01-03", "2026-01-15", "2026-02-01", "2026-02-14", "2026-02-20", "2026-04-02"]. Print the number of sign-ups per month including months with none (January to April), and the weekday on which most sign-ups happened.

Show hint

Make a Series of 1s indexed by the dates and resample("ME").sum(). For weekdays, dt.day_name().value_counts().idxmax().

Show solution
Python
import pandas as pd

dates = pd.to_datetime(pd.Series(["2026-01-03", "2026-01-15", "2026-02-01", "2026-02-14", "2026-02-20", "2026-04-02"]))
per_month = pd.Series(1, index=dates).resample("ME").sum()
per_month.index = per_month.index.strftime("%b")
print(per_month)
print(dates.dt.day_name().value_counts().idxmax())
Output
Jan    2
Feb    3
Mar    0
Apr    1
dtype: int64
Saturday

March appears with 0 because resample creates every month in the range.

Key takeaway#

Next: Rolling Windows and Cumulative Values.

Finished this lesson?