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.
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
- Does OSHA Cover Your Home Office? What the Policy Says · Remote Work Notes
- The EU AI Act's AI Literacy Rule: What Employers Must Do · AI at Work, Plainly
- How to Get a Unique List With the UNIQUE Function · Spreadsheet Diary