Learn Python / Dates and Times

Dates and Times

Birthdays, deadlines, timestamps, opening hours: dates and times are everywhere. Python's built-in datetime module handles them, including the tricky parts like month lengths and leap years.

The main types

The datetime module has a few classes you'll use all the time:

Type Holds Example
date year, month, day 2026-10-05
time hour, minute, second 14:30:00
datetime date and time 2026-10-05 14:30:00
timedelta a duration 3 days, 4 hours

Today and now

from datetime import date, datetime

today = date.today()
now = datetime.now()

print(today)
print(now)
print(today.year, today.month, today.day)
print(now.hour, now.minute)
Output

Your output depends on when, and in which time zone, you run it.

Going deeper: Time zones optional

datetime.now() gives a naive datetime: it has no idea which time zone it's in (tzinfo is None). That's fine for a program that only runs in one place. Once you deal with users or servers in different places, use aware datetimes, which carry their time zone with them:

from datetime import datetime, timezone, timedelta

local = datetime.now()
print(local.tzinfo)               # None: naive

utc_now = datetime.now(timezone.utc)
print(utc_now)                    # ends in +00:00

india = timezone(timedelta(hours=5, minutes=30))
print(utc_now.astimezone(india))  # the same moment, Indian time
Output

A common rule is to store times in UTC and convert to the user's time zone only when you display them.

Fixed offsets like +05:30 don't know about daylight saving time. For real place names such as "Europe/London", use ZoneInfo from the zoneinfo module on your own computer: datetime.now(ZoneInfo("Europe/London")).

Creating a specific date

from datetime import date, datetime

moon_landing = date(1969, 7, 20)
meeting = datetime(2026, 3, 14, 15, 30)

print(moon_landing)
print(meeting)
print(moon_landing.weekday())      # Monday is 0, Sunday is 6
print(moon_landing.isoweekday())   # Monday is 1, Sunday is 7
Output

Python checks that dates are real:

from datetime import date

date(2026, 2, 30)
Output

Formatting dates with strftime

strftime() turns a date into text using format codes:

from datetime import datetime

moment = datetime(2026, 3, 14, 15, 9, 26)

print(moment.strftime("%d/%m/%Y"))
print(moment.strftime("%A, %d %B %Y"))
print(moment.strftime("%I:%M %p"))
print(moment.strftime("%Y-%m-%d %H:%M:%S"))
print(f"{moment:%b %d, %Y}")     # format codes work in f-strings too
Output

The most useful codes:

Code Meaning Example
%Y 4-digit year 2026
%m month number 03
%d day of month 14
%B / %b month name / short March / Mar
%A / %a weekday name / short Saturday / Sat
%H hour (24-hour) 15
%I hour (12-hour) 03
%M minute 09
%S second 26
%p AM or PM PM

Parsing text into dates with strptime

strptime() does the opposite: it reads a date from text, using the same codes to describe the layout:

from datetime import datetime

text = "25/12/2026 18:30"
christmas_dinner = datetime.strptime(text, "%d/%m/%Y %H:%M")

print(christmas_dinner)
print(christmas_dinner.strftime("%A"))
Output

If the text doesn't match the format, you get a ValueError. The ISO format YYYY-MM-DD has a shortcut:

from datetime import date

print(date.fromisoformat("2026-07-04"))
Output

Date arithmetic with timedelta

A timedelta is a length of time. Add it to or subtract it from dates:

from datetime import date, timedelta

start = date(2026, 1, 28)

print(start + timedelta(days=7))
print(start + timedelta(weeks=2))
print(start - timedelta(days=30))
Output

Month lengths and leap years are handled for you. Notice how adding a week to January 28 lands in February.

Subtracting two dates gives a timedelta:

from datetime import date

start = date(2026, 1, 1)
end = date(2026, 12, 25)

gap = end - start
print(gap)
print(gap.days, "days")
Output

With datetime values, durations can include hours and minutes:

from datetime import datetime

check_in = datetime(2026, 5, 1, 14, 0)
check_out = datetime(2026, 5, 4, 11, 30)

stay = check_out - check_in
print(stay)
print(stay.total_seconds() / 3600, "hours")
Output

Comparing dates

Dates compare naturally with <, > and ==, and they sort correctly:

from datetime import date

deadline = date(2026, 6, 30)
submitted = date(2026, 7, 2)

if submitted > deadline:
    late = (submitted - deadline).days
    print(f"Late by {late} days")

dates = [date(2026, 5, 1), date(2025, 12, 31), date(2026, 1, 15)]
print(sorted(dates))
Output

Timing your code

To measure how long something takes, subtract two datetime.now() values, or use time.perf_counter():

import time

start = time.perf_counter()
total = sum(i * i for i in range(1_000_000))
elapsed = time.perf_counter() - start

print(f"Result {total:,} in {elapsed:.3f} seconds")
Output

Exercises

Exercise 1: Day of the week

Print the day of the week you were born, or of any date you like, as a full name such as Thursday.

from datetime import date

birthday = date(2000, 1, 1)
Output

Exercise 2: Due date

A library book is borrowed on 2026-03-25 and is due 21 days later. Print the due date as Due: Wednesday 15 April 2026.

from datetime import date, timedelta

borrowed = date(2026, 3, 25)
Output

Exercise 3: Days until an event

Parse the event date from the string and print how many days there are between today and the event: Days to go: 81.

from datetime import date, datetime

today = date(2026, 10, 5)
event_text = "December 25, 2026"
Output

Exercise 4: Age calculator

Write age_on(birth, on_date) that returns a person's age in whole years on a given date. Remember: if their birthday hasn't happened yet that year, subtract one.

from datetime import date

def age_on(birth, on_date):
    pass

print(age_on(date(1990, 8, 15), date(2026, 8, 14)))   # 35
print(age_on(date(1990, 8, 15), date(2026, 8, 15)))   # 36
Output

Date and time tools at a glance

A quick reference for later. The examples use d = date(2026, 3, 15) and from datetime import date, datetime, timedelta. Results marked "e.g." depend on when you run them. The strftime codes, such as %d and %B, are in the table earlier in this lesson.

Tool What it does Example Result
date.today() Today's date date.today() e.g. 2026-10-06
datetime.now() The current date and time datetime.now() e.g. 2026-10-06 14:30:05.123456
date(y, m, d) A specific date date(2026, 3, 15) 2026-03-15
datetime(y, m, d, h, min) A specific date and time datetime(2026, 3, 15, 9, 30) 2026-03-15 09:30:00
.year, .month, .day The parts of a date d.month 3
.weekday() Day of the week: Monday is 0, Sunday is 6 d.weekday() 6
.strftime(format) Formats a date as text d.strftime("%d %b %Y") '15 Mar 2026'
datetime.strptime(text, format) Reads a date from text datetime.strptime("15/03/2026", "%d/%m/%Y") 2026-03-15 00:00:00
.isoformat() The standard YYYY-MM-DD text form d.isoformat() '2026-03-15'
date.fromisoformat(text) Reads a YYYY-MM-DD date date.fromisoformat("2026-03-15") 2026-03-15
timedelta(...) A length of time: days, hours, minutes, seconds, weeks d + timedelta(days=30) 2026-04-14
date2 - date1 The time between two dates, as a timedelta (date(2026, 12, 25) - d).days 285
.total_seconds() A timedelta in seconds timedelta(hours=1, minutes=30).total_seconds() 5400.0
.replace(...) A copy with some parts changed d.replace(year=2027) 2027-03-15
time.perf_counter() A precise clock for timing code (import time) time.perf_counter() e.g. 1234.5678

Summary

  • Import what you need: from datetime import date, datetime, timedelta.
  • date.today() and datetime.now() give the current date and time.
  • strftime() formats a date as text, and strptime() parses text into a date. Both use codes like %Y, %m and %d.
  • Add or subtract a timedelta to move dates. Subtracting two dates gives a timedelta.
  • Dates compare and sort naturally.