Subtract the dates. The result is a timedelta, and .days is the number you want.
from datetime import date start = date(2026, 10, 7) deadline = date(2026, 12, 25) gap = deadline - start print(gap) print(gap.days, "days to go")
79 days, 0:00:00 79 days to go
Subtract the other way round and you get a negative number, which is a handy "is this overdue?" check:
from datetime import date due = date(2026, 10, 1) today = date(2026, 10, 7) overdue_by = (today - due).days print(f"{overdue_by} days overdue" if overdue_by > 0 else "on time")
6 days overdue
Moving a date forward or back
Add a timedelta:
from datetime import date, timedelta ordered = date(2026, 10, 7) print(ordered + timedelta(days=14)) # delivery estimate print(ordered - timedelta(weeks=1)) # a week earlier
2026-10-21 2026-09-30
timedelta has no months=, because months aren't a fixed length: one month after 31 January has no good answer. If you need calendar months, dateutil.relativedelta (pip install python-dateutil) handles it, ending on 28 or 29 February.
With times, not just days
.days only counts whole days. For the full gap, use total_seconds():
from datetime import datetime clock_in = datetime(2026, 10, 7, 9, 15) clock_out = datetime(2026, 10, 7, 17, 45) worked = clock_out - clock_in print(worked) print(worked.days) # 0, because it's less than a day print(worked.total_seconds() / 3600, "hours")
8:30:00 0 8.5 hours
Weekdays only
NumPy counts business days, Monday to Friday, with the end date excluded:
import numpy as np print(np.busday_count("2026-10-05", "2026-10-19"))
10
Pass holidays=["2026-10-12"] to skip public holidays too.
To read a date from text first, see converting a string to a date.