Math with Dates in Python

Dates And Time Mar 19, 2026

Math with Dates in Python

Performing math with dates — adding days, subtracting weeks, calculating differences, or projecting future dates — is one of the most essential skills in data science. Whether you’re building rolling windows, calculating customer lifetime, measuring freshness, or creating time-based features, Python’s timedelta and relativedelta make date arithmetic clean, accurate, and powerful.

TL;DR — Key Tools for Date Math

  • timedelta → days, hours, minutes, seconds
  • dateutil.relativedelta → months, years, weeks
  • pandas .dt accessor for vectorized operations
  • Always work with timezone-aware datetimes

1. Basic Date Arithmetic with timedelta

from datetime import date, timedelta
from zoneinfo import ZoneInfo

today = date.today()

# Add time
tomorrow = today + timedelta(days=1)
next_week = today + timedelta(weeks=1)
future = today + timedelta(days=30, hours=6)

# Subtract time
last_week = today - timedelta(weeks=1)
print(f"Last week: {last_week}")

2. Advanced Math with relativedelta

from dateutil.relativedelta import relativedelta

# Add months or years (timedelta cannot do this accurately)
next_month = date.today() + relativedelta(months=1)
next_year = date.today() + relativedelta(years=1)

# End of month handling
end_of_month = date(2026, 3, 31) + relativedelta(months=1)   # correctly becomes April 30

3. Real-World Data Science Examples

import pandas as pd

# Create a small demo file so this example runs as-is
# (in your project, sales_data.csv is your real export)
import numpy as np
rng = np.random.default_rng(42)
n = 60
pd.DataFrame({
    "order_id": range(1001, 1001 + n),
    "order_date": pd.date_range("2026-01-01", periods=n, freq="3D"),
    "customer_id": rng.integers(101, 121, n),
    "customer_name": rng.choice([" ana", "ben ", "chen", "dana"], n),
    "product_id": rng.integers(1, 9, n),
    "region": rng.choice(["North", "South", "East", "West"], n),
    "category": rng.choice(["Electronics", "Computers", "Books", "Home"], n),
    "payment_method": rng.choice(["card", "cash", "wallet"], n),
    "segment": rng.choice(["consumer", "business"], n),
    "quantity": rng.integers(1, 6, n),
    "amount": rng.uniform(50, 2500, n).round(2),
    "discount": rng.choice([0.0, 0.05, 0.1, 0.2], n),
}).assign(
    price=lambda d: (d["amount"] / d["quantity"]).round(2),
    profit=lambda d: (d["amount"] * rng.uniform(0.05, 0.3, n)).round(2),
).assign(
    ship_date=lambda d: d["order_date"] + pd.Timedelta(days=2),
    status=lambda d: np.where(d["amount"] > 2000, "priority", "standard"),
).to_csv("sales_data.csv", index=False)

df = pd.read_csv("sales_data.csv", parse_dates=["order_date"])

# Current time
now = pd.Timestamp.now(tz="UTC")
df["order_date"] = df["order_date"].dt.tz_localize("UTC")   # demo dates are naive; make them UTC-aware to match now

# Math with dates in pandas
df["days_since_order"] = (now - df["order_date"]).dt.days
df["projected_delivery"] = df["order_date"] + pd.Timedelta(days=14)
df["one_month_ago"] = df["order_date"] - pd.Timedelta(days=30)

# Rolling window example
df["sales_7_days_ago"] = df["amount"].shift(7)

4. Best Practices in 2026

  • Use timedelta for day/hour/minute arithmetic
  • Use relativedelta for month/year calculations
  • Prefer pandas Timedelta and .dt for large DataFrames
  • Always perform calculations on timezone-aware datetimes
  • Store original dates and derived math columns separately

Date Arithmetic Rules

Adding a timedelta to a date moves it by a fixed number of days. Only the days part matters for a date: hours and minutes in the timedelta are ignored, because a date has no time.

Months and years have different lengths, so timedelta cannot express "one month later". dateutil.relativedelta and pandas DateOffset handle calendar arithmetic and clip to the end of shorter months.

Subtracting tz-aware and naive timestamps raises an error, so make both sides the same kind before doing math.

Worked Example: Fixed Days versus Calendar Months

We compare adding 30 days with adding one calendar month.

from datetime import date, timedelta
from dateutil.relativedelta import relativedelta
import pandas as pd

start = date(2026, 1, 31)
print(start + timedelta(days=30))
print(start + relativedelta(months=1))
print(date(2026, 3, 1) + timedelta(hours=30))

s = pd.Series(pd.to_datetime(["2026-01-31", "2026-02-15"]))
print((s + pd.DateOffset(months=1)).dt.date.tolist())

Thirty days after 31 January is 2 March, while one calendar month later is 28 February. Adding 30 hours to a date moves it by only one day. pandas DateOffset clips to month end in the same way.

Practical Tips

Always test date arithmetic around month ends and leap days, such as 31 January and 29 February.

These edge cases are where most date bugs hide.

Common Mistakes

  • Using 30 days to mean one month.
  • Expecting hours to affect a date.
  • Mixing naive and aware timestamps.
  • Forgetting leap years in manual calculations.

Quick Summary

  • timedelta adds fixed durations.
  • relativedelta and DateOffset add calendar units.
  • Dates ignore time parts.
  • Keep time zone awareness consistent.

Conclusion

Math with dates is a core skill for any data scientist. In 2026, the combination of timedelta, relativedelta, and pandas vectorized operations lets you perform accurate time-based feature engineering, projections, and freshness analysis with clean, readable code.

Next steps:

  • Add time-delta features (days since order, projected delivery, etc.) to one of your current datasets

Related Tutorials

Share:
Last updated: March 2026
Built-in Functions in Python 2026 str() in Python 2026: String Conversion + Modern Formatting & Best Practices memoryview with JAX in Python 2026: Zero-Copy NumPy → JAX Array Interop + Efficient ML Examples memoryview with TensorFlow in Python 2026: Zero-Copy NumPy → Tensor Interop + GPU Pinning & ML Examples memoryview with TensorFlow in Python 2026: Zero-Copy NumPy → Tensor Interop + ML Examples memoryview with NumPy & PyTorch in Python 2026: Zero-Copy Views, Efficient Slicing & ML Interop Examples memoryview with NumPy in Python 2026: Zero-Copy Views, Efficient Slicing & Real ML Examples memoryview() in Python 2026: Zero-Copy Magic for Large Binary Data + Real Examples import() in Python 2026: How It Works, Security Risks & Modern Alternatives (importlib) zip() in Python 2026: How to Use It, strict=True Behavior & Real-World Examples vars() in Python 2026: Accessing Object Namespace + Modern Introspection Patterns type() in Python 2026: Dynamic Type Inspection & Object Creation + Modern Patterns tuple() in Python 2026: Immutable Sequences + Modern Patterns & Best Practices super() in Python 2026: Method Resolution & Modern Inheritance Patterns sum() in Python 2026: Summing Iterables + Modern Numeric Patterns & Best Practices staticmethod() in Python 2026: Static Methods, Utility Functions & Modern Best Practices sorted() in Python 2026: Sorting Iterables + Modern Patterns & Best Practices slice() in Python 2026: Creating Slice Objects + Modern Patterns & Best Practices setattr() in Python 2026: Dynamic Attribute Setting + Modern Patterns & Safety set() in Python 2026: Mutable Sets Creation + Modern Patterns & Best Practices