Skip to main content

How to Convert Datetime to Seconds in Python

Converting datetime objects to seconds is a task that serves two distinct purposes in Python: obtaining Unix timestamps for storage, APIs, and inter-system communication, or calculating durations between two points in time. Each purpose requires a different approach, and mixing them up is a common source of bugs.

In this guide, you will learn how to convert datetime objects and durations to seconds using Python's built-in modules, avoid critical pitfalls like the .seconds vs .total_seconds() trap, and handle timezones correctly.

Understanding Unix Timestamps (Epoch Time)

A Unix timestamp represents the number of seconds that have elapsed since January 1, 1970, 00:00:00 UTC, commonly referred to as the Unix epoch. This is the standard way to represent a specific moment in time as a single number.

Getting the Current Timestamp

from datetime import datetime, timezone

# Current UTC time as a Unix timestamp
now_utc = datetime.now(timezone.utc)
timestamp = now_utc.timestamp()

print(f"Datetime: {now_utc}")
print(f"Unix timestamp: {timestamp}")
print(f"As integer: {int(timestamp)}")

Output (values will vary based on the current time):

Datetime: 2026-02-13 10:26:28.489621+00:00
Unix timestamp: 1770978388.489621
As integer: 1770978388

Converting a Specific Datetime to a Timestamp

from datetime import datetime, timezone

dt = datetime(2026, 12, 31, 23, 59, 59, tzinfo=timezone.utc)
timestamp = dt.timestamp()

print(f"Datetime: {dt}")
print(f"Timestamp: {timestamp}")

Output:

Datetime: 2026-12-31 23:59:59+00:00
Timestamp: 1798761599.0
Naive Datetimes Can Produce Unexpected Results

Calling .timestamp() on a naive datetime (one without timezone info) causes Python to assume the datetime represents local time on the machine running the code. This means the same code produces different timestamps on machines in different timezones:

from datetime import datetime, timezone

# Naive datetime (no timezone info)
naive_dt = datetime(2026, 12, 31, 23, 59, 59)
print(f"Naive timestamp: {naive_dt.timestamp()}") # Result depends on local timezone

# Explicit UTC datetime (always consistent)
aware_dt = datetime(2026, 12, 31, 23, 59, 59, tzinfo=timezone.utc)
print(f"UTC timestamp: {aware_dt.timestamp()}") # Always 1798761599.0

Always attach timezone information to your datetime objects to ensure consistent, portable results.

Converting Durations with timedelta

The timedelta object represents a span of time rather than a specific moment. Its .total_seconds() method converts the entire duration into seconds.

from datetime import timedelta

# Create a duration
duration = timedelta(hours=2, minutes=30, seconds=45)

# Convert to total seconds
total_seconds = duration.total_seconds()

print(f"Duration: {duration}")
print(f"Total seconds: {total_seconds}")

Output:

Duration: 2:30:45
Total seconds: 9045.0

Calculating the Difference Between Two Datetimes

Subtracting one datetime from another produces a timedelta, which you can then convert to seconds:

from datetime import datetime

start = datetime(2023, 1, 1, 9, 0, 0)
end = datetime(2023, 1, 1, 17, 30, 0)

difference = end - start
seconds_elapsed = difference.total_seconds()

print(f"Duration: {difference}")
print(f"In seconds: {seconds_elapsed}")
print(f"In minutes: {seconds_elapsed / 60}")
print(f"In hours: {seconds_elapsed / 3600}")

Output:

Duration: 8:30:00
In seconds: 30600.0
In minutes: 510.0
In hours: 8.5

The .seconds vs .total_seconds() Trap

This is one of the most common and dangerous pitfalls when working with durations in Python. The .seconds attribute and the .total_seconds() method look similar but behave very differently.

Incorrect approach (.seconds ignores the days component):

from datetime import timedelta

duration = timedelta(days=2, hours=5, minutes=30)

# .seconds only returns the seconds within the current day portion
print(f".seconds: {duration.seconds}")

Output:

.seconds:        19800

The value 19800 represents only 5 hours and 30 minutes (the time portion), completely ignoring the 2 days.

Correct approach (.total_seconds() includes the full duration):

from datetime import timedelta

duration = timedelta(days=2, hours=5, minutes=30)

print(f".total_seconds(): {duration.total_seconds()}")

Output:

.total_seconds(): 192600.0

The value 192600.0 correctly accounts for 2 full days (172800 seconds) plus 5 hours and 30 minutes (19800 seconds).

note

The .seconds attribute returns only the seconds component of the timedelta, which is always a value between 0 and 86399. It is one of three stored components (.days, .seconds, .microseconds) that together define the timedelta internally. Always use .total_seconds() when you need the complete duration expressed in seconds.

Converting Time Components to Seconds Manually

Sometimes you need to convert individual hours, minutes, and seconds values into a total number of seconds without creating datetime objects.

def time_to_seconds(hours=0, minutes=0, seconds=0):
"""Convert time components to total seconds."""
return hours * 3600 + minutes * 60 + seconds

total = time_to_seconds(hours=2, minutes=45, seconds=30)
print(f"2h 45m 30s = {total} seconds")

Output:

2h 45m 30s = 9930 seconds

Converting a time Object to Seconds Since Midnight

The datetime.time object does not have a .total_seconds() method, so you need to compute it from its components:

from datetime import time

t = time(14, 30, 45) # 2:30:45 PM

seconds_since_midnight = t.hour * 3600 + t.minute * 60 + t.second
print(f"{t} is {seconds_since_midnight} seconds since midnight")

Output:

14:30:45 is 52245 seconds since midnight

Converting Seconds Back to a Readable Format

When you have a large number of seconds and need to display it in a human-friendly way, use divmod() to break it down:

def seconds_to_readable(seconds):
"""Convert seconds to a human-readable duration string."""
days, remainder = divmod(int(seconds), 86400)
hours, remainder = divmod(remainder, 3600)
minutes, secs = divmod(remainder, 60)

parts = []
if days:
parts.append(f"{days}d")
if hours:
parts.append(f"{hours}h")
if minutes:
parts.append(f"{minutes}m")
if secs or not parts:
parts.append(f"{secs}s")

return " ".join(parts)

print(seconds_to_readable(90061))
print(seconds_to_readable(3665))
print(seconds_to_readable(45))
print(seconds_to_readable(0))

Output:

1d 1h 1m 1s
1h 1m 5s
45s
0s

Working with Milliseconds and Microseconds

Some APIs and systems use milliseconds (common in JavaScript and Java) or microseconds instead of seconds:

from datetime import datetime, timezone

now = datetime.now(timezone.utc)

# Standard Unix timestamp in seconds
timestamp_sec = now.timestamp()

# Milliseconds (multiply by 1,000)
timestamp_ms = int(now.timestamp() * 1000)

# Microseconds (multiply by 1,000,000)
timestamp_us = int(now.timestamp() * 1_000_000)

print(f"Seconds: {timestamp_sec}")
print(f"Milliseconds: {timestamp_ms}")
print(f"Microseconds: {timestamp_us}")

Output (values will vary):

Seconds:      1770978630.356482
Milliseconds: 1770978630356
Microseconds: 1770978630356482

Measuring Elapsed Time for Performance

When measuring how long a piece of code takes to execute, avoid using datetime.now(). Instead, use time.perf_counter(), which provides the highest available resolution and is not affected by system clock adjustments:

import time

start = time.perf_counter()

# Simulate work
time.sleep(1.5)

end = time.perf_counter()
elapsed = end - start

print(f"Elapsed: {elapsed:.4f} seconds")

Output:

Elapsed: 1.5001 seconds
tip

time.perf_counter() uses a monotonic clock with sub-microsecond resolution on most systems, making it ideal for benchmarking. Use time.monotonic() when you need a monotonic clock but do not require the highest precision, such as for scheduling timeouts.

Timezone-Aware Conversions

Understanding how timezones affect timestamp conversions is essential for writing correct code in applications that span multiple regions:

from datetime import datetime, timezone
from zoneinfo import ZoneInfo # Python 3.9+

# Same local time in two different timezones
dt_utc = datetime(2023, 6, 15, 12, 0, 0, tzinfo=timezone.utc)
dt_ny = datetime(2023, 6, 15, 12, 0, 0, tzinfo=ZoneInfo("America/New_York"))

print(f"UTC noon timestamp: {dt_utc.timestamp()}")
print(f"NYC noon timestamp: {dt_ny.timestamp()}")

# The difference equals the timezone offset
diff = dt_ny.timestamp() - dt_utc.timestamp()
print(f"Offset: {diff / 3600} hours")

Output:

UTC noon timestamp: 1686830400.0
NYC noon timestamp: 1686844800.0
Offset: 4.0 hours

NYC noon happens 4 hours after UTC noon during Eastern Daylight Time, which is why its timestamp is larger.

Method Reference

GoalMethodReturns
Datetime to Unix epochdt.timestamp()float (seconds since epoch)
Full duration to secondstd.total_seconds()float (total seconds)
Seconds component onlytd.secondsint (0 to 86399, partial)
High-precision elapsed timetime.perf_counter()float (seconds)
Monotonic clock for schedulingtime.monotonic()float (seconds)

Conclusion

Converting datetime values to seconds in Python is straightforward once you understand the distinction between timestamps (specific moments in time) and durations (spans of time). Use datetime.timestamp() to get Unix epoch seconds, and use timedelta.total_seconds() to convert durations. Always prefer .total_seconds() over .seconds to avoid silently dropping the days component from your calculations, and always attach explicit timezone information to your datetime objects to ensure consistent behavior across different environments.

For performance measurement, reach for time.perf_counter() instead of datetime subtraction, as it provides higher resolution and immunity to system clock changes.