将datetime转换为Unix时间戳,并在python中转换回来

我有dt = datetime(2013,9,1,11),我想获得这个datetime对象的Unix时间戳。

当我执行(dt - datetime(1970,1,1)).total_seconds()时,我得到了时间戳1378033200

当使用datetime.fromtimestamp转换回它时,我得到了datetime.datetime(2013, 9, 1, 6, 0)

时间不对。我错过了什么?

607424 次浏览

你错过的是时区。

假设你距离UTC时间还有5个小时,所以2013-09-01T11:00:00 local时间和2013-09-01T06:00:00Z时间是相同的。

你需要阅读datetime文档的顶部,其中解释了时区以及“naive”和“aware”对象。

如果你最初的天真日期时间是UTC,恢复它的方法是使用utcfromtimestamp而不是fromtimestamp

另一方面,如果您最初的天真datetime是本地的,那么首先就不应该从中减去UTC时间戳;使用datetime.fromtimestamp(0)代替。

或者,如果您有一个可感知的datetime对象,则需要在两侧使用一个本地(可感知的)epoch,或者显式地与UTC进行转换。

如果你已经或可以升级到Python 3.3或更高版本,你可以通过使用timestamp方法来避免所有这些问题,而不是试图自己弄清楚如何做。即使你不这样做,你也可以考虑借用其源代码

(如果你能等到Python 3.4,看起来PEP 341很可能会进入最终版本,这意味着J.F. Sebastian和我在评论中谈论的所有东西都可以用stdlib完成,并且在Unix和Windows上都以相同的方式工作。)

与其用这个表达式从dt创建POSIX时间戳,

(dt - datetime(1970,1,1)).total_seconds()

用这个:

int(dt.strftime("%s"))

我用第二种方法在你的例子中得到了正确答案。

编辑:一些后续…在一些评论之后(见下文),我很好奇在strftime中缺少对%s的支持或文档。以下是我的发现:

datetimetimePython源代码中,字符串STRFTIME_FORMAT_CODES告诉我们:

"Other codes may be available on your platform.
See documentation for the C library strftime function."

所以现在如果我们man strftime(在BSD系统如Mac OS X上),你会发现对%s的支持:

"%s is replaced by the number of seconds since the Epoch, UTC (see mktime(3))."

无论如何,这就是为什么%s可以在它所做的系统上工作。但是对于OP的问题,有更好的解决方案(将时区考虑在内)。请看@abarnert的接受答案。

当转换为unix时间戳时,python基本上是假设UTC,但在转换回来时,它会给你一个转换为本地时区的日期。

参见这个问题/答案; 获取datetime.datetime.fromtimestamp()使用的时区 < / p >

< >强的解决方案

import time
import datetime
d = datetime.date(2015,1,5)


unixtime = time.mktime(d.timetuple())

如果你想将python datetime转换为seconds since epoch,你应该显式地做:

>>> 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

在Python 3.3+中,你可以使用timestamp()来代替:

>>> import datetime
>>> datetime.datetime(2012, 4, 1, 0, 0).timestamp()
1333234800.0

您错过了时区信息(已回答,同意)

arrow允许使用datetimes避免这种折磨;它已经被编写、测试、pypi发布、跨python (2.6 - 3.xx)。

你所需要的:pip install arrow(或添加到依赖项)

解决你的问题

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'

如果datetime对象表示UTC时间,则不要使用time。Mktime,因为它假设元组在您的本地时区。相反,使用calendar.timegm:

>>> import datetime, calendar
>>> d = datetime.datetime(1970, 1, 1, 0, 1, 0)
>>> calendar.timegm(d.timetuple())
60
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)

如果你想要UTC时间戳:time.mktime只为当地的 dt .使用calendar.timegm是安全的,但dt必须UTC区域,所以将区域更改为UTC。如果dt是UTC,则使用calendar.timegm

使用UTC时区:

time_stamp = calendar.timegm(dt.timetuple())


datetime.utcfromtimestamp(time_stamp)
def datetime_to_epoch(d1):
"""
January 1st, 1970 at 00:00:00 UTC is referred to as the Unix epoch
:param d1: input date
:return: seconds since unix epoch
"""
if not d1.tzinfo:
raise ValueError("date is missing timezone information")


d2 = datetime(1970, 1, 1, tzinfo=timezone.utc)
time_delta = d1 - d2
ts = int(time_delta.total_seconds())
return ts




def epoch_to_datetime_string(timestamp, tz_name="UTC", **kwargs):
"""
method to convert unix timestamp to date time string
:param ts: 10 digit unix timestamp in seconds
:param tz_name: timezone name
:param kwargs: formatter=<formatter-string>
:return: date time string in timezone
"""


naive_date = datetime.fromtimestamp(timestamp)
aware_date = naive_date.astimezone(pytz.timezone(tz_name))
formatter = kwargs.pop("formatter", "%d %b %Y %H:%M:%S")
return aware_date.strftime(formatter)

这个类将满足你的需求,你可以将变量传递到ConvertUnixToDatetime &调用您希望它基于哪个函数进行操作。

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())
import time
from datetime import datetime
time.mktime(datetime.now().timetuple())