Maintenance

Site is under maintenance — quizzes are still available.

Go to quizzes

Work with Dates and Times using datetime

Learn how to use Python's datetime module to work with dates and times effectively in this step-by-step tutorial. Understand how to create, format, and manipulate dates and times, handle time zones, and deal with common edge cases. Includes a hands-on exercise and practical troubleshooting tips.

Focus: work with dates and times using datetime

Sponsored

Dates and times are everywhere in software — log timestamps, scheduled tasks, data analysis, and user-facing calendars. Yet few things trip up Python developers more consistently than working with dates and times using datetime. The datetime module is Python's built-in, batteries-included answer to this universal need. This lesson demystifies it so you can stop guessing and start building reliable time-aware code.

The problem this lesson solves

Without a clear mental model, trying to represent a simple date — like "tomorrow at 3 PM" — can lead to a tangle of string parsing, manual arithmetic, and off-by-one errors. You might reach for third-party libraries too soon, or write brittle code that breaks across time zones. The core problem: dates and times are not simple strings or numbers; they have their own semantics (leap years, months with different lengths, daylight saving time). Python's datetime module wraps these complexities into intuitive objects, so you can focus on what you want to do with a date instead of how to compute it.

Core concept / mental model

Think of datetime as a toolbox of four main object types:

  • date: A year, month, and day (no time). Useful for birthdays, due dates.
  • time: Hours, minutes, seconds, microseconds — no date attached. Like a daily alarm.
  • datetime: A date and a time together — the most common use case. Think of a flight departure or a log entry.
  • timedelta: A duration (difference between two points in time). Think “3 hours later” or “5 days ago.”

These objects work together: you add a timedelta to a datetime to get a new datetime, or subtract two datetime objects to get a timedelta.

Pro tip: Always work with datetime objects, never with raw strings. Strings are for display; objects are for logic.

How it works step by step

1. Getting the current moment

Use datetime.datetime.now() or datetime.date.today() to capture now.

2. Creating specific dates and times

You construct datetime(year, month, day, hour, minute, second) objects directly. The arguments map 1-to-1 to calendar components.

3. Formatting and parsing (the strftime / strptime dance)

  • strftime (string from time) — converts a datetime object to a formatted string for display.
  • strptime (string parse time) — converts a string into a datetime object, using a format directive.

Format codes like %Y (4-digit year), %m (month), %d (day), %H (hour), %M (minute) are your friends. A full list is in the Python docs.

4. Date arithmetic with timedelta

Add or subtract a timedelta to shift a datetime forward or backward in time. timedelta(days=1) means "tomorrow," timedelta(hours=-12) means "12 hours ago."

5. Comparing dates

All datetime objects support <, >, ==, etc. The comparisons are intuitive: datetime(2024, 3, 15) > datetime(2024, 3, 14) is True.

Hands-on walkthrough

Let's start with a complete example that answers: "What was the date 7 days from today?" and prints it in a readable format.

from datetime import datetime, timedelta

# Get today's date and time
now = datetime.now()
print(f"Now: {now}")

# Add 7 days
future = now + timedelta(days=7)
print(f"7 days later: {future}")

# Format output nicely
formatted = future.strftime("%A, %B %d, %Y")
print(f"Formatted: {formatted}")

Expected output (actual values depend on when you run it):

Now: 2025-03-15 14:32:10.123456
7 days later: 2025-03-22 14:32:10.123456
Formatted: Saturday, March 22, 2025

Now let's parse a common string format (ISO 8601) into a datetime:

from datetime import datetime

date_string = "2025-12-25"
parsed_date = datetime.strptime(date_string, "%Y-%m-%d")
print(f"Parsed: {parsed_date}")
print(f"Day of week: {parsed_date.strftime('%A')}")

Expected output:

Parsed: 2025-12-25 00:00:00
Day of week: Thursday

Calculate the time until New Year:

from datetime import datetime

today = datetime.now()
new_year = datetime(today.year + 1, 1, 1)
difference = new_year - today
print(f"Days until New Year: {difference.days}")
print(f"Seconds until New Year: {difference.total_seconds()}")

Expected output:

Days until New Year: 291
Seconds until New Year: 25171200.0

Compare options / when to choose what

Once you're comfortable with datetime, you might wonder: should I use datetime or third-party libraries?

Library/Module Best for Consideration
datetime (built-in) Simple date manipulation, formatting, basic arithmetic No timezone database built-in (use zoneinfo in Python 3.9+ for time zones)
dateutil (third-party) Relative dates (e.g., "next Monday"), fuzzy parsing Heavier dependency; great for complex human-style dates
arrow (third-party) Human-friendly API, timezone handling Overkill for basic needs; adds extra dependency
pandas (third-party) Time series analysis, large datasets Only when you already use pandas; heavy for standalone date work

Rule of thumb: Start with datetime for 90% of tasks. Reach for dateutil only when you need natural language parsing like "last Friday". Avoid third-party modules for basic date math — they add complexity without benefit.

Troubleshooting & edge cases

Here are the most common pitfalls when working with dates and times using datetime:

Mistake: Confusing month and day in parser formats

# Wrong: %m is month, %d is day
datetime.strptime("2025-03-04", "%Y-%d-%m")  # Would interpret 03 as day, 04 as month — silently wrong

Fix: Always double-check your format string matches the input exactly.

Mistake: Forgetting that datetime objects are immutable

You cannot change a datetime inline. today.replace(day=15) returns a new object — you must assign it.

start = datetime(2025, 1, 10)
start.day = 15  # AttributeError: attribute is read-only

Mistake: Assuming strftime uses 12-hour clock by default

%H is 24-hour, %I is 12-hour. Use %I with %p (AM/PM) for 12-hour display.

from datetime import datetime
dt = datetime(2025, 3, 15, 15, 30)
print(dt.strftime("%I:%M %p"))  # "03:30 PM"
print(dt.strftime("%H:%M"))     # "15:30"

Edge case: timedelta with months and years

timedelta does not support months or years because they vary in length. For month-level arithmetic, you need dateutil.relativedelta or manual logic.

# This does NOT exist in datetime:
# today + timedelta(months=1)  # TypeError

Pro tip: For "3 months from now," increment the month number and wrap around. Use dateutil.relativedelta for a clean solution: from dateutil.relativedelta import relativedelta.

Edge case: Daylight saving time transitions

When an hour is skipped (spring forward) or repeated (fall back), naive datetime objects ignore the issue. Use time-zone-aware objects from zoneinfo to get correct arithmetic across DST boundaries.

from datetime import datetime, timedelta
from zoneinfo import ZoneInfo

eastern = ZoneInfo("America/New_York")
dt_aware = datetime(2025, 3, 9, 1, 30, tzinfo=eastern)  # DST spring-forward at 2 AM
next_hour = dt_aware + timedelta(hours=1)
print(next_hour)  # Correctly jumps to 3:30 AM EDT

What you learned & what's next

You now understand how to:

  • Create date, time, datetime, and timedelta objects
  • Get the current date/time
  • Format dates as strings (strftime) and parse strings into dates (strptime)
  • Perform date arithmetic (timedelta) and comparisons
  • Avoid common mistakes like misusing format codes or expecting month arithmetic in timedelta
  • Recognize when to reach for third-party tools like dateutil

Next step: Build on this foundation by exploring the time module for measuring performance (time.time()) or scheduling tasks (time.sleep()). Then dive into the calendar module for month calendars and weekday calculations. These skills will make you confident when handling time in any Python project.

Practice recap

Try this mini-exercise: Write a script that reads a date string like "2025-08-15 14:30:00", parses it into a datetime, adds 2 days and 5 hours, then prints the result in the format "Friday, August 15, 2025 at 07:30 PM". Use strptime, timedelta, and strftime — no third-party modules.

Common mistakes

  • Using %m (month) and %d (day) in the wrong order when parsing or formatting strings, leading to silent data corruption.
  • Trying to modify a datetime object in-place (e.g., start.day = 15) — datetime objects are immutable; always assign the result of .replace() or .shift().
  • Assuming timedelta supports months or years — it only works with days, seconds, and microseconds. For months/years, use dateutil.relativedelta.
  • Ignoring time zones (naive datetimes) when working with UTC offsets or DST transitions, causing off-by-one-hour errors in logs and scheduling.
  • Using strftime with %H (24-hour) when a 12-hour format with AM/PM is expected — always pair %I with %p for 12-hour display.

Variations

  1. Use datetime.utcnow() (deprecated in 3.12) or datetime.now(tz=timezone.utc) for UTC-aware datetimes in modern Python.
  2. For parsing natural language dates like "next Tuesday" or relative expressions like "3 weeks ago", the third-party dateutil library provides parser.parse() and relativedelta.
  3. When working exclusively with date ranges (no times), datetime.date objects suffice; use date_range = [start + timedelta(days=i) for i in range((end-start).days)].

Real-world use cases

  • Automatically generating a timestamp for every log entry in a web application, formatted as ISO 8601 strings.
  • Calculating subscription expiration dates: add 30 or 365 days from the purchase datetime to generate a renewal date.
  • Scheduling a daily report email: capture the current time, compute the next 9 AM occurrence (adjusting for DST), and send the report at that moment.

Key takeaways

  • Python's datetime module provides date, time, datetime, and timedelta objects for all basic date/time needs.
  • Use strftime to format a datetime as a string and strptime to parse a string back into a datetime — always match the format specifier carefully.
  • Date arithmetic is done with timedelta (days, seconds, microseconds); for month/year shifts, drop back to manual logic or dateutil.relativedelta.
  • Always prefer time-zone-aware datetimes (using zoneinfo) in any system that spans multiple time zones or observes DST.
  • Avoid third-party libraries for 90% of date tasks; the built-in datetime is robust, well-documented, and keeps dependencies minimal.

Sponsored

Sponsored

Discussion

Questions, corrections, and tips help everyone reading this page.

0 comments

Add a comment

Shown publicly with your comment.

Be constructive · max 4,000 characters

No comments yet — start the thread.

Related tutorials, quizzes, and articles for this topic.