【发布时间】:2017-04-27 02:24:12
【问题描述】:
我的问题:我需要将 UTC 时间元组转换为 UTC 时间戳。但我有一些困惑。
首先是一点信息:
-
time.mktime(tuple):此函数始终返回本地时间的时间戳。这是 localtime() 的反函数。它的参数是 struct_time 或完整的 9 元组,以本地时间表示时间,而不是 UTC。
-
calendar.timegm(tuple):这会从提供的时间元组中返回 UTC 时间戳取一个时间元组,如时间模块中的gmtime()函数返回的,并返回对应的Unix时间戳值。实际上,time.gmtime() 和 timegm() 是互为倒数的
现在让我们做一个测试:
>>> from datetime import datetime
>>> import time
>>> import calendar as cal
>>> utc_now = datetime.utcnow()
>>> now = datetime.now()
>>> utc_now
datetime.datetime(2013, 3, 16, 9, 17, 22, 489225)
>>> now
datetime.datetime(2013, 3, 16, 5, 17, 29, 736903)
>>> time.mktime(datetime.timetuple(utc_now)), time.mktime(datetime.timetuple(now))
(1363439842.0, 1363425449.0)
>>> cal.timegm(datetime.timetuple(utc_now)), cal.timegm(datetime.timetuple(now))
(1363425442, 1363411049)
为什么有四个不同的值?当我想将 UTC 时间元组转换为 UTC 时间戳时,哪一个是正确的?
更新
我想我已经找到了我的困惑的答案,所以让我解释一下。
首先,我们需要知道一些重要的事情:
有两种日期和时间对象:“naive”和“aware”。
感知对象对适用的算法和政治时间调整有足够的了解,例如时区和夏令时信息,以相对于其他感知对象定位自身。感知对象用于表示不可解释的特定时刻 [1]。
一个朴素的对象不包含足够的信息来明确地定位自己相对于其他日期/时间对象。 一个简单的对象是表示协调世界时(UTC)、当地时间还是其他时区的时间完全取决于程序,就像特定数字是否表示米、英里一样取决于程序,或质量。天真的对象很容易理解和使用,但代价是忽略了现实的某些方面。
我们从datetime.utcnow() 或datetime.now() 得到的是“幼稚”的对象。这意味着返回的datetime 对象无论如何都不会说明您的当地时间或UTC 时间——它只是代表“某个时间”。它只是封装了日期和时间信息(年、月、日、小时、分钟、秒等)。您有责任将其与本地或 UTC 的概念联系起来。
因此,请记住,简单的日期时间对象仅代表“某个时间”。 datetime.now() 函数返回与您当前时间相等的“某个时间”,datetime.utcnow() 函数返回“某个时间”,即英格兰格林威治的当前时间(UTC 时间)。
“某个时间”只是日期和时间的值。请注意,在地球上的不同位置,“某个时间”发生在不同的时间。例如,如果“某个时间”的值是 1 月 1 日 10:30,那么它将比格林威治英格兰的当前时间早 5 小时成为纽约的当前时间。
因此,我们可以看到有两件事:一个通用的“某个时间”值,以及“某个时间”在不同“时间”的不同位置变成当前时间的概念。 (这里没有双关语,请继续阅读)
现在,让我们首先定义什么是“纪元”。我们知道“某个时间”只是时间的一个通用值。然后,纪元是发生在英格兰格林威治的“某个时间”,其中参数的值是:January 1 1970, 00:00:00。
“时间戳”不是。自纪元以来经过的秒数。这意味着在英格兰格林威治时间为Jan 1, 1970, 00:00:00 时,时间戳为0。但时间戳大约是。 (5 * 60 * 60) 当时间是纽约的Jan 1, 1970, 00:00:00。
>>> tt = datetime.timetuple(datetime(1970, 1, 1, 0, 0, 0))
>>> cal.timegm(tt)
0
因此,我们可以看到Jan 1, 1970, 00:00:00 的相同“某个时间”值在我们更改位置时具有不同的时间戳。因此,当您谈论时间戳时,您还需要说“哪个位置”是与时间戳相关的,以及该位置与英格兰格林威治有关的向东或向西多少。该位置表示为“时区”。
现在,每个系统(计算机)都配置了一个时区,并且与该时区相关的所有时间戳都有效地变为“本地”。 UTC 是全球参考。
所以,假设您有一个“一段时间”的 X 值,它转换为:
-
Y您当地时间的时间戳 -
ZUTC 时间戳
那么这意味着Y 没有。秒必须经过“一段时间”才能成为您所在位置的当前时间,Z 必须经过秒数才能使格林威治英格兰的当前时间成为“一段时间”。
现在,最后,让我们回到函数mktime 和timegm。这些需要一个时间元组,这只是“一段时间”的另一种表示。请记住,我们给他们传递了一个天真的时间,没有任何本地或 UTC 概念。
假设X 是一个时间元组,代表一个天真的“某个时间”。那么
-
mktime(X)将返回编号。为了使您的本地当前时间变为“某个时间”,必须经过的秒数,并且 -
timegm(X)将返回使格林威治英格兰的当前时间等于“某个时间”所必须花费的秒数。
在上面的示例中,now 和 utc_now 表示幼稚的“某个时间”,当我们将这些“某个时间”值输入 mktime 和 timegm 时,它们只会返回数字。相应位置(您的位置和英格兰格林威治)必须经过的秒数才能使其当前时间成为“某个时间”。
最后,回到我的问题:我需要将 UTC 时间元组转换为 UTC 时间戳。
首先,没有“UTC 时间元组”的概念——它只是“某个时间”。如果我需要将其转换为 UTC,我只需使用 timegm:
cal.timegm(datetime.timetuple(utc_now))
这将为我提供当前 UTC 时间的时间戳(即英格兰格林威治当前的“某个时间”)。
【问题讨论】:
-
信息量很大。谢谢。
-
纪元是
Jan 1, 1970, 00:00:00UTC+0000。在纽约是Dec 31, 1969, 19:00:00 EST-0500。无论本地时钟显示什么,时代都是世界各地的同一时间实例(对于 POSIX 时代,纽约的本地时钟将显示晚上 7 点)。时间戳不依赖于当地时区——它在世界各地的任何给定时刻都完全相同。