Python - calendar.timegm() vs. time.mktime()
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 开发者_如何学Pythonseconds 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
>>>
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.
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.
Let us consider below 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
Get timestamp epoch milliseconds 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 :)
精彩评论