使用strftime将Python datetime转换为epoch时间戳

300

我有一个来自UTC的时间,想知道它距离纪元以来的秒数。

我正在使用strftime将其转换为秒数。 以2012年4月1日为例。

>>>datetime.datetime(2012,04,01,0,0).strftime('%s')
'1333234800'

2012年4月1日UTC时间从纪元开始是1333238400,但上述代码返回的是1333234800,相差1小时。

看起来strftime将我的系统时间考虑在内,并在某处应用时区偏移。我以为datetime是纯朴的?

如何解决这个问题?如果可能的话,避免导入其他库,除非是标准库。(我有可移植性的问题)


16
我是唯一一个注意到你在数字中使用八进制字面量的人吗? - Fish Monitor
有关Python问题:datetime.strftime('%s')应尊重tzinfo - jfs
4
Python 3.3及以上版本提供了datetime.datetime.timestamp(datetime.datetime.utcnow())函数。 - MarkHu
对于相反的操作,请访问此处:在Python中如何将自纪元以来的秒数转换为datetime对象 - MarkHu
8个回答

569
在Python 3.3+中,你可以使用timestamp()函数:
>>> datetime.datetime(2012,4,1,0,0).timestamp()
1333234800.0

在Python 3.2或更早的版本中,你可以明确地这样做:
 >>> (datetime.datetime(2012,4,1,0,0) - datetime.datetime(1970,1,1)).total_seconds()
 1333238400.0

为什么不应该使用 datetime.strftime('%s') Python实际上不支持将%s作为strftime的参数(如果你查看http://docs.python.org/library/datetime.html#strftime-and-strptime-behavior,它不在列表中),之所以能工作是因为Python将信息传递给了系统的strftime函数,而后者使用了本地时区。
>>> datetime.datetime(2012,04,01,0,0).strftime('%s')
'1333234800'

17
我一直在费尽心思地想弄清楚为什么我经常看到strftime(“%s”),但在文档中找不到它的介绍。感谢你没有提供任何帮助! - Jonathan Vanasco
65
不要使用.strftime("%s"):它不被支持,不具备可移植性,并且可能会在意识到的日期时间对象上产生错误的结果。如果输入值为UTC(如提问中),但本地时区不是UTC,则该方法将失败。 - jfs
2
@earthmeLon,你的括号有误。时间增量(通过两个日期时间相减得到)具有total_seconds,但日期时间没有。 - jleahy
2
这对我不起作用:AttributeError: 'datetime.timedelta'对象没有'total_seconds'属性 - Michael
3
@Michael 这个函数是在 Python 2.7 中新增的,你可能在使用旧版本。对于 2.7 版本之前的版本,你可以使用 td.seconds + td.days*24*3600 来实现。这种方法会丢弃微秒部分。 - jleahy
显示剩余18条评论

112

我在时区等方面遇到了严重的问题。Python处理所有这些事情的方式对我来说相当令人困惑。使用日历模块(参见链接1234),似乎一切都运行良好。

>>> import datetime
>>> import calendar
>>> aprilFirst=datetime.datetime(2012, 04, 01, 0, 0)
>>> calendar.timegm(aprilFirst.timetuple())
1333238400

7
+1因为它是适用于该问题输入的唯一可行答案。 - jfs
这个是可移植的吗? - benjaminz
1
这应该被标记为正确答案,因为它回答了问题的关注点。非常好的表扬。 - Leo Prince
3
这个方法“有效”,但请注意问题陈述:“I have a time in UTC”这种方法始终使用系统的本地时区,无法指定时区。如果在此示例中,aprilFirst 是一个“知道”不同于系统时区的时区实例,则结果将不正确(时区在 timetuple() 调用中丢失)。要获取“知道”日期时间的正确答案,可以在最近的 Python 3 上使用 awaredt.timestamp()。对于 Python 2 来说有点难,一种方法是使用 arrow 库。arrow.get(awaredt).timestamp 将得到正确答案。 - Adam Williamson
1
不错的观点,@AdamWilliamson,但示例中的代码没有本地化datetime对象,因此我假设“我有一个UTC时间”意味着OP有一个不知道的datetime对象,被_假定_为在UTC中,他想要获得一个epoch(如果datetime恰好是TZ-aware,这可能会改变事情)。另外,请记住,这个答案已经快8年了,自那以后发生了很多事情(例如2013年发布了arrow)。 - Savir
显示剩余2条评论

37
import time
from datetime import datetime
now = datetime.now()

time.mktime(now.timetuple())

2
这是一种不正确的写法 time.time() (mktime() 在 DST 转换期间可能会失败,而 time.time() 继续工作)。除非本地时区是 UTC(问题中的输入是 UTC),否则它不能回答问题。即使输入表示本地时间,如果它不使用 tz 数据库并且本地时区在多年内可能具有不同的 utc 偏移量,例如 2010-2015 年的 Europe/Moscow,则 mktime() 也可能在过去/未来的日期失败 - 使用 UTC 时间(如问题中所示)或带时区的 datetime 对象。 - jfs
这里有更多关于将本地时间(例如由.now()返回的时间)转换为纪元时间戳(由mktime()返回的时间)的问题。如果你阅读了它,你就会明白为什么使用UTC输入(在问题中使用)比表示本地时间的简单日期时间对象更可取。 - jfs

17
import time
from datetime import datetime
now = datetime.now()

# same as above except keeps microseconds
time.mktime(now.timetuple()) + now.microsecond * 1e-6

(抱歉,它不允许我评论现有的回答)


这是因为 time.mktime 没有考虑微秒部分,对吗? - Eduardo
1
正确。基于C结构的时间元组结构体没有微秒的空间,因此我们需要从datetime对象中获取信息并将其添加到末尾。 - Charles Plager
除非本地时区是UTC,否则它不会回答问题。 - jfs
在我的机器上,即使我的时区是ET,这个程序也能正常工作。 - Charles Plager
1
这将根据系统的本地时间在不同的系统上提供不同的时间戳。 - Yousaf

7
如果您只需要Unix / Epoch时间戳,这一行代码就可以实现:
created_timestamp = int((datetime.datetime.now() - datetime.datetime(1970,1,1)).total_seconds())
>>> created_timestamp
1522942073L

仅依赖于datetime,在python2和python3中均可使用。


4

对于一个明确的不受时区影响的解决方案,请使用pytz库。

import datetime
import pytz

pytz.utc.localize(datetime.datetime(2012,4,1,0,0), is_dst=False).timestamp()

输出(float):1333238400.0


在 https://dev59.com/sWw05IYBdhLWcg3wuUKZ#21145908 上看到了一个类似的答案,但这个一行代码对于我的用例非常好,因为传入的数据是UTC时间,而仅使用 .timestamp() 会假定它是本地时间。 - Nikhil VJ
这适用于1970年之前的日期。谢谢。被接受的答案对于1970年之前的日期不起作用。(Python 3.7.3 64位Anaconda3) - canbax

3

  1. 这意味着您想要转换现在的时间,而不是一个随机的日期时间对象。
  2. 您不需要使用日历。 time.mktime(randomDateTime.timetuple()) + randomDateTime.microsecond * 1e-6
- Charles Plager
@CharlesPlager,time.mktime是不正确的;它会将参数解释为本地时区,而OP想要将时间解释为UTC(就像calendar.timegm一样)。 - stewbasic
这对我来说是最准确的答案,如果您想将您的时间转换为GMT,并且希望在转换为时期时间戳时保持不变。 - Yousaf
只需按照您的答案, calendar.timegm(datetime.strptime("2019-05-03T05:40:09.770494+00:00"[:16], '%Y-%m-%dT%H:%M').timetuple()) 我有UTC时间戳,无论在哪个系统上运行,它都会给出正确的时间戳,诀窍是使用strptime.timetumple。 - Yousaf

0

1
请注意,这是在Python 3.7中引入的。 - keithpjolley

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接