Python
date range
datetime module
programming
code tutorial

Creating a range of dates in Python

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

Python does not have a built-in daterange() function like range() for integers. To generate a sequence of dates, use datetime.timedelta in a loop, a generator function, or pandas.date_range() for data analysis workflows. Each approach lets you iterate over consecutive days, weeks, months, or custom intervals.

Method 1: timedelta Loop

python
1from datetime import date, timedelta
2
3start = date(2025, 1, 1)
4end = date(2025, 1, 10)
5
6current = start
7while current <= end:
8    print(current)
9    current += timedelta(days=1)
10
11# 2025-01-01
12# 2025-01-02
13# ...
14# 2025-01-10
python
1from datetime import date, timedelta
2
3def daterange(start, end, step=1):
4    """Yield dates from start to end (exclusive), stepping by `step` days."""
5    current = start
6    while current < end:
7        yield current
8        current += timedelta(days=step)
9
10# Daily dates
11for d in daterange(date(2025, 1, 1), date(2025, 1, 6)):
12    print(d)
13# 2025-01-01 through 2025-01-05
14
15# Every 3 days
16for d in daterange(date(2025, 1, 1), date(2025, 1, 15), step=3):
17    print(d)
18# 2025-01-01, 2025-01-04, 2025-01-07, 2025-01-10, 2025-01-13

The generator yields one date at a time without building the full list in memory.

Method 3: List Comprehension

python
1from datetime import date, timedelta
2
3start = date(2025, 1, 1)
4days = 10
5
6dates = [start + timedelta(days=i) for i in range(days)]
7print(dates)
8# [date(2025, 1, 1), date(2025, 1, 2), ..., date(2025, 1, 10)]
9
10# Between two dates
11start = date(2025, 3, 1)
12end = date(2025, 3, 8)
13dates = [start + timedelta(days=i) for i in range((end - start).days + 1)]
14# Includes both start and end dates

Method 4: pandas.date_range()

python
1import pandas as pd
2
3# Daily range
4dates = pd.date_range(start="2025-01-01", end="2025-01-10", freq="D")
5print(dates)
6# DatetimeIndex(['2025-01-01', '2025-01-02', ..., '2025-01-10'], freq='D')
7
8# By number of periods
9dates = pd.date_range(start="2025-01-01", periods=5, freq="D")
10# 5 consecutive days starting from Jan 1
11
12# Weekly
13dates = pd.date_range(start="2025-01-01", end="2025-03-01", freq="W-MON")
14# Every Monday
15
16# Monthly (end of month)
17dates = pd.date_range(start="2025-01-01", end="2025-12-31", freq="ME")
18
19# Convert to Python date objects
20date_list = dates.date.tolist()

Common Frequency Codes

CodeMeaning
DCalendar day
BBusiness day (Mon-Fri)
WWeekly (default Sunday)
W-MONWeekly on Monday
MSMonth start
MEMonth end
QSQuarter start
YSYear start
hHourly

Method 5: dateutil.rrule

python
1from datetime import date
2from dateutil.rrule import rrule, DAILY, WEEKLY, MONTHLY
3
4# Daily
5dates = list(rrule(DAILY, dtstart=date(2025, 1, 1), until=date(2025, 1, 5)))
6# [datetime(2025, 1, 1), ..., datetime(2025, 1, 5)]
7
8# Weekly
9dates = list(rrule(WEEKLY, dtstart=date(2025, 1, 1), count=4))
10# 4 weeks starting from Jan 1
11
12# Monthly (handles varying month lengths correctly)
13dates = list(rrule(MONTHLY, dtstart=date(2025, 1, 31), count=4))
14# Jan 31, Feb 28, Mar 31, Apr 30 — smart month-end handling
15
16# Every 2 weeks
17dates = list(rrule(DAILY, interval=14, dtstart=date(2025, 1, 1), count=6))

dateutil.rrule is especially useful for month and year intervals where month lengths vary.

Working with datetime (Including Time)

python
1from datetime import datetime, timedelta
2
3start = datetime(2025, 1, 1, 9, 0)  # 9:00 AM
4
5# Every hour for 8 hours
6times = [start + timedelta(hours=i) for i in range(8)]
7for t in times:
8    print(t.strftime("%Y-%m-%d %H:%M"))
9
10# 2025-01-01 09:00
11# 2025-01-01 10:00
12# ...
13# 2025-01-01 16:00
14
15# Every 30 minutes
16times = [start + timedelta(minutes=30*i) for i in range(16)]

Business Days Only

python
1import pandas as pd
2from datetime import date
3
4# pandas business day range
5bdays = pd.bdate_range(start="2025-01-01", end="2025-01-15")
6print(bdays)
7# Excludes weekends
8
9# Custom business days (exclude holidays too)
10from pandas.tseries.holiday import USFederalHolidayCalendar
11bday = pd.offsets.CustomBusinessDay(calendar=USFederalHolidayCalendar())
12dates = pd.date_range(start="2025-01-01", end="2025-01-31", freq=bday)

Formatting Date Ranges

python
1from datetime import date, timedelta
2
3start = date(2025, 1, 1)
4dates = [start + timedelta(days=i) for i in range(5)]
5
6# As strings
7formatted = [d.strftime("%Y-%m-%d") for d in dates]
8# ['2025-01-01', '2025-01-02', ..., '2025-01-05']
9
10# As ISO format
11iso = [d.isoformat() for d in dates]
12
13# As custom format
14labels = [d.strftime("%B %d, %Y") for d in dates]
15# ['January 01, 2025', 'January 02, 2025', ...]

Reverse Range (Descending)

python
1from datetime import date, timedelta
2
3start = date(2025, 1, 10)
4end = date(2025, 1, 1)
5
6# Countdown
7current = start
8while current >= end:
9    print(current)
10    current -= timedelta(days=1)
11
12# Or with list comprehension
13dates = [start - timedelta(days=i) for i in range(10)]
14# [date(2025, 1, 10), date(2025, 1, 9), ..., date(2025, 1, 1)]

Common Pitfalls

  • Off-by-one on end date: range(10) excludes 10. Be explicit about whether your date range includes the end date. Use <= for inclusive, < for exclusive.
  • Month arithmetic with timedelta: timedelta(days=30) does not equal "one month" — months have 28-31 days. Use dateutil.relativedelta(months=1) for month-accurate arithmetic.
  • Timezone-naive date ranges: date objects have no timezone. If you need timezone-aware ranges, use datetime with zoneinfo.ZoneInfo and check DST transitions.
  • Memory with large ranges: [start + timedelta(days=i) for i in range(365*100)] creates a list of 36,500 dates in memory. Use a generator for large ranges.
  • pandas freq string changes: In pandas 2.x, some frequency strings changed (e.g., M became ME for month-end, Y became YE for year-end). Check your pandas version.

Summary

  • Use a generator with timedelta(days=1) for simple day-by-day iteration
  • Use list comprehension [start + timedelta(days=i) for i in range(n)] for small ranges
  • Use pandas.date_range() for data analysis with flexible frequency codes
  • Use dateutil.rrule for month/year intervals that respect varying month lengths
  • Use pd.bdate_range() for business-day-only ranges
  • Always be explicit about inclusive vs exclusive end dates

Course illustration
Course illustration

All Rights Reserved.