Python - calendar.timegm() vs. time.mktime()

PythonTimezone

Python Problem Overview


I seem to have a hard time getting my head around this.

What's the difference between calendar.timegm() and time.mktime()?

Say I have a datetime.datetime with no tzinfo attached, shouldn't the two give the same output? Don't they both give the number of seconds between epoch and the date passed as a parameter? And since the date passed has no tzinfo, isn't that number of seconds the same?

>>> import calendar
>>> import time
>>> import datetime
>>> d = datetime.datetime(2010, 10, 10)
>>> calendar.timegm(d.timetuple())
1286668800
>>> time.mktime(d.timetuple())
1286640000.0
>>> 

Python Solutions


Solution 1 - Python

time.mktime() assumes that the passed tuple is in local time, calendar.timegm() assumes it's in GMT/UTC. Depending on the interpretation the tuple represents a different time, so the functions return different values (seconds since the epoch are UTC based).

The difference between the values should be equal to the time zone offset of your local time zone.

Solution 2 - Python

calendar.timegm converts from UTC timestamp, time.mktime converts from local time not UTC.

8 hours difference in their results corresponds exactly to timezone of your location.

Solution 3 - Python

Let me explain this with an example.

>>> import datetime
>>> import time
>>> import calendar
>>> utc_time_now = datetime.datetime.utcnow()
>>> utc_time_now
datetime.datetime(2022, 5, 21, 6, 47, 33, 929433)
>>> time.mktime(utc_time_now.timetuple())
1653095853.0
>>> calendar.timegm(utc_time_now.timetuple())
1653115653
>>> time.tzname
('IST', 'IST')
>>> time.strftime("%z", time.gmtime())
'+0530'
>>> (1653115653-1653095853)
19800

Before we begin with an explanation, please note that 'datetime.datetime.utcnow()' returns a DateTime object which is 'naive' and has no information about your local timezone.

time.mktime()
Applying the above function to a DateTime object considers the 'Timezone'.
So acc. to the example above, when you provide the time '2022-05-21 06:47:33' to time.gmtime(), it assumes that this time is not actually in UTC but in your local timezone ('IST' in my case).

In my case, the timezone is 'IST', which is +05:30 (5 hr, 30 mins) ahead of the UTC timezone. So to return the epoch in the UTC timezone, it subtracts +05:30 (19800 seconds) from the datetime object in its timestamp calculation.
Hence, it returns the timestamp (1653095853.0), which is 19800 seconds less than the original UTC epoch seconds (1653115653).

Note: If your timezone is negative (like -05:30), it will add 19800 seconds to the final epoch calculation. Hence you will see time.gmtime() timestamp is greater by 19800 seconds from the UTC epoch timestamp.

calendar.timegm()
It returns the corresponding Unix timestamp value, assuming an epoch of 1970-01-01. Hence no extra adjustment in the DateTime object is made.
Whatever DateTime object value it gets, it subtracts it from epoch time '1970-01-01' and returns the total seconds() elapsed.

BONUS
If you want to get timestamp epoch seconds from your UTC DateTime object.
1st Method:

>>> utc_time_now
datetime.datetime(2022, 5, 21, 7, 16, 34, 938547)
>>> int((calendar.timegm(utc_time_now.timetuple()) + (utc_time_now.microsecond/1e6))*1000.0)
1653117394938

2nd Method:

>>> utc_time_epoch = datetime.datetime.utcfromtimestamp(0)
>>> utc_time_epoch 
datetime.datetime(1970, 1, 1, 0, 0)
>>> utc_time_now = datetime.datetime.utcnow()
>>> utc_time_now 
datetime.datetime(2022, 5, 21, 7, 16, 34, 938547)
>>> elapsed_time = utc_time_now - utc_time_epoch
>>> elapsed_time
datetime.timedelta(19133, 26194, 938547)
>>> int(elapsed_time.total_seconds() * 1000.0)
1653117394938

Have a good time :)

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionibzView Question on Stackoverflow
Solution 1 - PythonsthView Answer on Stackoverflow
Solution 2 - PythonSilentGhostView Answer on Stackoverflow
Solution 3 - PythonSanjitView Answer on Stackoverflow