【问题标题】:Python: Convert UTC time-tuple to UTC timestampPython:将 UTC 时间元组转换为 UTC 时间戳
【发布时间】: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 您当地时间的时间戳
  • Z UTC 时间戳

那么这意味着Y 没有。秒必须经过“一段时间”才能成为您所在位置的当前时间,Z 必须经过秒数才能使格林威治英格兰的当前时间成为“一段时间”。

现在,最后,让我们回到函数mktimetimegm。这些需要一个时间元组,这只是“一段时间”的另一种表示。请记住,我们给他们传递了一个天真的时间,没有任何本地或 UTC 概念。

假设X 是一个时间元组,代表一个天真的“某个时间”。那么

  • mktime(X) 将返回编号。为了使您的本地当前时间变为“某个时间”,必须经过的秒数,并且
  • timegm(X) 将返回使格林威治英格兰的当前时间等于“某个时间”所必须花费的秒数。

在上面的示例中,nowutc_now 表示幼稚的“某个时间”,当我们将这些“某个时间”值输入 mktimetimegm 时,它们只会返回数字。相应位置(您的位置和英格兰格林威治)必须经过的秒数才能使其当前时间成为“某个时间”。


最后,回到我的问题:我需要将 UTC 时间元组转换为 UTC 时间戳。

首先,没有“UTC 时间元组”的概念——它只是“某个时间”。如果我需要将其转换为 UTC,我只需使用 timegm:

cal.timegm(datetime.timetuple(utc_now))

这将为我提供当前 UTC 时间的时间戳(即英格兰格林威治当前的“某个时间”)。

【问题讨论】:

  • 信息量很大。谢谢。
  • 纪元是Jan 1, 1970, 00:00:00 UTC+0000。在纽约是Dec 31, 1969, 19:00:00 EST-0500。无论本地时钟显示什么,时代都是世界各地的同一时间实例(对于 POSIX 时代,纽约的本地时钟将显示晚上 7 点)。时间戳不依赖于当地时区——它在世界各地的任何给定时刻都完全相同。

标签: python datetime


【解决方案1】:

实际上只有三个不同的值。这两个值:

1363425449.0 (time.mktime(datetime.timetuple(now))
1363425442   (cal.timegm(datetime.timetuple(utc_now)))

仅相差 7 秒,这是您在转储变量时最初看到的:

>>> utc_now
datetime.datetime(2013, 3, 16, 9, 17, 22, 489225)
>>> now
datetime.datetime(2013, 3, 16, 5, 17, 29, 736903)

(注意输出中秒部分的 22 与 29。)

其他两个值完全是错误的,因为您应用了错误类型的参数 - 您使用 UTC 值而不是本地值调用 time.mktime,并且使用本地值而不是本地值调用 cal.timegm UTC 值。文档清楚地说明了预期 - 因此请确保您只使用适当的值。您基本上会看到您的本地时间偏移(从外观上看是 4 小时)在不应该应用的情况下应用(根据错误的位置在不同的方向上)。

当您进行此类诊断时,使用epochconverter.com 会很有帮助,它会为您提供当前的 Unix 时间戳,以便您可以将其与您的输出进行比较。

【讨论】:

  • 文档没有说明参数应该是本地还是 UTC。还有为什么说另外两个值不正确呢?
  • @good_computer:什么意思? mktime 的文档youquoted 明确表示它应该是本地的,而timegm 的文档youquoted 表示元组应该是从gmtime 返回的那种(这是UTC)。如果您在函数需要本地时间时传入 UTC 值,反之亦然,则函数将在您不希望时应用本地/UTC 转换,或者应用它当你确实想要它时。 (可惜API自己检测不到这个,人生就是这样……你要小心了)
  • @good_computer:您的“某个时间”概念在许多框架中也称为“本地日期和时间”——例如 Joda Time 中的LocalDateTime。这是一个没有关联时区的日期/时间。那么您实际上还有问题吗,或者您是否已排序?
猜你喜欢
  • 2019-01-05
  • 2013-12-04
  • 1970-01-01
  • 1970-01-01
  • 2019-08-15
  • 2015-08-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多