Skip to main content

Python datetime: How to Work with Dates and Times in Python

Learn the different ways to work with Python’s datetime tools and simplify everything from parsing strings to managing timezone-aware timestamps.
Updated Dec 8, 2025  · 2 min read

Working with dates and times looks simple until you start dealing with formats, time zones, daylight saving rules, or timestamps from multiple systems, at which point it's not an option to store time as raw strings or integers. Python’s datetime module exists to help you manage all of these moving parts in a predictable way.

This guide walks through the core classes, how to create and work with datetime objects, how to perform arithmetic, how to format and parse values, handle time zones, and more. Each section builds on the last, so you can move from basic operations to more advanced patterns.

Core Classes of the Python datetime Module

Before doing anything specific, it helps to understand how Python models dates and times at a conceptual level. The datetime module uses a small set of classes, each focused on one part of the problem. Knowing where each class fits makes the rest of the workflow much easier.

date

When you only need a calendar date without worrying about time of day or time zones, the date class is thing you need. It represents the year, month, and day using familiar attributes.

Here are the attributes:

  • year

  • month

  • day

And the methods:

  • today()

  • fromisoformat()

  • replace()

  • isoformat()

  • weekday()

  • isoweekday()

from datetime import date
d = date(2025, 3, 1)
print(d)

This code creates a simple calendar date. If you enter an invalid combination (like February 30), Python raises what is known as a ValueError.

time

Some tasks only care about the time of day, say, a reminder that runs at 2:30 PM. The time class would be helpful because it stores hours, minutes, seconds, and (not necessary for this example), microseconds or timezone data.

The attributes are: hour, minute, second, microsecond, tzinfo

The methods are: replace(), isoformat()

from datetime import time
t = time(14, 30, 15)
print(t)

This creates a clock time without a date attached. Invalid values (like hour=27) will generate an error.

datetime

Most real-world situations combine both date and time, and that’s where datetime comes in. It’s the most versatile class in the module and the one you’ll use most often for logging, processing, and coordinating events.

The attributes are (in addition to all the ones above): tzinfo

And the methods are now(), utcnow(), fromisoformat(), strptime(), strftime(), astimezone() It also support arithmetic with timedelta, which I'll cover in more detail.

from datetime import datetime
dt = datetime(2025, 3, 1, 14, 30)
print(dt)

This produces a complete timestamp with both date and time components.

timedelta

Whenever you need to measure elapsed time or shift a timestamp forward or backward, timedelta is the right choice. It represents a duration, not a specific moment.

The attributes are: days, seconds, microseconds. It's commonly used for offsets, time differences, and scheduling logic.

from datetime import timedelta
delta = timedelta(days=7, hours=3)
print(delta)

This represents a fixed-length duration. It becomes especially useful when added to or subtracted from a datetime.

tzinfo

tzinfo defines Python’s interface for time zones. You won’t create these directly, but the datetime system uses them whenever you attach or convert time zones.

timezone

timezone is a built-in tzinfo implementation for fixed UTC offsets like UTC or UTC+1. It’s useful for simple cases where daylight saving rules don’t matter.

Creating and Accessing Python datetime Objects

Once you know the classes, the next step is learning how to create instances of them. Python gives you several approaches depending on where your data comes from: manual entry, system time, timestamps, or text.

Using Class constructors

Constructors give you full control over the values you’re creating. This is often the most explicit and error-resistant way to build date, time, or datetime objects.

from datetime import date
d = date(2025, 3, 1)
print(d)

This builds a calendar date directly. Invalid values immediately raise an error, helping catch mistakes early.

from datetime import time
t = time(14, 30, 15)
print(t)

This produces a time-of-day value. Use this when you don’t need the date attached.

from datetime import datetime
dt = datetime(2025, 3, 1, 14, 30)
print(dt)

This creates a full timestamp. Adding a tzinfo argument makes it timezone-aware.

Creating from timestamps

Unix timestamps show up in logs, APIs, and operating systems. Python converts them easily to human-readable datetime objects.

datetime.fromtimestamp(1700000000)
datetime.utcfromtimestamp(1700000000)

The first interprets the timestamp in local time; the second interprets it in UTC.

Class methods for current values

When you need the current date or time, Python provides simple helpers. These are essential for logging, event tracking, and real-time pipelines.

from datetime import datetime, date, timezone
print(date.today())
print(datetime.now())
print(datetime.now(tz=timezone.utc))  # Python 3.12+ preferred

These give you the current system time in either local time or UTC, depending on your needs.

datetime.fromtimestamp(1700000000)
datetime.utcfromtimestamp(1700000000)

These convert epoch timestamps into datetime objects. They’re extremely common when parsing API or database values.

Parsing from strings

Real-world datasets often store timestamps as text. Python provides reliable tools to convert those strings into structured values.

strptime()
from datetime import datetime
dt = datetime.strptime("2025-03-01 14:30", "%Y-%m-%d %H:%M")
print(dt)

strptime() parses a string using a format pattern. If the string doesn’t match exactly, Python raises ValueError.

from datetime import datetime
dt = datetime.strptime("not-a-date", "%Y-%m-%d")

This would fail because the input doesn’t match the expected pattern.

fromisoformat()
datetime.fromisoformat("2025-03-01T14:30:00")

ISO 8601 strings parse cleanly because the structure is standardized. This is often the easiest way to load timestamps from APIs or modern data pipelines.

Performing Date Arithmetic

Once you can create timestamps, the next step is working with them. You can do this by calculating durations, shifting dates, or comparing intervals.

Timedelta for temporal calculations

timedelta models fixed-duration periods like “5 hours” or “2 weeks.” These periods are useful for scheduling, logging, and if you need a simple countdown.

from datetime import datetime, timedelta
dt = datetime(2025, 3, 1, 14, 30)
new_dt = dt + timedelta(days=5)
print(new_dt)

This example shifts the timestamp forward by five days.

start = datetime(2025, 3, 1, 9, 0)
end = datetime(2025, 3, 1, 14, 30)
duration = end - start
print(duration.total_seconds())

Here, subtracting two datetimes gives you a timedelta, which you can convert to seconds, days, or hours.

Fixed-duration vs. calendar-aware arithmetic

Not all units of time are equal. Months vary in length, years may have leap days, and end-of-month behavior can be unpredictable. For these scenarios, timedelta isn’t enough.

dateutil.relativedelta handles “calendar-aware” arithmetic:

from dateutil.relativedelta import relativedelta
from datetime import date
d = date(2025, 1, 31)
print(d + relativedelta(months=1))

This correctly handles the missing “February 31” scenario by shifting the date appropriately.

Formatting and Parsing Dates

Datetime formatting appears everywhere: APIs expect specific formats, users prefer readable text, and logs depend on consistent timestamp strings. Python supports both flexible formatting and standardized representations.

String formatting with strftime

strftime() lets you turn datetime objects into formatted strings using predefined codes.

from datetime import datetime
dt = datetime(2025, 3, 1, 14, 30)
print(dt.strftime("%A, %B %d, %Y at %H:%M"))

This prints a human-readable string with the weekday and full month name.

dt.strftime("%Y-%m-%dT%H:%M:%S")

This produces an ISO-like string suitable for data storage or APIs.

Parsing strings with strptime

from datetime import datetime
dt = datetime.strptime("2025-03-01 14:30", "%Y-%m-%d %H:%M")
print(dt)

This converts text into a datetime object. Any mismatch between the string and pattern raises an error.

Working with ISO 8601 and RFC 3339

ISO 8601 solves the ambiguity found in many regional date formats. Python supports it out of the box:

from datetime import datetime
dt = datetime.fromisoformat("2025-03-01T14:30:00")
print(dt.isoformat())

This is the safest format when exchanging data across systems, APIs, or databases.

Handling Time Zones

Time zones introduce some of the trickiest challenges in temporal programming. Python helps by distinguishing between naive and aware datetime objects and providing tools for real-world zone handling.

Naive vs. aware datetime objects

A naive datetime has no timezone:

from datetime import datetime
naive_dt = datetime(2025, 3, 1, 14, 30)
print(naive_dt.tzinfo)  # None

An aware datetime includes a timezone offset:

from datetime import timezone, timedelta
aware_dt = naive_dt.replace(tzinfo=timezone(timedelta(hours=1)))
print(aware_dt)

Mixing naive and aware values in comparisons or arithmetic usually causes errors.

Using the zoneinfo module

Python's zoneinfo module provides access to real-world IANA time zones:

from zoneinfo import ZoneInfo
from datetime import datetime
dt = datetime(2025, 3, 1, 14, 30, tzinfo=ZoneInfo("Europe/Paris"))
print(dt)

Timezone conversion is simple:

dt.astimezone(ZoneInfo("America/New_York"))

This expresses the exact moment in a different local time zone.

Converting between time zones

You can convert any aware timestamp to another zone using astimezone():

from zoneinfo import ZoneInfo
dt_ny = dt.astimezone(ZoneInfo("America/New_York"))
print(dt_ny)

A common best practice is storing timestamps in UTC and converting only when needed for display.

Comparing and Filtering Dates

Comparisons appear in nearly every workflow. I'm thinking about sorting logs, filtering events, or determining whether something occurred before or after a threshold.

from datetime import datetime
a = datetime(2025, 3, 1, 12, 0)
b = datetime(2025, 3, 1, 15, 0)
print(a < b)  # True

Timezone-aware comparisons account for offsets:

from datetime import datetime
from zoneinfo import ZoneInfo
dt1 = datetime(2025, 3, 1, 12, 0, tzinfo=ZoneInfo("Europe/London"))
dt2 = datetime(2025, 3, 1, 7, 0, tzinfo=ZoneInfo("America/New_York"))
print(dt1 == dt2)  # True — same moment in time

Filtering collections works naturally:

dates = [
    datetime(2025, 3, 1, 10),
    datetime(2025, 2, 20, 9),
    datetime(2025, 3, 1, 8)
]
cutoff = datetime(2025, 3, 1)
filtered = [d for d in dates if d >= cutoff]
print(filtered)

UTC normalization is helpful when working across zones.

More Advanced Use Cases

Datetime shows up in many workflows beyond basic parsing and arithmetic. Here are a few patterns you’ll encounter often.

Unix timestamps

Unix timestamps measure seconds since January 1, 1970 (UTC). They're widely used in systems programming and APIs.

from datetime import datetime
dt = datetime.fromtimestamp(1700000000)
print(dt)

Milliseconds and microseconds require scaling:

ts_ms = 1700000000000
dt_ms = datetime.fromtimestamp(ts_ms / 1000)

ts_us = 1700000000000000
dt_us = datetime.fromtimestamp(ts_us / 1_000_000)

Scheduling and timers

Libraries like schedule depend on datetime values to determine when tasks should run. Whether you're triggering functions every few seconds or scheduling a one-off event later in the day, datetime provides the foundation for those comparisons.

Data analysis patterns

Datetime attributes are often extracted for grouping and time-based analysis:

dt = datetime(2025, 3, 1, 14, 30)
print(dt.year)
print(dt.isocalendar())

In pandas, resampling by period is extremely common:

import pandas as pd
df = pd.DataFrame({
    "value": [10, 12, 15],
    "timestamp": pd.to_datetime([
        "2025-03-01",
        "2025-03-02",
        "2025-03-08"
    ])
}).set_index("timestamp")

print(df.resample("W").sum())

Conclusion

To learn more about datetime, please see this video from our course Working with Dates and Times in Python by Max Shrom and Data Types for Data Science in Python by Jason Myers. 

You may also find our Converting Strings to Dates as datetime Objects tutorial if you need a little additional help converting strings.


Oluseye Jeremiah's photo
Author
Oluseye Jeremiah
LinkedIn

Tech writer specializing in AI, ML, and data science, making complex ideas clear and accessible.

Topics

Learn Python with DataCamp

Course

Introduction to Python

4 hr
6.6M
Master the basics of data analysis with Python in just four hours. This online course will introduce the Python interface and explore popular packages.
See DetailsRight Arrow
Start Course
See MoreRight Arrow
Related

blog

Python Data Types Explained: A Beginner’s Guide

Learn the different Python data types and how to use them effectively.
Moez Ali's photo

Moez Ali

15 min

Working with Dates and Times.png

cheat-sheet

Working with Dates and Times in Python Cheat Sheet

Working with dates and times is essential when manipulating data in Python. Learn the basics of working with datetime data in this cheat sheet.
Richie Cotton's photo

Richie Cotton

Tutorial

Python String to DateTime: How to Convert Strings to DateTime Objects

Learn all about the Python datetime module in this step-by-step guide, which covers string-to-datetime conversion, code samples, and common errors.
Arunn Thevapalan's photo

Arunn Thevapalan

Tutorial

Python timedelta: Working With Time Intervals in Python

In Python, timedelta is a data type within the datetime module used to represent durations or differences between two points in time.
Stephen Gruppetta's photo

Stephen Gruppetta

Tutorial

Python Tutorial for Beginners

Get a step-by-step guide on how to install Python and use it for basic data science functions.
Matthew Przybyla's photo

Matthew Przybyla

Tutorial

Python JSON Data: A Guide With Examples

Learn how to work with JSON in Python, including serialization, deserialization, formatting, optimizing performance, handling APIs, and understanding JSON’s limitations and alternatives.
Moez Ali's photo

Moez Ali

See MoreSee More