calendar.timegm: Convert UTC to Unix Timestamps

Published on: September 14, 2026
Reading time: 5 minutes
Developer working with UTC timestamps and Python calendar.timegm

calendar.timegm is a Python standard-library function that converts a date-and-time structure into a Unix timestamp while interpreting every component as UTC. It is useful when a parser, protocol, legacy API, or operating-system function gives you a tuple compatible with time.gmtime() and you need the number of seconds since the Unix epoch.

This guide explains what the function returns, how it differs from time.mktime(), how to combine it with datetime and zoneinfo, and how to avoid subtle timezone bugs in APIs, logs, scheduled jobs, and distributed systems.

What calendar.timegm does

The function receives a sequence containing at least year, month, day, hour, minute, and second. It treats those values as a UTC date and returns the corresponding Unix timestamp. The Unix epoch starts at 1970-01-01 00:00:00 UTC.

import calendar

utc_tuple = (2026, 9, 14, 12, 0, 0)
timestamp = calendar.timegm(utc_tuple)
print(timestamp)

The function is the practical inverse of time.gmtime(). The latter converts a timestamp into a UTC structure, while timegm converts that structure back into seconds.

Round trip with time.gmtime

import calendar
import time

original = time.time()
structure = time.gmtime(original)
restored = calendar.timegm(structure)
print(original, restored)

The restored value normally loses the fractional part because struct_time stores whole seconds. This pattern is valuable for message queues, audit logs, and protocols that exchange integer timestamps.

Why time.mktime is different

time.mktime() interprets its input as local time. Therefore, the same numeric tuple may produce different timestamps on servers configured in different regions. calendar.timegm() always interprets the values as UTC.

import calendar
import time

value = (2026, 9, 14, 9, 0, 0, 0, 0, -1)
print(calendar.timegm(value))
print(time.mktime(value))

If the tuple represents a universal time, using mktime can silently shift the instant by the local UTC offset. Use timegm when UTC is part of the data contract.

Using struct_time

A struct_time object is accepted because it behaves like a sequence. Fields such as weekday and day of year do not replace the main calendar components.

import calendar
import time

parsed = time.strptime("2026-09-14 12:30:00", "%Y-%m-%d %H:%M:%S")
timestamp = calendar.timegm(parsed)

Remember that strptime parses text but does not prove that the source text is UTC. The surrounding application must define the timezone meaning.

Comparison with datetime.timestamp

Modern code often uses timezone-aware datetime objects because they carry more context.

from datetime import datetime, timezone

date = datetime(2026, 9, 14, 12, 0, tzinfo=timezone.utc)
print(date.timestamp())

This is usually the clearest choice when your application already works with datetime. However, calendar.timegm remains convenient for tuple-based interfaces and for code that wants to state explicitly that a structure is UTC.

Converting datetime through a UTC tuple

import calendar
from datetime import datetime, timezone

now = datetime.now(timezone.utc)
timestamp = calendar.timegm(now.utctimetuple())

This conversion discards microseconds. Use now.timestamp() when subsecond precision matters.

Naive datetime values

A naive datetime has no timezone information. Treating it as UTC without knowing its origin is dangerous. A value such as 09:00 could represent São Paulo, New York, or UTC.

from datetime import datetime, timezone

naive = datetime(2026, 9, 14, 9, 0)
explicit_utc = naive.replace(tzinfo=timezone.utc)

replace does not convert an instant. It only declares that the existing clock values belong to UTC. Use it only when that claim is true.

Converting regional time with zoneinfo

from datetime import datetime
from zoneinfo import ZoneInfo

local = datetime(2026, 9, 14, 9, 0, tzinfo=ZoneInfo("America/Sao_Paulo"))
utc = local.astimezone(ZoneInfo("UTC"))
print(utc.timestamp())

Regional zones account for historical offset rules. Converting through zoneinfo is safer than manually adding or subtracting hours.

Parsing API input

APIs should accept a documented format, ideally ISO 8601 with an offset. Parse the value into a timezone-aware object before converting it.

from datetime import datetime

text = "2026-09-14T12:00:00+00:00"
date = datetime.fromisoformat(text)
timestamp = int(date.timestamp())

Use calendar.timegm when the protocol already provides a UTC tuple. Do not strip an offset from a string and then pretend that the remaining numbers are UTC.

Negative timestamps

Many modern platforms support negative timestamps for dates before 1970. Exact range support can vary by operating system and Python build. Applications that process historical dates should test their required boundaries in every deployment environment.

Leap seconds

Traditional Unix timestamps do not model leap seconds as separate ordinary seconds. Python follows platform time behavior and is not intended as an astronomical timescale library. For scientific timing requirements, use a specialized library and an explicitly defined timescale.

Input validation

External date components must be validated. Creating a datetime is a simple way to reject impossible combinations.

from datetime import datetime, timezone

try:
    value = datetime(2026, 2, 30, tzinfo=timezone.utc)
except ValueError as error:
    print("Invalid date", error)

Also define acceptable year limits, reject unexpected types, and document whether the source is UTC or regional time.

Deterministic tests

Timezone code is easier to test with fixed UTC values. Verify both the expected timestamp and the inverse conversion.

import calendar
import time

def test_timegm_round_trip():
    source = (2026, 9, 14, 12, 0, 0, 0, 0, 0)
    timestamp = calendar.timegm(source)
    result = time.gmtime(timestamp)
    assert result[:6] == source[:6]

Avoid tests whose expected result depends on the CI server timezone. UTC-based tests are portable and easier to review.

Seconds, milliseconds, and microseconds

calendar.timegm returns integer seconds. Browser and Java ecosystems often use milliseconds. Databases and telemetry systems may use microseconds or nanoseconds. Always document the unit and convert explicitly.

seconds = calendar.timegm((2026, 9, 14, 12, 0, 0))
milliseconds = seconds * 1000

A correct value in the wrong unit can appear as a date thousands of years away, making unit confusion one of the most common integration errors.

Logs and distributed systems

UTC timestamps make events from different regions sortable. Services should store the instant in UTC and convert it to the user timezone only at presentation time.

event = {
    "name": "job_finished",
    "timestamp": calendar.timegm((2026, 9, 14, 12, 0, 0)),
}

For tracing, add a request identifier and preserve subsecond precision when event ordering requires it.

Scheduled jobs

A scheduler often receives a regional wall-clock time. Convert that time with zoneinfo, then store a UTC instant. Do not pass the regional tuple directly to timegm, because the function will interpret it as UTC and shift the actual execution time.

Database storage

Databases can store timestamps as native timezone-aware values, ISO strings, or Unix integers. Whichever representation you choose, define the timezone and precision. Integer timestamps are compact, but they do not carry the original timezone or formatting intent.

Common mistakes

Frequent mistakes include passing local time to timegm, using mktime for UTC data, dropping microseconds unexpectedly, mixing seconds and milliseconds, assuming tuples include timezone metadata, and relying on the deployment server timezone.

Best practices

Keep internal instants in UTC, use aware datetime objects at boundaries, convert regional wall time with zoneinfo, validate all external components, document units, and reserve calendar.timegm for structures that genuinely represent UTC.

Continue with the Academify guides about Python datetime, Python zoneinfo, Python time, and working with dates in Python.

External references

Read the official calendar.timegm documentation and the official datetime documentation for current behavior and compatibility details.

Conclusion

calendar.timegm provides a focused and predictable conversion from a UTC tuple to a Unix timestamp. It avoids the local-time interpretation of time.mktime and pairs naturally with time.gmtime. Timezone-aware datetime objects are often more expressive in new applications, but timegm remains a reliable tool for tuple-based protocols, logs, parsers, scheduled systems, and legacy integrations where UTC is explicit.

Share:

Facebook
WhatsApp
Twitter
LinkedIn

Article content

    Related articles

    Programmer analyzing code to identify file MIME types with Python
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    mimetypes.guess_file_type: Detect MIME Types

    Learn Python mimetypes.guess_file_type for MIME detection in paths, URLs, uploads, and HTTP responses with safe fallbacks.

    Ler mais

    Tempo de leitura: 5 minutos
    13/09/2026
    Server components representing isolated Python interpreters running in parallel
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    InterpreterPoolExecutor: True Parallelism in Python

    Learn Python InterpreterPoolExecutor for CPU-bound tasks, isolated interpreters, true parallelism, and safer concurrency design.

    Ler mais

    Tempo de leitura: 6 minutos
    13/09/2026
    Microprocessor representing CPUs available to a Python process
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    os.process_cpu_count: Count Available CPUs

    Learn Python os.process_cpu_count to size workers according to the CPUs actually available to the process.

    Ler mais

    Tempo de leitura: 4 minutos
    12/09/2026
    Laptop with digital code representing SQLite BLOB data
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    sqlite3.Blob: Incremental BLOB Reads and Writes

    Learn Python sqlite3.Blob for incremental BLOB reads and writes, lower memory use, and safer binary data handling in SQLite.

    Ler mais

    Tempo de leitura: 5 minutos
    12/09/2026
    Statistical analysis for Python random.binomialvariate
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    random.binomialvariate: Simulate Binomial Outcomes

    Learn Python random.binomialvariate to simulate successes, validate probabilities, and analyze binomial scenarios with practical examples.

    Ler mais

    Tempo de leitura: 5 minutos
    11/09/2026
    Python source code and function signature analysis
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    inspect.signature.bind: Validate Function Arguments

    Learn Python inspect.signature.bind to validate arguments, apply defaults, and build safer decorators and dynamic APIs.

    Ler mais

    Tempo de leitura: 4 minutos
    11/09/2026