将日期时间转换为POSIX时间

56

我该如何在Python中将日期或时间对象转换为POSIX时间戳?有一些方法可以从时间戳创建一个日期时间对象,但似乎没有明显的方法来完成相反的操作。


3
这个问题的答案已经过时了。你应该使用datetime.datetime对象的.timestamp()方法,如下所示below。请将其标记为正确答案。 - Giorgio Balestrieri
还要确保在调用.timestamp()时,使用的是带有时区信息的日期对象,因为时区无关的日期对象"被认为代表本地时间"。 - Marc
6个回答

64
import time, datetime

d = datetime.datetime.now()
print time.mktime(d.timetuple())

似乎根据平台的不同,时间没有mktime方法。 - Tirno
8
请注意,这提供的是当地时间,而不是协调世界时(UTC)。有关UTC,请参阅fixermark的答案 - Craig McQueen
2
准确来说:请注意,mktime 期望输入 本地时间,并且输出没有时区 - 它是一个Unix时间戳,表示以秒为单位的持续时间(始终从纪元开始,因此可以给出时间)。 (datetime.now() 返回当前本地时间。) - Thanatos
1
在夏令时转换期间,有50%的几率返回错误结果。请参见本地时间的问题 - jfs
请注意,由于 POSIX 时间戳仅精确到秒,因此在 timetuple() 步骤中,日期时间将被截断为秒。因此,通过进行此转换会丢失精度。 - Shaun
显示剩余2条评论

23

对于UTC计算,calendar.timegmtime.gmtime的反函数。

import calendar, datetime
d = datetime.datetime.utcnow()
print calendar.timegm(d.timetuple())

1
注意:calendar.timegm() 函数需要 UTC 时间作为输入,但是其结果(时间戳)并不带有任何时区信息。它仅表示自 1970 年 1 月 1 日 00:00:00 (UTC) 起经过的秒数,相当于一个固定的时间点(即“时代”起始日)== 1969-12-31T19:00:00-05:00 (纽约)== 1970-01-01T00:00:00Z(UTC)== 1970-01-01T03:00:00+03:00 (莫斯科)。 - jfs
更正:由于闰秒的存在,“自1970年01月01日00:00:00+00:00以来的秒数”并非经过的SI秒数。可以使用“utc_to_tai()函数”(https://gist.github.com/zed/a912498be36c6a947c33#file-utc_to_tai-py-L25)来计算经过的SI秒数。 - jfs

12

请注意,Python现在(3.5.2)在datetime对象中包含了一个内置方法以用于此功能:

>>> import datetime
>>> now = datetime.datetime(2020, 11, 18, 18, 52, 47, 874766)
>>> now.timestamp() # Local time
1605743567.874766
>>> now.replace(tzinfo=datetime.timezone.utc).timestamp() # UTC
1605725567.874766 # 5 hours delta (I'm in UTC-5)

你确定这正确吗?now是一个时区无关的日期时间对象,调用.timestamp方法将首先假定该对象在本地时间(它确实是隐式的,而且幸运),然后进行转换以提供符合posix标准的时间戳(即自UTC Unix时间以来的秒数)。 - Marc
@Marc,我不理解你的评论:在调用now.timestamp()旁边的示例中,我明确地说“#本地时间”。你能澄清一下问题吗? - Clément
now.timestamp() 给出的是符合 POSIX 标准的时间戳,因为此时 now 是一个本地时区隐式使用的原始时间戳,所以它是一个正确的 UTC Unix 纪元时间戳。当在原始日期时间对象上调用 .timestamp 时,它会假定为本地时区(这就是它的默认值),并给出一个正确的 UTC Unix 时间戳。然而,当你调用 replace 时,日期时间对象不会进行任何转换,它只会将 now 从原始状态转换为有意识的状态。在大多数情况下,这似乎是错误的。 - Marc
哦,这个答案中的“now”部分并不重要。可以随意将其编辑为日期文字。 - Clément
“now”只是因为它如何影响“now.timestamp()”的输出而变得相关。要将“now”从此对话中排除,我们可以执行“datetime.datetime.now().replace(tzinfo=datetime.timezone.utc).timestamp()”,这与“datetime.datetime.utcnow().timestamp()”一样好。它们都有同样的问题,“.timestamp()”很可能会假定错误的时区。时间很令人困惑,所以我可能是错的,但这就是我理解文档的方式。 - Marc
显示剩余3条评论

4

在Python中,time.time()函数可以返回包括微秒在内的浮点数秒数。为了将datetime转换回这种表示形式,您需要添加微秒组件,因为直接使用timetuple函数不包含它。

import time, datetime

posix_now = time.time()

d = datetime.datetime.fromtimestamp(posix_now)
no_microseconds_time = time.mktime(d.timetuple())
has_microseconds_time = time.mktime(d.timetuple()) + d.microsecond * 0.000001

print posix_now
print no_microseconds_time
print has_microseconds_time

不要在往返转换(ts -> local -> ts)中使用本地时间。这可能会在夏令时转换期间出现故障。您可以轻松扩展timegm()以包括微秒,并将其用于ts -> utc -> ts转换。 - jfs

1

这要看情况

你的日期时间对象是时区感知还是无意识的?

时区感知

如果它是时区感知的,那就简单了。

from datetime import datetime, timezone
aware_date = datetime.now(tz=timezone.utc)
posix_timestamp = aware_date.timestamp()

当你使用date.timestamp()时,它会给你一个"POSIX时间戳"

注意:更准确的称呼应该是纪元/Unix时间戳,因为它可能不符合POSIX标准

时区无关

如果它没有时区信息(即无关),那么你需要知道它最初所在的时区,以便我们可以使用replace()将其转换为有时区信息的日期对象。假设你已将其存储/检索为UTC无关的时间。这里我们创建一个示例:

from datetime import datetime, timezone
naive_date = datetime.utcnow()  # this date is naive, but is UTC based
aware_date = naive_date.replace(tzinfo=timezone.utc)  # this date is no longer naive

# now we do as we did with the last one

posix_timestamp = aware_date.timestamp()

尽早将日期转换为时区感知日期总是更好的选择,以防止由于使用原始日期(Python通常会假定它们是本地时间并可能导致错误)而引起的问题。

注意:同时要小心理解纪元,因为它与平台有关。


0

最佳的posix/epoch时间戳与日期时间之间的转换方法:

this_time = datetime.datetime.utcnow() # datetime.datetime type
epoch_time = this_time.timestamp()      # posix time or epoch time
this_time = datetime.datetime.fromtimestamp(epoch_time)

utcnow 输出一个时区无关的日期时间对象,当在其上运行 .timestamp() 时,Python 将假定本地时区(即使它是 UTC 无关的,而不是本地无关的),这将给您带来错误的反馈。 - Marc

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