Convert datetime to Unix timestamp and convert it back in python
PythonDatetimeTimestampPython Problem Overview
I have dt = datetime(2013,9,1,11)
, and I would like to get a Unix timestamp of this datetime object.
When I do (dt - datetime(1970,1,1)).total_seconds()
I got the timestamp 1378033200
.
When converting it back using datetime.fromtimestamp
I got datetime.datetime(2013, 9, 1, 6, 0)
.
The hour doesn't match. What did I miss here?
Python Solutions
Solution 1 - Python
solution is
import time
import datetime
d = datetime.date(2015,1,5)
unixtime = time.mktime(d.timetuple())
Solution 2 - Python
If you want to convert a python datetime to seconds since epoch you should do it explicitly:
>>> import datetime
>>> datetime.datetime(2012, 04, 01, 0, 0).strftime('%s')
'1333234800'
>>> (datetime.datetime(2012, 04, 01, 0, 0) - datetime.datetime(1970, 1, 1)).total_seconds()
1333238400.0
In Python 3.3+ you can use timestamp()
instead:
>>> import datetime
>>> datetime.datetime(2012, 4, 1, 0, 0).timestamp()
1333234800.0
Solution 3 - Python
What you missed here is timezones.
Presumably you've five hours off UTC, so 2013-09-01T11:00:00 local and 2013-09-01T06:00:00Z are the same time.
You need to read the top of the datetime
docs, which explain about timezones and "naive" and "aware" objects.
If your original naive datetime was UTC, the way to recover it is to use utcfromtimestamp
instead of fromtimestamp
.
On the other hand, if your original naive datetime was local, you shouldn't have subtracted a UTC timestamp from it in the first place; use datetime.fromtimestamp(0)
instead.
Or, if you had an aware datetime object, you need to either use a local (aware) epoch on both sides, or explicitly convert to and from UTC.
If you have, or can upgrade to, Python 3.3 or later, you can avoid all of these problems by just using the timestamp
method instead of trying to figure out how to do it yourself. And even if you don't, you may want to consider borrowing its source code.
(And if you can wait for Python 3.4, it looks like PEP 341 is likely to make it into the final release, which means all of the stuff J.F. Sebastian and I were talking about in the comments should be doable with just the stdlib, and working the same way on both Unix and Windows.)
Solution 4 - Python
Rather than this expression to create a POSIX timestamp from dt
,
(dt - datetime(1970,1,1)).total_seconds()
Use this:
int(dt.strftime("%s"))
I get the right answer in your example using the second method.
EDIT: Some followup... After some comments (see below), I was curious about the lack of support or documentation for %s
in strftime
. Here's what I found:
In the Python source for datetime
and time
, the string STRFTIME_FORMAT_CODES
tells us:
"Other codes may be available on your platform.
See documentation for the C library strftime function."
So now if we man strftime
(on BSD systems such as Mac OS X), you'll find support for %s
:
"%s is replaced by the number of seconds since the Epoch, UTC (see mktime(3))."
Anyways, that's why %s
works on the systems it does. But there are better solutions to OP's problem (that take timezones into account). See @abarnert's accepted answer here.
Solution 5 - Python
For working with UTC timezones:
time_stamp = calendar.timegm(dt.timetuple())
datetime.utcfromtimestamp(time_stamp)
Solution 6 - Python
You've missed the time zone info (already answered, agreed)
arrow
package allows to avoid this torture with datetimes; It is already written, tested, pypi-published, cross-python (2.6 — 3.xx).
All you need: pip install arrow
(or add to dependencies)
Solution for your case
dt = datetime(2013,9,1,11)
arrow.get(dt).timestamp
# >>> 1378033200
bc = arrow.get(1378033200).datetime
print(bc)
# >>> datetime.datetime(2013, 9, 1, 11, 0, tzinfo=tzutc())
print(bc.isoformat())
# >>> '2013-09-01T11:00:00+00:00'
Solution 7 - Python
If your datetime object represents UTC time, don't use time.mktime, as it assumes the tuple is in your local timezone. Instead, use calendar.timegm:
>>> import datetime, calendar
>>> d = datetime.datetime(1970, 1, 1, 0, 1, 0)
>>> calendar.timegm(d.timetuple())
60
Solution 8 - Python
def dt2ts(dt, utc=False):
if utc:
return calendar.timegm(dt.timetuple())
if dt.tzinfo is None:
return int(time.mktime(dt.timetuple()))
utc_dt = dt.astimezone(tz.tzutc()).timetuple()
return calendar.timegm(utc_dt)
If you want UTC timestamp :time.mktime
just for local dt .Use calendar.timegm
is safe but dt must the utc zone so change the zone to utc. If dt in UTC just use calendar.timegm
.
Solution 9 - Python
Well, when converting TO unix timestamp, python is basically assuming UTC, but while converting back it will give you a date converted to your local timezone.
See this question/answer; https://stackoverflow.com/questions/18812638/get-timezone-used-by-datetime-datetime-fromtimestamp
Solution 10 - Python
def datetime_to_epoch(d1):
# create 1,1,1970 in same timezone as d1
d2 = datetime(1970, 1, 1, tzinfo=d1.tzinfo)
time_delta = d1 - d2
ts = int(time_delta.total_seconds())
return ts
def epoch_to_datetime_string(ts, tz_name="UTC"):
x_timezone = timezone(tz_name)
d1 = datetime.fromtimestamp(ts, x_timezone)
x = d1.strftime("%d %B %Y %H:%M:%S")
return x
Solution 11 - Python
This class will cover your needs, you can pass the variable into ConvertUnixToDatetime & call which function you want it to operate based off.
from datetime import datetime
import time
class ConvertUnixToDatetime:
def __init__(self, date):
self.date = date
# Convert unix to date object
def convert_unix(self):
unix = self.date
# Check if unix is a string or int & proceeds with correct conversion
if type(unix).__name__ == 'str':
unix = int(unix[0:10])
else:
unix = int(str(unix)[0:10])
date = datetime.utcfromtimestamp(unix).strftime('%Y-%m-%d %H:%M:%S')
return date
# Convert date to unix object
def convert_date(self):
date = self.date
# Check if datetime object or raise ValueError
if type(date).__name__ == 'datetime':
unixtime = int(time.mktime(date.timetuple()))
else:
raise ValueError('You are trying to pass a None Datetime object')
return type(unixtime).__name__, unixtime
if __name__ == '__main__':
# Test Date
date_test = ConvertUnixToDatetime(datetime.today())
date_test = date_test.convert_date()
print(date_test)
# Test Unix
unix_test = ConvertUnixToDatetime(date_test[1])
print(unix_test.convert_unix())
Solution 12 - Python
import time
from datetime import datetime
time.mktime(datetime.now().timetuple())