I want to treat this one a bit differently from a general “subtract two datetimes” walkthrough, because in practice, “computing time differences” covers a broader family of problems than just full datetime subtraction — sometimes I need the difference between two time objects (no date), sometimes between two dates only, sometimes I need business-day differences, and sometimes I need to measure elapsed wall-clock time for performance logging. I’ve collected the patterns I actually use for each of these below.
The Foundation: timedelta
Every time-difference operation in Python ultimately produces or consumes a timedelta object. It’s worth understanding its constructor fully, because I use it for far more than just subtraction results — I also construct timedelta objects directly to represent durations I want to add or compare against.
from datetime import timedelta
d1 = timedelta(days=1, hours=6, minutes=30)
d2 = timedelta(hours=30, minutes=30)
print(d1 == d2) # True — both represent the same total duration
print(d1.total_seconds()) # 108000.0
timedelta normalizes any combination of units you pass into a canonical internal form, so timedelta(hours=30, minutes=30) and timedelta(days=1, hours=6, minutes=30) compare as equal because they represent the same actual duration.
Difference Between Two Full Datetimes
This is the most common case, and it’s simple subtraction:
from datetime import datetime
start = datetime(2026, 7, 30, 9, 0, 0)
end = datetime(2026, 8, 2, 17, 45, 0)
diff = end - start
print(diff)
print(f"{diff.days} days and {diff.seconds // 3600} hours")
Output:
3 days, 8:45:00
3 days and 8 hours
Difference Between Two Dates Only (No Time Component)
When I only care about calendar days — for example, “how many days until the deadline” — I use date objects instead of full datetime objects, which avoids any time-of-day noise entirely:
from datetime import date
today = date(2026, 7, 30)
deadline = date(2026, 9, 1)
days_left = (deadline - today).days
print(days_left)
Output:
33
Subtracting two date objects also produces a timedelta, but since there’s no time component, .seconds and .microseconds will always be zero — .days is all you need.
Difference Between Two time Objects
This one surprises people: you cannot directly subtract two time objects in Python.
from datetime import time
t1 = time(9, 0, 0)
t2 = time(17, 30, 0)
# This raises: TypeError: unsupported operand type(s) for -: 'datetime.time' and 'datetime.time'
# diff = t2 - t1
time objects represent a point on a 24-hour clock with no associated date, and Python deliberately doesn’t define subtraction for them, because “the difference between 9 AM and 5:30 PM” is ambiguous without knowing whether you’re measuring within the same day or across midnight. The fix is to combine each time with an arbitrary common date first:
from datetime import datetime, date
reference_date = date(2000, 1, 1)
dt1 = datetime.combine(reference_date, t1)
dt2 = datetime.combine(reference_date, t2)
diff = dt2 - dt1
print(diff)
Output:
8:30:00
I use datetime.combine() with an arbitrary shared reference date specifically for this pattern — it doesn’t matter what the date is, only that it’s the same for both.
Computing Business-Day (Working-Day) Differences
Calendar-day differences don’t account for weekends or holidays, which matters a lot for scheduling and SLA calculations. Python’s standard library doesn’t have a built-in business-day calculator, but numpy does, via busday_count:
import numpy as np
start = np.datetime64("2026-07-30")
end = np.datetime64("2026-08-10")
business_days = np.busday_count(start, end)
print(business_days)
For a pure-standard-library approach without numpy, I use a small loop-based function:
from datetime import date, timedelta
def business_days_between(start_date, end_date):
count = 0
current = start_date
while current < end_date:
if current.weekday() < 5: # Monday=0 ... Friday=4
count += 1
current += timedelta(days=1)
return count
print(business_days_between(date(2026, 7, 30), date(2026, 8, 10)))
This loop-based version is O(n) in the number of days between the two dates, which is fine for typical ranges but noticeably slower than numpy‘s vectorized busday_count for very large ranges or when computing many such differences at once.
Measuring Elapsed Execution Time (Performance Timing)
For profiling how long a piece of code takes to run, I don’t use datetime subtraction at all — I use the time module’s monotonic, high-resolution counters, which are designed specifically for this and aren’t affected by system clock adjustments:
import time
start = time.perf_counter()
# work being timed
total = sum(i * i for i in range(1_000_000))
elapsed = time.perf_counter() - start
print(f"Elapsed: {elapsed:.6f} seconds")
time.perf_counter() uses the highest-resolution clock available on the platform and is monotonic — it only ever moves forward, which makes it reliable for measuring short durations, unlike time.time(), which reflects wall-clock time and can jump backward or forward if the system clock is corrected.
For simple one-off benchmarking of a whole function or code block, the timeit module is built exactly for this:
import timeit
elapsed = timeit.timeit(lambda: sum(i * i for i in range(10000)), number=100)
print(f"Average per run: {elapsed / 100:.6f} seconds")
Comparing Time Differences Across Time Zones
If the two datetimes you’re subtracting are aware and in different zones, the subtraction is still computed correctly, because both are internally normalized to UTC before the arithmetic happens:
from zoneinfo import ZoneInfo
start = datetime(2026, 7, 30, 9, 0, 0, tzinfo=ZoneInfo("America/New_York"))
end = datetime(2026, 7, 30, 20, 0, 0, tzinfo=ZoneInfo("Asia/Tokyo"))
print(end - start)
Output:
-2:00:00
That negative result is correct — because of the large offset difference between New York and Tokyo, 8 PM in Tokyo on the same calendar day is actually earlier in absolute time than 9 AM in New York. This is exactly the kind of result that’s easy to get wrong with manual offset math and easy to get right by trusting the library.
Real-World Use Case: SLA Countdown Timer
A pattern I’ve built more than once — computing remaining time against an SLA deadline, formatted for a dashboard:
from datetime import datetime, timezone
def sla_status(deadline_utc):
now = datetime.now(timezone.utc)
remaining = deadline_utc - now
if remaining.total_seconds() < 0:
return f"Overdue by {abs(remaining)}"
return f"{remaining} remaining"
deadline = datetime(2026, 8, 1, 0, 0, 0, tzinfo=timezone.utc)
print(sla_status(deadline))
Computing Age or Elapsed Full Years
A specific variant of “time difference” I run into often enough to call out separately is computing someone’s age, or more generally, the number of complete years between two dates. Naively dividing the day-count difference by 365 gives a slightly wrong answer because of leap years, so I compute it based on calendar components instead:
from datetime import date
def full_years_between(start_date, end_date):
years = end_date.year - start_date.year
if (end_date.month, end_date.day) < (start_date.month, start_date.day):
years -= 1
return years
birth_date = date(1994, 3, 15)
today = date(2026, 7, 30)
print(full_years_between(birth_date, today))
Output:
32
The comparison (end_date.month, end_date.day) < (start_date.month, start_date.day) is doing the real work here — it checks whether this year’s birthday has actually occurred yet, decrementing the year count by one if not. This tuple-comparison trick is a clean, Pythonic way to compare month-and-day pairs without extra conditional branching.
Measuring Differences Across a Whole Series of Timestamps
When I have a sequence of events and want the duration between each consecutive pair — for example, gaps between log entries to detect unusually long pauses — I zip the sequence against itself, offset by one:
events = [
datetime(2026, 7, 30, 9, 0, 0),
datetime(2026, 7, 30, 9, 15, 0),
datetime(2026, 7, 30, 9, 45, 0),
datetime(2026, 7, 30, 11, 0, 0),
]
gaps = [b - a for a, b in zip(events, events[1:])]
for gap in gaps:
print(gap)
Output:
0:15:00
0:30:00
1:15:00
This zip(sequence, sequence[1:]) pattern is one I reuse constantly any time I need consecutive-pair comparisons, not just for datetimes — it’s a clean, allocation-light way to iterate over neighboring elements without manual index management.
Common Mistakes
- Trying to subtract two
timeobjects directly without combining them with a shared reference date first. - Using
time.time()instead oftime.perf_counter()for benchmarking, risking inaccuracy from wall-clock adjustments. - Ignoring weekends/holidays when a “days between” calculation was actually meant to represent business days.
- Forgetting
.total_seconds()and manually (and often incorrectly) combining.daysand.secondsfor a duration in seconds.
Debugging Tips
If a computed difference is negative when you expected positive (or vice versa), double check which datetime is the minuend and which is the subtrahend — end - start versus start - end is a very easy mistake to make when reading through a larger function.
FAQs
Q: How do I get the difference in whole weeks? (end - start).days // 7.
Q: Can timedelta represent negative durations? Yes — subtracting a later time from an earlier one produces a negative timedelta, and arithmetic with negative durations works correctly, though the internal .days/.seconds split can look unintuitive (see the normalization discussed in related guides).
Q: What’s the most precise way to measure a short code block’s execution time? time.perf_counter() for a single measurement, or the timeit module when you want an averaged result across multiple runs.
Summary
Computing time differences in Python spans several related but distinct problems: full datetime subtraction, date-only subtraction, time-only comparison (which requires combining with a reference date), business-day counting, and performance timing. Each has its own idiomatic tool — timedelta subtraction for calendar math, and time.perf_counter() or timeit for execution timing — and picking the right one avoids a lot of subtle bugs.
References
- Python official docs:
datetime— timedelta objects - Python official docs:
time.perf_counter - Python official docs:
timeit— Measure execution time of small code snippets