Python Dates and Times: datetime, timedelta, strftime, strptime
Python's built-in datetime module handles dates, times, differences between them, and conversion to and from text. Four pieces cover most beginner needs: date and datetime for a moment on the calendar, timedelta for a length of time, strftime() to turn a date into text, and strptime() to turn text into a date. Every example here was run in Python 3.13, and the output shown is what it printed. The module reference was read in October 2026.
Add days to a date, or count the gap
Mirrors the post: date + timedelta(days=n), end date minus start date gives .days, and weekday() counts Monday as 0 and Sunday as 6. Like timedelta, it works in days, not months.
1. Making a date
from datetime import date, datetime, timedelta
launch = date(2026, 3, 14)
print(launch)
print(launch.year, launch.month, launch.day)
print(launch.weekday())
print(launch.strftime("%A"))
2026-03-14
2026 3 14
5
Saturday
date(year, month, day) creates a date. date.today() returns the current local date, but these examples use fixed dates so the output never changes. The reference says weekday() returns Monday as 0 and Sunday as 6, so 5 is Saturday.
2. Differences and adding days
Subtracting one date from another gives a timedelta, which the reference defines as a duration. Adding a timedelta to a date moves it forward or backward.
deadline = date(2026, 4, 30)
gap = deadline - launch
print(gap)
print(gap.days)
print(launch + timedelta(days=30))
print(launch - timedelta(weeks=2))
print(launch < deadline)
47 days, 0:00:00
47
2026-04-13
2026-02-28
True
March 14 to April 30 is 47 days. Dates also compare with < and >. A timedelta accepts days, weeks, hours, minutes and seconds as keyword arguments. It does not accept months or years, because their length varies. To move by "one month," you have to decide what that means for your case. Adding 30 days to January 31 lands on March 2, not on the end of February:
print(date(2026, 1, 31) + timedelta(days=30))
2026-03-02
3. Dates with a time of day
datetime adds hours and minutes. Adding a timedelta carries over correctly:
d = datetime(2026, 3, 14, 9, 30)
print(d)
print(d + timedelta(hours=5, minutes=45))
2026-03-14 09:30:00
2026-03-14 15:15:00
4. Date to text: strftime
strftime() takes a format string made of codes. The ones used most often are %Y (four-digit year), %m (month number), %d (day), %H and %M (hour on a 24-hour clock, minute), %B (full month name) and %A (full weekday name). The reference lists the full set.
print(d.strftime("%Y-%m-%d %H:%M"))
print(d.strftime("%B %d, %Y"))
print(d.strftime("%d/%m/%y"))
print(d.isoformat())
2026-03-14 09:30
March 14, 2026
14/03/26
2026-03-14T09:30:00
Note the third line. 14/03/26 is day-first, while 03/14/26 would be month-first. Pick one format on purpose, because readers in different countries read the same digits differently. isoformat() gives the year-month-day standard form.
5. Text to date: fromisoformat and strptime
If your text is already in ISO form, fromisoformat() is the simplest way back:
print(date.fromisoformat("2026-03-14"))
2026-03-14
For any other layout, datetime.strptime(text, format) parses the text using the same codes. The format has to describe the text exactly:
parsed = datetime.strptime("03/14/2026 18:05", "%m/%d/%Y %H:%M")
print(parsed)
print(repr(parsed))
2026-03-14 18:05:00
datetime.datetime(2026, 3, 14, 18, 5)
If the text does not match the format, you get a ValueError, as the reference says:
datetime.strptime("14/03/2026", "%m/%d/%Y")
ValueError: time data '14/03/2026' does not match format '%m/%d/%Y'
Here the "14" cannot be a month, so parsing fails. That is often the first sign that day and month are in the opposite order from what you assumed.
6. days is not the whole duration
A timedelta stores days and seconds separately. The reference warns about a common bug of reading .seconds when the total was intended, and points to total_seconds() instead.
start = datetime(2026, 3, 14, 9, 0)
end = datetime(2026, 3, 16, 17, 30)
span = end - start
print(span)
print(span.days, span.seconds)
print(span.total_seconds())
print(span.total_seconds() / 3600)
2 days, 8:30:00
2 30600
203400.0
56.5
The span is 2 days and 8.5 hours. .seconds shows only the 30,600 seconds (8.5 hours) left over after the 2 days, while total_seconds() gives the whole duration, 203,400 seconds or 56.5 hours.
7. Naive and aware
Everything above is "naive," meaning there is no time zone attached. The reference explains that a naive object cannot tell you which zone it is in; it is up to your program to remember whether it means UTC or local time. If your data crosses time zones, use aware objects, and see the reference for timezone, and the zoneinfo module, which the standard library describes as IANA time zone support. The reference also says datetime.utcnow() is deprecated since Python 3.12 and recommends datetime.now() with a time zone instead.
8. Key takeaways
date(y, m, d)anddatetime(y, m, d, h, mi)build values;date.today()gives the current local date.- Subtracting two dates gives a
timedelta; adding atimedeltashifts a date. There is no month or year unit. strftime()formats a date as text;strptime()andfromisoformat()parse text into dates.- A text/format mismatch raises
ValueError; check day-first versus month-first. - Use
total_seconds()for the whole duration, not.seconds. - Naive values carry no time zone; do not mix them with aware ones.
Sources
More on work & tech from other topics
- Fake Check and Reshipping Job Scams: How They Work · Remote Work Notes
- Can You Record a Zoom or Teams Meeting Without Telling People? Washington and Florida Law · AI at Work, Plainly
- IFERROR vs IFNA, Which Errors Should You Hide? · Spreadsheet Diary