我有dt = datetime(2013,9,1,11),我想得到这个日期时间对象的unix时间戳。
当我做dt - datetime(1970,1,1)).total_seconds()时,我得到了时间戳1378033200。
当用datetime.fromtimestamp把它转换回来时,我得到了datetime.datetime(2013, 9, 1, 6, 0)。
时间不匹配。我错过了什么?
- 相关:在python中将datetime.date转换为UTC时间戳
- 另一方面,如果您使用的是python 3.3+,那么您确实非常希望使用timestamp方法,而不是自己尝试。首先,这完全避免了从不同时区中减去原始时间的可能性。
- dt是从哪里来的?是当地时间还是UTC时间?
- 我应该在这里提到,真正的解决办法是征服世界,取缔所有时区。这个实现留给读者作为练习。
- @我还想提交一个清除所有代码页和Unicode符号的请求,即禁止所有非ASCII和非默认代码页语言。仍然允许画符号。
- @丹尼尔:请求被拒绝。我不想在这里创造一种单一世界的语言,即使我们这样做了,我也不想让历史语言学家和托尔金学者的生活变得不可能。Unicode已经解决了这个问题,除了某些组织和产品(tron联盟、使用shift-jis而不是utf-8的日本软件、微软仍然为用户文本文件提供默认为cp1252的操作系统,以及假装utf-16是固定宽度字符集和/或与unicode相同的各种sdk)需要是puni之外。把他们排成一行。
解决方案是
1 2 3 4 5
| import time
import datetime
d = datetime.date(2015,1,5)
unixtime = time.mktime(d.timetuple()) |
- 它假设d是一个简单的日期/日期时间对象,表示本地时间(如果操作系统不提供历史TZ DB(过去本地时区的UTC偏移量可能不同),则可能会因不明确的时间或过去/未来日期而失败)。更多的选择。
- 看起来没人介意浮点解。这对每个人都很明显吗?
- 这会降低微秒。可能很有趣。
- 唯一的问题是你不考虑时区。
- 不应该。如果你需要调整TZ,你需要先调整。
你错过的是时区。
大概你有五个小时的时差,所以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在本地时区,则应使用问题中的公式不正确的datetime.fromtimestamp(0)(当前时区中的epoch),而不是datetime(1970, 1,1)(UTC中的unix epoch)。
- @塞巴斯蒂安:我不想详细介绍这三种可能性,但我想你是对的,我应该。
- 顺便说一句,如果系统不存储历史时区信息(例如,在Windows上),fromtimestamp(0)可能会失败。在这种情况下,可以使用pytz。
- @J.F.Sebastian:但是除非你已经知道你在哪个时区,否则pytz没有帮助;要以编程的方式实现这一点,你需要一个不同的库来获取当前的Windows时区并将其转换为pytz时区和/或按名称查找它。
- 还有一个tzlocal模块也可以在Windows上工作。下面介绍如何将UTC时间转换为本地时间。
- @J.F.Sebastian:确切地说,tzlocal是一个独立的库,不是pytz的一部分。您也可以使用dateutil和各种其他替代方法来实现。(在选择众多备选方案之一时:在Windows上,您需要一个将Windows名称映射到标准名称并在pytz中查找它们的名称,或者最终得到相同的不完整/损坏的数据;在现代posix系统上,您需要一个解析/etc/localtime并动态构建时区对象的名称,或者最终得到不明确的名称proble。女士)
- 在这种情况下,dateutil失败(当.fromtimestamp(0)失败时)
- 澄清:tzlocal返回pytz时区,即tzlocal计算出本地时区(也支持Windows名称),pytz提供实际历史时区数据。
- 非常感谢你提到utcfromtimestamp!
不是用这个表达式从dt创建posix时间戳,
1
| (dt - datetime(1970,1,1)).total_seconds() |
使用此:
我用第二种方法在你的例子中得到了正确的答案。
编辑:一些后续…经过一些评论(见下文),我对strftime中缺少对%s的支持或文档感到好奇。以下是我发现的:
在datetime和time的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接受的答案。
- 这是无证行为(我相信)。例如,在Windows上,它会导致"格式字符串无效"。
- @新鲜,有趣。你可能是对的。虽然我在文档中没有看到strftime("%s"),但我只是确认了这一点,以便在Mac和Linux上工作。谢谢。
- 另外,%s给你一个整数,所以你会失去精度。
- 显然它忽略了TZINFO字段。
- 不支持"%s"—它在Windows上对时区敏感的日期时间对象失败。你可以用time.mktime(dt.timetuple())代替
- 是的,我已经更新了我上面的答案,以帮助解释为什么有些系统支持%s,而其他系统不支持。无论如何,我推荐@abarnett的答案。
- @达伦斯通:你不需要读资料来源。time.strftime()和datetime.strftime文档都委托平台strftime(3)功能处理不支持的指令。即使在Mac OS X上,%s也可能失败,例如datetime.strftime("%s")应该尊重tzinfo。
- 您不应该使用%s,因为您将只使用您所在系统的本地化系统时间。如果您试图获得真正的Unix时间戳,则需要使用.timestamp()。
如果要将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 |
- 不考虑时区。
- 您不想使用%s,因为它将被本地化为您当前所在系统的时钟。您应该只使用.timestamp()获得正确的epoch/unix时间。
- %s不适用于Windows系统(ValueError: Invalid format string)
- 如果我输入08或09,小时位置会出错
- "amitnair92只是把8或9
对于使用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。