Skip to content

pandas dt.dayofweek

Want to know the day from a Pandas datetime column? You can use dt.dayofweek. But watch out: Monday is 0 and Sunday is 6. If you aren't expecting those numbers, you could be in for a surprise or two.

What it does

.dt.dayofweek returns the day of the week as an int32, and it counts from Monday: Monday is 0, Tuesday 1, and Sunday is 6. That matches Python's own datetime.weekday(), and it is not going to change.

I start my week on Sunday. So does the calendar on my phone, and so does Excel's WEEKDAY. Pandas' numbering is a fact about Pandas, not a fact about weeks, and the whole job here is keeping the two apart.

.dt.day_of_week and .dt.weekday are aliases.

Official documentation: Series.dt.dayofweek.

A worked example, on real data

Wikimedia publishes daily pageview counts for every Wikipedia, free and without a key. A year of the Hebrew Wikipedia is 365 rows, and its readers keep an Israeli week — Sunday through Thursday are workdays, and the weekend is Friday and Saturday:

import pandas as pd

url = ('https://wikimedia.org/api/rest_v1/metrics/pageviews/aggregate/'
       'he.wikipedia/all-access/user/daily/20250101/20251231')

df = (pd
      .json_normalize(pd.read_json(url,
                      storage_options={'User-Agent': 'Mozilla/5.0'})['items'])
      .assign(date=lambda df_: pd.to_datetime(df_['timestamp'],
                                              format='%Y%m%d%H'))
      [['date', 'views']])

df.groupby(df['date'].dt.dayofweek)['views'].mean().round().astype(int)
date
0    1818144
1    1833972
2    1822092
3    1814446
4    1822678
5    1944397
6    1898744
Name: views, dtype: int64

There's nothing technically wrong with this result. But the two busiest days are 5 and 6, and I personally never remember that these refer to Saturday and Sunday. If you want the day numbers to start with 0 for Sunday, you can use mod and rename. Or you can just invoke dt.day_name(), and get the names:

(df
 .groupby([df['date'].dt.dayofweek.add(1).mod(7).rename('n'),
           df['date'].dt.day_name().rename('day')])['views']
 .mean().round().astype(int)
 .reset_index('day'))
         day    views
n
0     Sunday  1898744
1     Monday  1818144
2    Tuesday  1833972
3  Wednesday  1822092
4   Thursday  1814446
5     Friday  1822678
6   Saturday  1944397

Identical numbers, and now the shape is legible: five flat workdays around 1.82 million, Sunday a little above them, and a real spike on Saturday, when nobody in Israel is at work.

Mistakes people make

>= 5 as a weekend test. It means Saturday and Sunday, which is indeed the weekend in most countries — but not everywhere:

df.loc[df['date'].dt.dayofweek >= 5, 'views'].mean().round().astype(int)
df.loc[df['date'].dt.dayofweek.isin([4, 5]), 'views'].mean().round().astype(int)
1921570
1883537

Depending on where you are, you might need to use the second query, rather than the first.

Mixing the numbering with a Sunday-first Categorical. If you have taught a name column that Sunday comes first, .dt.dayofweek has not heard about it and still calls Sunday 6. Sort by one or the other, never both in the same chain.

Assuming ISO agrees. .dt.isocalendar()['day'] also gives the day of the week, and it numbers Monday 1 through Sunday 7 — off by one from .dt.dayofweek, and a UInt32 rather than an int32. Excel's WEEKDAY defaults to Sunday 1 through Saturday 7. Three conventions, three answers.

Parentheses. .dt.dayofweek() raises TypeError: 'Series' object is not callable. Numbers are attributes; names are methods.

Where it shows up in Bamboo Weekly

Four Bamboo Weekly solutions use .dt.dayofweek, and it is worth noticing that in three of them I ended up preferring the names.

Bamboo Weekly #152: Congestion pricing is the two-key pattern above, on MTA ridership: group by dayofweek and day_name together, then reset_index the number away so the display keeps the label and the sort keeps the order.

Bamboo Weekly #151: PyPI in 2025 puts the choice plainly — many people would test dt.dayofweek > 4, and I built is_weekend from dt.day_name().isin([...]) instead, because it reads. PyPI serves 2.8 billion downloads on a weekday and 1.7 billion on a weekend day.

Bamboo Weekly #172: World Cup uses the number where the number is the point: .loc[pd.col('datetime').dt.dayofweek > 4] as a filter, to compare who wins at weekend matches.

Bamboo Weekly #162: Spotify and car accidents is where I say out loud that I never remember which number is which, and reach for day_name — and then find that nine of ten hit albums dropped on a Friday.

Practice it

Work through a dt.dayofweek exercise, with instant feedback and no signup required: practice.lernerpython.com/bamboo-weekly/dt-dayofweek/

Go deeper

The names, and the ordered Categorical that keeps them in calendar order, are on dt.day_name. The rest of the numeric accessor is on dt.year, and the time-of-day half on dt.hour. Weekday filters usually want isin, and none of it runs before to_datetime. The Pandas user guide's time series chapter covers isocalendar and the business-day offsets, which take a weekend definition as an argument.

More Pandas videos on Python and Pandas with Reuven Lerner.

Bamboo Weekly is the practice. If you want the structured version — full courses with downloadable Jupyter notebooks, plus live Pandas office hours when you get stuck — that is LernerPython+Data. A paid Bamboo Weekly subscription is included with it.

See it on real data

Below are the 2 Bamboo Weekly exercises that use dt.dayofweek on real-world data — try each one, then study the worked solution.

Part of the Pandas Methods Index. See also practice by skill.