Generating Dates: date_range & Periods
Create regular sequences of dates with pd.date_range (start, end, periods, freq), learn the frequency aliases like D, W, ME, h, and meet Periods for whole months and quarters.
Often you need dates that are not in your data: a fixture calendar for a new season, one row for every day so that days without matches show up as zero, or a timeline of hourly ball-by-ball snapshots. Typing them by hand is impossible — pd.date_range generates them. Munna's notebook (video 09) starts the DateTime part exactly here: pd.date_range(start='01/01/2024', end='31/12/2024'), then tries periods= and different freq values.
Definition
pd.date_range()returns aDatetimeIndexof equally spaced dates or times. You describe the sequence with any three ofstart,end,periods(how many dates) andfreq(the step, such as"D"day,"W"week,"ME"month end,"h"hour). APeriodis different: it represents a whole span (e.g. March 2024) instead of a single instant.
- DatetimeIndex — an index made of Timestamps; you can use it as a DataFrame index, loop over it, or turn it into a column.
- Equally spaced — every gap equals
freq(calendar-aware:"ME"always lands on the last day of each month). - Any three — with
start+end+freqpandas counts the periods itself; withstart+end+periodsit computes the spacing, likenp.linspace.
Syntax
python
pd.date_range(start=None, end=None, periods=None, freq=None,
tz=None, normalize=False, name=None, inclusive="both")
pd.period_range(start=None, end=None, periods=None, freq=None)
pd.Period("2024-03", freq="M")| Parameter | Meaning | Default |
|---|---|---|
start / end | first / last date (string or Timestamp) | None |
periods | how many dates to generate | None |
freq | step between dates — a frequency alias like "D", "2D", "W", "ME", "h" | "D" (if not computable) |
tz | time zone for the dates, e.g. "Asia/Kolkata" | None (naive) |
normalize | set times to midnight | False |
name | name of the resulting index | None |
inclusive | include "both", "left", "right" or "neither" endpoint | "both" |
Frequency aliases
| Alias | Meaning | Alias | Meaning |
|---|---|---|---|
"D" | calendar day | "h" | hour |
"B" | business day (Mon–Fri) | "min" | minute |
"W" | weekly, on Sunday (= "W-SUN") | "s" | second |
"W-MON" | weekly, on Monday | "MS" | month start |
"ME" | month end | "QE" / "QS" | quarter end / start |
"YE" / "YS" | year end / start | "2D", "3h", "15min" | multiples |
Note (pandas 3): the old aliases
"M","Q","Y"/"A","H"and"T"were removed — they now raiseValueError: Invalid frequency. Use"ME","QE","YE","h"and"min". (Munna's notebook already shows the'H' is deprecatedwarning that led to this change.)
Example — start + end (daily)
python
days = pd.date_range(start="2024-03-22", end="2024-03-28")
print(days)
print(len(days), type(days).__name__)text
DatetimeIndex(['2024-03-22', '2024-03-23', '2024-03-24', '2024-03-25',
'2024-03-26', '2024-03-27', '2024-03-28'],
dtype='datetime64[us]', freq='D')
7 DatetimeIndexHow it works: with no freq, the step is one calendar day, and both endpoints are included. The freq='D' at the end shows the step pandas used.
Example — start + periods + freq
python
print(pd.date_range("2024-03-22", periods=4, freq="W"))
print(pd.date_range("2024-03-22", periods=4, freq="2D"))
print(pd.date_range("2024-01-01", periods=3, freq="ME"))
print(pd.date_range("2024-01-01", periods=3, freq="MS"))
print(pd.date_range("2024-03-22 19:30", periods=4, freq="h"))text
DatetimeIndex(['2024-03-24', '2024-03-31', '2024-04-07', '2024-04-14'], dtype='datetime64[us]', freq='W-SUN')
DatetimeIndex(['2024-03-22', '2024-03-24', '2024-03-26', '2024-03-28'], dtype='datetime64[us]', freq='2D')
DatetimeIndex(['2024-01-31', '2024-02-29', '2024-03-31'], dtype='datetime64[us]', freq='ME')
DatetimeIndex(['2024-01-01', '2024-02-01', '2024-03-01'], dtype='datetime64[us]', freq='MS')
DatetimeIndex(['2024-03-22 19:30:00', '2024-03-22 20:30:00',
'2024-03-22 21:30:00', '2024-03-22 22:30:00'],
dtype='datetime64[us]', freq='h')How it works:
"W"jumps to Sundays — the first Sunday on or after 22 March is 24 March."ME"gives the last day of each month (29 Feb — 2024 is a leap year);"MS"gives the first."h"steps one hour; times are kept.
Example — start + end + periods (like linspace)
python
print(pd.date_range(start="2024-01-01", end="2024-03-31", periods=3))text
DatetimeIndex(['2024-01-01', '2024-02-15', '2024-03-31'], dtype='datetime64[us]', freq=None)The three dates are spread evenly from start to end — the same idea as np.linspace. Here freq=None, because the gap (45 days) is computed, not a named frequency.
Example — business days and an IPL fixture grid
python
weekdays = pd.date_range("2024-04-01", "2024-04-10", freq="B")
print(weekdays.day_name().tolist())
fixtures = pd.DataFrame({"date": pd.date_range("2024-03-22", periods=5, freq="D")})
fixtures["match_no"] = range(1, 6)
fixtures["day"] = fixtures["date"].dt.day_name()
print(fixtures)text
['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Monday', 'Tuesday', 'Wednesday']
date match_no day
0 2024-03-22 1 Friday
1 2024-03-23 2 Saturday
2 2024-03-24 3 Sunday
3 2024-03-25 4 Monday
4 2024-03-26 5 Tuesday"B" skips Saturdays and Sundays. A DatetimeIndex also has .day_name(), .month etc. directly (no .dt needed — .dt is only for Series).
Example — fill in missing days with reindex
A team's runs are recorded only on match days. To see every day (zeros on rest days), reindex onto a full date range:
python
runs = pd.Series([182, 166, 210], index=pd.to_datetime(["2024-03-24", "2024-03-27", "2024-03-29"]))
all_days = pd.date_range(runs.index.min(), runs.index.max(), freq="D")
print(runs.reindex(all_days, fill_value=0))text
2024-03-24 182
2024-03-25 0
2024-03-26 0
2024-03-27 166
2024-03-28 0
2024-03-29 210
Freq: D, dtype: int64Periods — whole months, quarters, years
python
p = pd.Period("2024-03", freq="M")
print(p, "|", p.start_time, "->", p.end_time)
print(pd.period_range("2024-03", periods=3, freq="M"))
dates = pd.Series(pd.to_datetime(["2024-03-22", "2024-04-14", "2024-05-26"]))
print(dates.dt.to_period("M"))
print(dates.dt.to_period("Q"))text
2024-03 | 2024-03-01 00:00:00 -> 2024-03-31 23:59:59.999999
PeriodIndex(['2024-03', '2024-04', '2024-05'], dtype='period[M]')
0 2024-03
1 2024-04
2 2024-05
dtype: period[M]
0 2024Q1
1 2024Q2
2 2024Q2
dtype: period[Q-DEC]How it works: a Period is a span: 2024-03 covers everything from 1 March 00:00 to 31 March 23:59:59.999999. dt.to_period("M") labels each date with its month — a handy key for grouping ("matches per month"). Note that for periods the monthly alias is still "M" (the "ME" rename only applies to date offsets / date_range).
Comparison — Timestamp vs Period vs DatetimeIndex
Timestamp | Period | DatetimeIndex | |
|---|---|---|---|
| Represents | one instant | a whole span (day, month, quarter…) | many instants |
| Made by | pd.Timestamp, pd.to_datetime | pd.Period, to_period, period_range | pd.date_range, pd.to_datetime(list) |
| Example | 2024-03-22 19:30 | 2024-03 | ['2024-03-22', '2024-03-23', …] |
Common mistakes
- ❌
freq="M"orfreq="H"in pandas 3 →ValueError. ✅"ME"/"MS"and"h". - ❌ Giving all four of
start,end,periods,freq→ValueError. ✅ Exactly three. - ❌
start="01/02/2024"meaning 1 Feb — pandas reads it as January 2. ✅ Use ISO strings"2024-02-01". - ❌ Expecting
"W"to start on the given date. ✅ It snaps to Sundays; use"7D"for "every 7 days from the start".
Interview tip
Q: Difference between freq="ME" and freq="MS"?
A: "ME" generates month-end dates (31 Jan, 29 Feb, …), "MS" generates month-start dates (1 Jan, 1 Feb, …).
Key points to remember
- pd.date_range builds a DatetimeIndex of equally spaced dates from three of start, end, periods and freq.
- Common freq aliases: 'D' day, 'B' business day, 'W' weekly (Sunday), 'ME'/'MS' month end/start, 'h' hour, 'min' minute.
- pandas 3 removed 'M', 'Q', 'Y', 'H', 'T' — use 'ME', 'QE', 'YE', 'h', 'min'.
- start + end + periods spaces dates evenly, like np.linspace.
- Reindexing onto a full date_range reveals missing days (fill_value=0).
- A Period is a whole span (e.g. March 2024); dt.to_period('M') labels dates by month.
- Use ISO strings 'YYYY-MM-DD' to avoid day/month confusion.
Try it yourself
date_range with different frequencies
Show rest days as zero with reindex
Periods: label dates by month and quarter
Practice: build a fixture calendar
Revision Flashcards
Tap a card to flip it and see the answer.
