将datetime转换为unix时间戳,并将其转换回python

Convert datetime to Unix timestamp and convert it back in python

我有dt = datetime(2013,9,1,11),我想得到这个日期时间对象的unix时间戳。

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

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

时间不匹配。我错过了什么?


解决方案是

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

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


你错过的是时区。

大概你有五个小时的时差,所以2013-09-01T11:00:00当地时间和2013-09-01T06:00:00Z是同一时间。

您需要阅读datetime文档的顶部,其中解释了时区和"幼稚"和"感知"对象。

如果原始的日期时间是UTC,恢复它的方法是使用utcfromtimestamp而不是fromtimestamp

另一方面,如果原始的日期时间是本地的,则不应该首先从中减去UTC时间戳;而是使用datetime.fromtimestamp(0)

或者,如果您有一个aware datetime对象,您需要在两侧使用本地(aware)epoch,或者显式地转换为和从UTC转换。

如果您有或可以升级到python 3.3或更高版本,那么您可以通过使用timestamp方法来避免所有这些问题,而不必亲自尝试解决这些问题。即使你不这样做,你也可以考虑借用它的源代码。

(如果您可以等待python 3.4,那么看起来pep 341很可能会进入最终版本,这意味着我和j.f.sebastian在评论中讨论的所有内容都应该只使用stdlib,并且在unix和windows上都以相同的方式工作。)


不是用这个表达式从dt创建posix时间戳,

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

使用此:

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

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

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

datetimetime的python源代码中,字符串STRFTIME_FORMAT_CODES告诉我们:

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

所以现在,如果我们(在Mac OS X等BSD系统上)使用man strftime,您将找到对%s的支持:

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

不管怎样,这就是%s在它所使用的系统上工作的原因。但有更好的解决方案来解决OP的问题(考虑到时区)。请参阅@abarnett接受的答案。


如果要将Python日期时间转换为自epoch以来的秒数,则应显式执行此操作:

1
2
3
4
5
>>> 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()

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


对于使用UTC时区:

1
2
3
time_stamp = calendar.timegm(dt.timetuple())

datetime.utcfromtimestamp(time_stamp)


如果datetime对象表示UTC时间,则不要使用time.mktime,因为它假定tuple在本地时区中。相反,使用calendar.timegm:

1
2
3
4
>>> import datetime, calendar
>>> d = datetime.datetime(1970, 1, 1, 0, 1, 0)
>>> calendar.timegm(d.timetuple())
60


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

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

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

您的案例解决方案

1
2
3
4
5
6
7
8
9
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'

好吧,当转换为unix时间戳时,python基本上假定为utc,但是在转换回unix时间戳时,它会给您一个转换为本地时区的日期。

见此问题/答案;获取datetime.datetime.fromTimestamp()使用的时区


1
2
3
4
5
6
7
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。如果在UTC中使用dt,只需使用calendar.timegm