SECTION 1
Historical Context & Motivation
Computers have needed to track dates and times since their earliest days. When you log into a website, send a text message, or schedule a reminder, the software behind the scenes is storing and comparing timestamps. Before standardized libraries existed, programmers had to write their own date-handling code from scratch — accounting for leap years, time zones, and the varying number of days in each month. This led to countless bugs and even famous disasters like the Y2K bug, where storing years as two digits threatened to cause widespread computer failures at the turn of the millennium.
Python's datetime module was introduced as part of the standard library to give every Python programmer a reliable, well-tested toolkit for working with dates and times. Instead of reinventing the wheel, you can import a single module and immediately start creating date objects, calculating time differences, and formatting dates for display.
1970 • Unix Epoch Established
1989 • Python Created by Guido van Rossum
time module for basic time functions, but it relies on low-level C functions and lacks intuitive date objects.2000 • Y2K Bug Highlights Date Handling Risks
2002 • datetime Module Added to Python 2.3
datetime module, providing object-oriented classes for dates, times, and time deltas. It becomes the standard way to handle dates in Python.2020s • datetime Remains the Standard
dateutil and arrow build on top of it for advanced features.The central question the datetime module answers is simple but important: How do we represent, manipulate, and display dates and times in a way that is both accurate and easy for programmers to use? In this lesson, you will learn the core classes in the datetime module and how to put them to work in your own programs.
SECTION 2
Core Principles & Key Classes
The datetime module is built around a handful of classes, each designed to represent a different aspect of time. Understanding these classes is the foundation for everything you will do with dates in Python. You always begin by importing the module with from datetime import date, datetime, timedelta (or similar import statements), and then you create objects from these classes.
date
date(2025, 1, 15).time
time(14, 30, 0).datetime
datetime(2025, 1, 15, 14, 30).timedelta
timedelta(days=7) for a one-week span.KEY TAKEAWAY
date class is the calendar page (just the date), the time class is the clock face (just the time), the datetime class is both combined into one, and timedelta is like counting the number of days between two dates you circled on the calendar.SECTION 3
Visual Explanation — The datetime Class Hierarchy
datetime class (gold box) combines the attributes of both date (cyan) and time (pink), while timedelta (green) represents durations between two points in time.As you can see in the diagram above, the datetime class sits at the intersection of date and time. This means a single datetime object carries all six attributes — year, month, day, hour, minute, and second — making it the most versatile class for everyday use. The timedelta class stands alongside them as the tool for measuring and calculating differences in time.
SECTION 4
How It Works — Creating and Using datetime Objects
Working with the datetime module follows a consistent pattern: you import the classes you need, create objects, and then access their attributes or call their methods. Let's walk through the key operations one by one.
Importing and Creating Objects
The module is named datetime, and it contains a class also called datetime. This can be confusing at first! The most common import style is from datetime import date, datetime, timedelta so you can use the class names directly. To create a specific date, you pass the year, month, and day as arguments: my_date = date(2025, 6, 15). For a full date and time, use my_dt = datetime(2025, 6, 15, 9, 30, 0) where the last three numbers are hour, minute, and second.
Getting the Current Date and Time
One of the most useful features is grabbing the current date and time. The method datetime.now() returns a datetime object representing the exact moment the code runs. Similarly, date.today() returns just today's date without any time information.
Accessing Attributes
Once you have a datetime or date object, you can access its parts using dot notation. For example, if now = datetime.now(), then now.year gives the year, now.month gives the month (1–12), now.day gives the day, and now.hour gives the hour in 24-hour format.
Formatting with strftime()
The strftime() method (short for 'string format time') converts a datetime object into a formatted string. You pass a format string using special codes: %Y for a four-digit year, %m for a two-digit month, %d for the day, %H for the hour (24-hour), and %M for the minute. For example, now.strftime("%B %d, %Y") might produce "January 15, 2025".
Arithmetic with timedelta
You can add or subtract timedelta objects to shift dates forward or backward. Writing date.today() + timedelta(days=30) gives you the date 30 days from now. You can also subtract two date or datetime objects to get a timedelta: difference = date2 - date1 and then access difference.days to see how many days apart they are.
SECTION 5
strftime Format Codes — Detailed Breakdown
The strftime() method is incredibly flexible. The table below lists the most commonly used format codes you will encounter. Each code starts with a percent sign and is replaced by the corresponding date/time component when the string is generated.
| Code | Meaning | Example Output |
|---|---|---|
%Y | Four-digit year | 2025 |
%m | Month as zero-padded number (01–12) | 01 |
%d | Day as zero-padded number (01–31) | 15 |
%H | Hour in 24-hour format (00–23) | 14 |
%I | Hour in 12-hour format (01–12) | 02 |
%M | Minute (00–59) | 30 |
%S | Second (00–59) | 00 |
%B | Full month name | January |
%A | Full weekday name | Wednesday |
%p | AM or PM | PM |
Common strftime format codes for the datetime module
strftime() takes a datetime object and a format string, then substitutes each format code (like %B and %Y) with the corresponding value to produce a human-readable string.Notice that literal characters like the comma, spaces, and the word "at" in the format string are passed through unchanged. Only codes starting with % are replaced. This gives you full control over how dates appear to your users — whether you want "01/15/2025" (American format), "15/01/2025" (European format), or something completely custom.
SECTION 6
Worked Example — Building a Countdown Timer
Let's write a short program that calculates how many days remain until a specific event — for instance, the last day of school on June 6, 2025. This example uses multiple datetime concepts together.
Countdown to Last Day of School
- 1
Step 1 — Import the needed classes
We needdatefor working with calendar dates andtimedeltais returned automatically when we subtract dates. Write:from datetime import datefrom datetime import date - 2
Step 2 — Get today's date
The class methoddate.today()returns the current date from the system clock. Store it in a variable:today = date.today(). If today is January 15, 2025, this createsdate(2025, 1, 15).today = date.today() # date(2025, 1, 15) - 3
Step 3 — Create the target date
Construct the last day of school as a date object. Remember the arguments are (year, month, day):last_day = date(2025, 6, 6).last_day = date(2025, 6, 6) - 4
Step 4 — Subtract to get the difference
When you subtract one date from another, Python returns atimedeltaobject. We write:remaining = last_day - today. The result is a timedelta representing 142 days.remaining = last_day - today # timedelta(days=142) - 5
Step 5 — Display the result
Access the.daysattribute of the timedelta to get an integer. We can use an f-string for a nice display:print(f"Only {remaining.days} days until the last day of school!")Output: Only 142 days until the last day of school!
Complete Code
from datetime import date
today = date.today()
last_day = date(2025, 6, 6)
remaining = last_day - today
print(f"Only {remaining.days} days until the last day of school!")SECTION 7
Strengths, Limitations & Comparisons
The datetime module is powerful, but it is important to understand both what it does well and where it falls short. Knowing its limitations helps you pick the right tool for the job.
| Feature | Strengths | Limitations |
|---|---|---|
| Date Arithmetic | Easy addition and subtraction with timedelta; automatically handles month lengths and leap years | No built-in way to add months or years (only days, seconds, and weeks) |
| Formatting | strftime() supports many format codes and works consistently across platforms | Format codes can be tricky to memorize (%m vs %M); no natural language parsing built in |
| Time Zones | Supports timezone-aware datetimes via the tzinfo interface | Built-in timezone support is minimal; most developers need the third-party pytz or zoneinfo library |
| Built-in | Part of Python's standard library — no installation required | Less user-friendly than third-party alternatives like arrow or pendulum |
| Comparison | Datetime objects support <, >, ==, and other comparison operators directly | Cannot compare naive (no timezone) and aware (has timezone) datetimes; raises TypeError |
Strengths and limitations of Python's datetime module
KEY TAKEAWAY
zoneinfo module or the dateutil library).SECTION 8
Connection to Advanced Topics
The basics you have learned here form the foundation for more advanced date and time handling. As your projects grow in complexity, you will encounter situations where you need features beyond what we have covered today. The table below previews how introductory datetime concepts connect to more advanced topics.
| Intro Concept (This Lesson) | Advanced Concept (Future Learning) |
|---|---|
date.today() and datetime.now() | Timezone-aware datetime.now(tz=ZoneInfo('US/Eastern')) using the zoneinfo module |
strftime() for formatting output | strptime() for parsing date strings into datetime objects (the reverse operation) |
timedelta(days=7) for simple offsets | The dateutil.relativedelta for adding months and years accurately |
Comparing two dates with < and > | Sorting lists of datetime objects and using them as dictionary keys or database timestamps |
Accessing .year, .month, .day | Using .isoformat(), .weekday(), .isocalendar() for ISO standards and calendar operations |
How introductory datetime concepts connect to advanced topics
As you move into web development, data science, or app building, you will find that datetime is used almost everywhere. Database records are timestamped with datetime values. APIs send dates as ISO 8601 strings (like "2025-01-15T14:30:00Z") that you will parse using strptime(). Mastering the basics now gives you a strong foundation for all of these future applications.
SECTION 9
Practice Problems
Question 1: CONCEPTUAL
date object and a datetime object in Python's datetime module? When would you choose one over the other?Show answer
date object stores only the calendar date (year, month, and day), while a datetime object stores both the date and the time (year, month, day, hour, minute, second, and microsecond). You would choose date when time information is irrelevant — for example, recording a birthday or a homework due date. You would use datetime when the specific time matters, such as logging when a user submitted a form or scheduling a meeting.Question 2: BASIC CALCULATION
date object for March 14, 2025 (Pi Day). Then write another expression that uses strftime() to format it as "03/14/2025".Show answer
from datetime import date followed by pi_day = date(2025, 3, 14). Then format it: pi_day.strftime("%m/%d/%Y") returns "03/14/2025". The code %m gives the zero-padded month, %d gives the zero-padded day, and %Y gives the four-digit year.Question 3: INTERMEDIATE
timedelta and prints it in the format "Friday, January 31, 2025".Show answer
from datetime import date, timedelta. Create the checkout date: checkout = date(2025, 1, 10). Add 21 days: due_date = checkout + timedelta(days=21), which gives date(2025, 1, 31). Format and print it: print(due_date.strftime("%A, %B %d, %Y")) outputs "Friday, January 31, 2025". The %A code provides the full weekday name, which Python computes automatically.Question 4: APPLIED
.days attribute, then divide by 365.Show answer
from datetime import date. Then: birth = date(2007, 9, 5) and today = date.today(). Calculate the difference: age_days = (today - birth).days. For an approximate age in years: age_years = age_days // 365. If today is January 15, 2025, then age_days is 6,341 and age_years is 17. Note that dividing by 365 is approximate because leap years add extra days. For production code, you would compare the month and day directly, but this approach is good enough for a quick calculation.Question 5: CRITICAL THINKING
from datetime import datetime
dt = datetime(2025, 3, 1) - datetime(2025, 2, 1)
print(dt.days)
They expected 30 but got 28. Explain why, and describe how the result would change if the year were 2024 instead of 2025.Show answer
dt.days returns 28, not 30. If the year were changed to 2024, which is a leap year (divisible by 4 and not a century year exception), February would have 29 days, and the output would be 29. This illustrates an important point: the datetime module automatically accounts for varying month lengths and leap years in its arithmetic. The student's assumption that all months have 30 days is the source of their confusion. Always let datetime handle the math rather than assuming fixed month lengths.SUMMARY
Lesson Summary
Summary
Python's datetime module provides four core classes for handling dates and times. The date class represents a calendar date (year, month, day), the time class represents a time of day, the datetime class combines both into one object, and timedelta represents a duration between two points in time. You create objects by passing numeric arguments (like year, month, and day), and you can retrieve the current date or time using date.today() or datetime.now().
To display dates in a specific format, use the strftime() method with format codes like %Y (year), %m (month), and %d (day). To perform date arithmetic, add or subtract timedelta objects, or subtract two dates to get a timedelta. The module handles tricky details like leap years and varying month lengths automatically, making it an essential part of every Python programmer's toolkit.