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.
Related Academify guides
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.







