Date & Time in Python | Python Course | Dataplexa

Date & Time in Python

Dates and times appear in almost every real application — order timestamps, user activity logs, scheduled tasks, billing cycles, and data exports all depend on accurate time handling. Python's built-in datetime module gives you everything you need to create, format, parse, compare, and do arithmetic with dates and times — no third-party packages required.

This lesson covers all four core classes, formatting and parsing, timedelta arithmetic, comparison, timezones, timestamp conversion, and a real-world scheduling example.

The Four Core Classes

  • date — stores a calendar date: year, month, day only
  • time — stores a time of day: hour, minute, second, microsecond only
  • datetime — stores both date and time combined — the most commonly used class
  • timedelta — represents a duration or difference between two points in time
from datetime import date, time, datetime, timedelta

# date — year, month, day
d = date(2024, 7, 19)
print(d)              # 2024-07-19
print(d.year, d.month, d.day)    # 2024 7 19

# time — hour, minute, second, microsecond
t = time(14, 30, 0)
print(t)              # 14:30:00

# datetime — date AND time combined
dt = datetime(2024, 7, 19, 14, 30, 0)
print(dt)             # 2024-07-19 14:30:00

# timedelta — a duration
delta = timedelta(days=7, hours=3, minutes=30)
print(delta)          # 7 days, 3:30:00

# datetime.combine — merge separate date and time objects
combined = datetime.combine(d, t)
print(combined)       # 2024-07-19 14:30:00
2024-07-19 2024 7 19 14:30:00 2024-07-19 14:30:00 7 days, 3:30:00 2024-07-19 14:30:00
  • Import from datetime — the module and the main class share the same name, so from datetime import datetime is the standard pattern.
  • Month and day are 1-indexed — January is 1, not 0. Hours use 24-hour format.
  • datetime.combine(date, time) merges a date and a time into a datetime.

Getting the Current Date and Time

from datetime import date, datetime

today = date.today()
print("Today     :", today)

now = datetime.now()
print("Now       :", now)

# Access individual components
print("Year      :", now.year)
print("Month     :", now.month)
print("Day       :", now.day)
print("Hour      :", now.hour)
print("Minute    :", now.minute)
print("Second    :", now.second)

# weekday() — Monday=0, Sunday=6
# isoweekday() — Monday=1, Sunday=7
print("weekday() :", now.weekday())
print("Day name  :", now.strftime("%A"))

# UTC timestamp (preferred for storing in databases)
from datetime import timezone
utc_now = datetime.now(tz=timezone.utc)
print("UTC now   :", utc_now)
Today : 2024-07-19 Now : 2024-07-19 14:32:05.123456 Year : 2024 Month : 7 Day : 19 Hour : 14 Minute : 32 Second : 5 weekday() : 4 Day name : Friday UTC now : 2024-07-19 14:32:05.123456+00:00
  • date.today() returns today's date with no time component.
  • datetime.now() returns current local date and time including microseconds.
  • datetime.now(tz=timezone.utc) returns an aware UTC datetime — preferred for database timestamps.
  • weekday() returns 0 for Monday through 6 for Sunday.

Formatting Dates — strftime()

strftime() converts a date or datetime object into a formatted string. The % format codes control the output. Use it for filenames, receipts, UI display, and export files.

from datetime import datetime

dt = datetime(2024, 7, 19, 14, 30, 5)

# Common patterns
print(dt.strftime("%Y-%m-%d"))           # 2024-07-19  ISO 8601
print(dt.strftime("%m/%d/%Y"))           # 07/19/2024  US style
print(dt.strftime("%d/%m/%Y"))           # 19/07/2024  European style
print(dt.strftime("%d-%b-%Y"))           # 19-Jul-2024
print(dt.strftime("%B %d, %Y"))          # July 19, 2024
print(dt.strftime("%I:%M %p"))           # 02:30 PM    12-hour clock
print(dt.strftime("%H:%M:%S"))           # 14:30:05    24-hour clock
print(dt.strftime("%A, %B %d, %Y"))      # Friday, July 19, 2024

# Practical: timestamped filename
filename = dt.strftime("report_%Y%m%d_%H%M%S.csv")
print(filename)                          # report_20240719_143005.csv

# ISO 8601 with time — standard for APIs and databases
print(dt.isoformat())                    # 2024-07-19T14:30:05
2024-07-19 07/19/2024 19/07/2024 19-Jul-2024 July 19, 2024 02:30 PM 14:30:05 Friday, July 19, 2024 report_20240719_143005.csv 2024-07-19T14:30:05
CodeMeaningExample
%Y4-digit year2024
%mZero-padded month07
%dZero-padded day19
%H24-hour hour14
%I12-hour hour02
%MMinutes30
%SSeconds05
%AFull weekday nameFriday
%BFull month nameJuly
%bAbbreviated monthJul
%pAM/PMPM

Parsing Strings into Dates — strptime()

strptime() does the reverse of strftime() — it parses a date string and converts it into a datetime object. Use it whenever dates arrive as strings from CSV files, APIs, or user input.

from datetime import datetime

# Format must match the input string exactly
dt1 = datetime.strptime("2024-07-19", "%Y-%m-%d")
print(dt1)          # 2024-07-19 00:00:00

dt2 = datetime.strptime("07/19/2024 02:30 PM", "%m/%d/%Y %I:%M %p")
print(dt2)          # 2024-07-19 14:30:00

dt3 = datetime.strptime("19-Jul-2024", "%d-%b-%Y")
print(dt3)          # 2024-07-19 00:00:00

# Parse date part only
print(dt1.date())   # 2024-07-19

# Sort a list of date strings by parsing them first
date_strings = ["2024-03-15", "2024-01-02", "2024-06-30", "2024-01-01"]
parsed = [datetime.strptime(d, "%Y-%m-%d") for d in date_strings]
sorted_dates = [d.strftime("%Y-%m-%d") for d in sorted(parsed)]
print(sorted_dates)

# Error handling — wrong format raises ValueError
try:
    datetime.strptime("19/07/2024", "%Y-%m-%d")
except ValueError as e:
    print("Parse error:", e)
2024-07-19 00:00:00 2024-07-19 14:30:00 2024-07-19 00:00:00 2024-07-19 ['2024-01-01', '2024-01-02', '2024-03-15', '2024-06-30'] Parse error: time data '19/07/2024' does not match format '%Y-%m-%d'

Date Arithmetic with timedelta

A timedelta represents a span of time. Add or subtract timedeltas to calculate future or past moments. Subtracting two dates gives a timedelta.

from datetime import date, datetime, timedelta

today = date(2024, 7, 19)

# Add and subtract
next_week   = today + timedelta(days=7)
in_30_days  = today + timedelta(days=30)
last_week   = today - timedelta(days=7)
print("Next week :", next_week)
print("In 30 days:", in_30_days)
print("Last week :", last_week)

# Difference between two dates → timedelta
start = date(2024, 1, 1)
gap   = today - start
print("Days since Jan 1:", gap.days)
print("Weeks since Jan 1:", gap.days // 7)

# timedelta with hours and minutes
deadline = datetime(2024, 7, 19, 9, 0, 0)
extended  = deadline + timedelta(hours=2, minutes=30)
print("Extended deadline:", extended)

# total_seconds() — convert any duration to seconds
duration = timedelta(days=1, hours=6, minutes=30)
print("Total seconds:", duration.total_seconds())
print("Total hours  :", duration.total_seconds() / 3600)

# Check if something happened within the last 7 days
event_date = date(2024, 7, 15)
if (today - event_date).days <= 7:
    print("Event was within the last week")
Next week : 2024-07-26 In 30 days: 2024-08-18 Last week : 2024-07-12 Days since Jan 1: 200 Weeks since Jan 1: 28 Extended deadline: 2024-07-19 11:30:00 Total seconds: 109800.0 Total hours : 30.5 Event was within the last week
  • timedelta accepts: days, seconds, microseconds, milliseconds, minutes, hours, weeks.
  • Use .total_seconds() rather than .seconds.seconds only gives the seconds component, ignoring days.

Comparing Dates and Datetimes

Date and datetime objects support all standard comparison operators: <, >, ==, !=, <=, >=. This makes filtering and deadline checking straightforward.

from datetime import date, datetime

d1 = date(2024, 1, 1)
d2 = date(2024, 7, 19)

print(d1 < d2)    # True  — d1 is earlier
print(d1 == d2)   # False
print(max(d1, d2))  # 2024-07-19

# Practical: check subscription expiry
today  = date(2024, 7, 19)
expiry = date(2025, 12, 31)
days_left = (expiry - today).days

if expiry > today:
    print(f"Active — {days_left} days remaining")
else:
    print("Subscription expired")

# Sort a list of datetimes
events = [
    datetime(2024, 3, 15, 9, 0),
    datetime(2024, 1, 2, 14, 30),
    datetime(2024, 6, 30, 8, 0),
]
for e in sorted(events):
    print(e.strftime("  %B %d, %Y at %I:%M %p"))
True False 2024-07-19 Active — 530 days remaining January 02, 2024 at 02:30 PM March 15, 2024 at 09:00 AM June 30, 2024 at 08:00 AM

Working with Timezones

A naive datetime has no timezone info. An aware datetime knows its timezone. Always use aware datetimes for any application with multiple users, multiple locations, or database storage.

from datetime import datetime
from zoneinfo import ZoneInfo   # Python 3.9+ built-in

# Create an aware datetime in UTC
utc_now = datetime.now(tz=ZoneInfo("UTC"))
print("UTC     :", utc_now.strftime("%Y-%m-%d %H:%M %Z"))

# Convert to different timezones
eastern = utc_now.astimezone(ZoneInfo("America/New_York"))
pacific = utc_now.astimezone(ZoneInfo("America/Los_Angeles"))
london  = utc_now.astimezone(ZoneInfo("Europe/London"))
tokyo   = utc_now.astimezone(ZoneInfo("Asia/Tokyo"))

print("New York:", eastern.strftime("%Y-%m-%d %H:%M %Z"))
print("Pacific :", pacific.strftime("%Y-%m-%d %H:%M %Z"))
print("London  :", london.strftime("%Y-%m-%d %H:%M %Z"))
print("Tokyo   :", tokyo.strftime("%Y-%m-%d %H:%M %Z"))

# Attach timezone to a specific datetime
meeting = datetime(2024, 7, 19, 10, 0, tzinfo=ZoneInfo("America/New_York"))
print("Meeting (NY)  :", meeting.strftime("%H:%M %Z"))
print("Meeting (UTC) :", meeting.astimezone(ZoneInfo("UTC")).strftime("%H:%M %Z"))
UTC : 2024-07-19 14:32 UTC New York: 2024-07-19 10:32 EDT Pacific : 2024-07-19 07:32 PDT London : 2024-07-19 15:32 BST Tokyo : 2024-07-20 23:32 JST Meeting (NY) : 10:00 EDT Meeting (UTC) : 14:00 UTC
  • zoneinfo is built into Python 3.9+ — no installation needed. For Python 3.8 and below, use the pytz library.
  • .astimezone(tz) converts an aware datetime to any other timezone.
  • Best practice: store all timestamps in UTC, convert to local timezone only for display.

Unix Timestamps

Many systems (databases, APIs, JavaScript) represent time as a Unix timestamp — the number of seconds since January 1, 1970 UTC. Python converts easily in both directions.

from datetime import datetime, timezone

# datetime → Unix timestamp
dt = datetime(2024, 7, 19, 14, 30, 0, tzinfo=timezone.utc)
ts = dt.timestamp()
print("Timestamp:", ts)   # 1721396200.0

# Unix timestamp → datetime
from datetime import datetime, timezone
back = datetime.fromtimestamp(ts, tz=timezone.utc)
print("Back to datetime:", back.strftime("%Y-%m-%d %H:%M:%S %Z"))

# Current time as Unix timestamp
now_ts = datetime.now(tz=timezone.utc).timestamp()
print("Now (Unix):", int(now_ts))
Timestamp: 1721396200.0 Back to datetime: 2024-07-19 14:30:00 UTC Now (Unix): 1721396400

Real-World Example — Subscription Manager

from datetime import date, timedelta

def subscription_report(users):
    today = date.today()
    # Use a fixed date for consistent example output
    today = date(2024, 7, 19)

    print(f"{'Name':<12} {'Expiry':<14} {'Status':<12} {'Days Left'}")
    print("-" * 52)
    for user in sorted(users, key=lambda u: u["expiry"]):
        expiry    = user["expiry"]
        days_left = (expiry - today).days
        if days_left < 0:
            status = "EXPIRED"
        elif days_left <= 7:
            status = "EXPIRING SOON"
        else:
            status = "Active"
        print(f"{user['name']:<12} {expiry.strftime('%Y-%m-%d'):<14} {status:<14} {days_left:>4}")

users = [
    {"name": "Alice",  "expiry": date(2024, 7, 15)},  # expired
    {"name": "Bob",    "expiry": date(2024, 7, 22)},  # expiring soon
    {"name": "Carol",  "expiry": date(2024, 8, 1)},   # active
    {"name": "Dave",   "expiry": date(2025, 1, 1)},   # active
    {"name": "Eve",    "expiry": date(2024, 7, 19)},  # expires today
]

subscription_report(users)

# Calculate renewal dates (30-day extension from today)
print()
today = date(2024, 7, 19)
for user in users:
    if (user["expiry"] - today).days <= 7:
        renewal = today + timedelta(days=30)
        print(f"  {user['name']}: renewal would be {renewal.strftime('%B %d, %Y')}")
Name Expiry Status Days Left ---------------------------------------------------- Alice 2024-07-15 EXPIRED -4 Eve 2024-07-19 EXPIRING SOON 0 Bob 2024-07-22 EXPIRING SOON 3 Carol 2024-08-01 Active 13 Dave 2025-01-01 Active 166 Alice: renewal would be August 18, 2024 Eve: renewal would be August 18, 2024 Bob: renewal would be August 18, 2024

Quick Reference Table

ToolPurposeKey Usage
dateCalendar date onlydate.today()
datetimeDate and time combineddatetime.now()
timedeltaDuration / date arithmetictimedelta(days=n)
strftime()datetime → formatted stringdt.strftime("%Y-%m-%d")
strptime()String → datetimedatetime.strptime(s, fmt)
isoformat()datetime → ISO 8601 stringdt.isoformat()
timestamp()datetime → Unix timestampdt.timestamp()
ZoneInfoTimezone-aware datetimesdatetime.now(tz=ZoneInfo("UTC"))
total_seconds()timedelta → float in secondsdelta.total_seconds()

Practice

Which class stores only a calendar date with no time component?



What method converts a datetime object into a formatted string?



What type is returned when you subtract two date objects?



What format code produces a four-digit year in strftime()?



What is the difference between a naive and an aware datetime?



Which timedelta method gives the full duration as a single float in seconds?



Quick Quiz

What does date.today() return?





What does datetime.strptime("2024-07-19", "%Y-%m-%d") return?





Which timedelta attribute gives the total duration as a single float in seconds?





What integer does weekday() return for Monday?





Which module built into Python 3.9+ handles timezone-aware datetimes?





What is the best practice for handling timestamps in a global application?





NEXT UP
Virtual Environments in Python
Learn to isolate project dependencies so your packages never conflict — the foundation of professional Python development.