The timedelta class from the datetime module represents an exact duration expressing the difference between two date or time instances.
Normalized Duration Units: While timedelta accepts weeks, days, hours, minutes, seconds, milliseconds, and microseconds, Python internally converts and stores only days, seconds, and microseconds. For calendar-aware operations spanning variable months or years, use relativedelta. To inspect tuple components, see date.timetuple().
The timedelta constructor takes optional duration arguments that default to zero:
# Formal constructor signature of datetime.timedelta
from datetime import timedelta
delta = timedelta(days=0, seconds=0, microseconds=0, milliseconds=0, minutes=0, hours=0, weeks=0)
| Parameter | Accepted Type | Default | Internal Storage & Conversion |
|---|---|---|---|
days |
int, float |
0 |
Stored directly as integer days. |
seconds |
int, float |
0 |
Normalized: 0 ≤ seconds < 86400 (overflow increments days). |
microseconds |
int, float |
0 |
Normalized: 0 ≤ microseconds < 1000000. |
weeks |
int, float |
0 |
Converted into 7 days. |
Adding or subtracting a timedelta to a date object returns a new date, adjusting for leap years and month boundaries:
# 1. Basic date arithmetic: adding and subtracting days
from datetime import date, timedelta
today = date(2026, 10, 18)
five_days_ahead = today + timedelta(days=5)
three_weeks_ago = today - timedelta(weeks=3)
print("Baseline Date: ", today)
print("5 Days Ahead: ", five_days_ahead)
print("3 Weeks in Past: ", three_weeks_ago)Terminal Output:
Baseline Date: 2026-10-18
5 Days Ahead: 2026-10-23
3 Weeks in Past: 2026-09-27
When working with timestamps, you can combine hours, minutes, and seconds into a single duration:
# 2. Combined time units (hours, minutes, seconds)
from datetime import datetime, timedelta
start = datetime(2026, 10, 18, 9, 30, 0)
duration = timedelta(days=1, hours=4, minutes=45)
end = start + duration
print("Session Start: ", start)
print("Session End: ", end)Terminal Output:
Session Start: 2026-10-18 09:30:00
Session End: 2026-10-19 14:15:00
Subtracting two datetime instances yields a timedelta measuring elapsed duration:
# 3. Calculating duration between two datetime objects
from datetime import datetime
t1 = datetime(2026, 10, 18, 8, 0, 0)
t2 = datetime(2026, 10, 20, 14, 30, 15)
diff = t2 - t1
print("Difference object:", diff)
print("Days component: ", diff.days)
print("Seconds component:", diff.seconds)
print("Total seconds: ", diff.total_seconds())Terminal Output:
Difference object: 2 days, 6:30:15
Days component: 2
Seconds component: 23415
Total seconds: 196215.0
CPython normalizes all inputs into three canonical attributes: days, seconds, and microseconds:
# 4. Internal normalization (days, seconds, microseconds)
from datetime import timedelta
# Hours, minutes, and milliseconds normalize into days, seconds, microseconds
d = timedelta(hours=25, minutes=90, milliseconds=1500)
print("Days: ", d.days)
print("Seconds: ", d.seconds)
print("Microseconds:", d.microseconds)
print("String: ", d)Terminal Output:
Days: 1
Seconds: 9001
Microseconds: 500000
String: 1 day, 2:30:01.500000
Timedelta instances support scalar multiplication, float division, and unit ratios:
# 5. Multiplication, division, and slot counts
from datetime import timedelta
slot = timedelta(hours=2, minutes=30)
doubled = slot * 2
half = slot / 2
# Ratio of two timedeltas returns float count
total_time = timedelta(days=3)
unit = timedelta(hours=6)
slots_count = total_time / unit
print("Doubled duration: ", doubled)
print("Half duration: ", half)
print("Task slot count: ", slots_count)Terminal Output:
Doubled duration: 5:00:00
Half duration: 1:15:00
Task slot count: 12.0
Session token validator with TTL expiration:
# 6. Production Recipe: Session Token Expiration Validator
from datetime import datetime, timedelta
class CacheToken:
def __init__(self, key: str, ttl_seconds: int):
self.key = key
self.created_at = datetime.now()
self.ttl = timedelta(seconds=ttl_seconds)
def is_expired(self, at_time: datetime = None) -> bool:
now = at_time or datetime.now()
return (now - self.created_at) > self.ttl
token = CacheToken("session_key", ttl_seconds=3600)
t_45m = token.created_at + timedelta(minutes=45)
t_75m = token.created_at + timedelta(minutes=75)
print("Expired at 45m?", token.is_expired(t_45m))
print("Expired at 75m?", token.is_expired(t_75m))Terminal Output:
Expired at 45m? False
Expired at 75m? TrueGenerating day-by-day schedules using stepping generators:
# 7. Production Recipe: Step-by-Step Date Range Generator
from datetime import date, timedelta
def date_range(start_date: date, count: int):
step = timedelta(days=1)
curr = start_date
for _ in range(count):
yield curr
curr += step
start = date(2026, 10, 18)
dates = [d.strftime('%Y-%m-%d') for d in date_range(start, 4)]
print("Consecutive dates:", dates)Terminal Output:
Consecutive dates: ['2026-10-18', '2026-10-19', '2026-10-20', '2026-10-21']
Use total_seconds() instead of .seconds for durations > 24 hours. Note that months are unsupported:
# 8. Common Traps: .seconds vs .total_seconds()
from datetime import timedelta
# TRAP: .seconds only returns partial-day seconds!
two_days = timedelta(days=2, hours=3)
print(".seconds: ", two_days.seconds) # 10800 (only the 3 hours)
print(".total_seconds():", two_days.total_seconds()) # 183600.0 (full duration)
# TRAP: timedelta does NOT accept 'months' or 'years'
try:
timedelta(months=1)
except TypeError as err:
print("Caught TypeError:", err)Terminal Output:
.seconds: 10800
.total_seconds(): 183600.0
Caught TypeError: 'months' is an invalid keyword argument for __new__()
Practice date arithmetic, duration normalization, and cache TTL validation in our interactive companion Jupyter Notebook:
Explore interactive code cells, benchmark duration operations, test token expiry logic, and run self-validating assertions.
View on GitHub Run in Google ColabRun these unit checks directly in Python or your local environment to verify timedelta mechanics:
# 9. Self-verifying unit test suite for datetime.timedelta
from datetime import date, datetime, timedelta
# Test 1: Addition and subtraction equality
base = datetime(2026, 10, 18, 12, 0, 0)
d1 = timedelta(days=1, hours=2)
assert (base + d1) - d1 == base
# Test 2: Normalization verification
d2 = timedelta(hours=24)
assert d2.days == 1 and d2.seconds == 0
# Test 3: total_seconds() accuracy
d3 = timedelta(days=1, minutes=1)
assert d3.total_seconds() == 86400 + 60
# Test 4: Division ratio
assert timedelta(days=1) / timedelta(hours=12) == 2.0
print("All datetime.timedelta unit assertions successfully verified!")Terminal Output:
All datetime.timedelta unit assertions successfully verified!
Months have variable durations (28 to 31 days). A fixed duration object like timedelta cannot represent variable months. Use relativedelta instead.
The .seconds attribute returns only the remainder seconds for the partial day (0 to 86399). The .total_seconds() method returns the entire duration converted to seconds.
Yes. Subtracting a future date from a past date results in a negative timedelta, internally normalized with negative days and positive seconds.
timedelta.resolution represents the smallest possible duration increment: exactly 1 microsecond (0:00:00.000001).
Author & Instructor at plus2net
I write and maintain practical tutorials on Python, PHP, SQL, JavaScript, HTML, jQuery, and web development at plus2net. The tutorials focus on clear explanations, working examples, and code that readers can test and adapt while learning.