如何获取当前的协调世界时(UTC)?

60

我有一个代表五分钟后的 Python datetime 对象,我想将其转换为 UTC 时间。我打算以 RFC 2822 格式输出它并放在 HTTP 头中,但我不确定这对此问题是否重要。我在这个网站上找到了一些关于转换时间对象的信息,看起来可以更简单地完成,但这次我真的想使用 datetime 对象,因为我正在使用 timedelta 来调整它们:

我尝试了类似以下的操作:

from datetime import datetime, timedelta

now = datetime.now()
fiveMinutesLater = datetime.now() + timedelta(minutes=5)
fiveMinutesLaterUtc = ???

时间或日期模块中似乎没有适合我使用的内容。看起来我可能可以通过将datetime对象传递给3或4个函数来完成,但我想知道是否有更简单的方法。

我希望不使用第三方模块,但如果这是唯一合理的选择,我可能会使用它们。


如何在Python中将本地时间转换为UTC? - jfs
字符串:https://dev59.com/lXVD5IYBdhLWcg3wHn2d - Ciro Santilli OurBigBook.com
1
相关 https://dev59.com/hWoy5IYBdhLWcg3wF6ML#8778548 - deceleratedcaviar
9个回答

66

运行此命令以获取一个UTC的简单日期时间(并在其基础上加五分钟):

>>> from datetime import datetime, timedelta
>>> datetime.utcnow()
datetime.datetime(2021, 1, 26, 15, 41, 52, 441598)
>>> datetime.utcnow() + timedelta(minutes=5)
datetime.datetime(2021, 1, 26, 15, 46, 52, 441598)
如果您想要一个带有时区信息的日期时间对象,请在 Python 3.2 或更高版本中运行以下代码:
>>> from datetime import datetime, timezone
>>> datetime.now(timezone.utc)
datetime.datetime(2021, 1, 26, 15, 43, 54, 379421, tzinfo=datetime.timezone.utc)

8
有些奇怪,没有人提到utcnow() 返回一个“naive”日期时间对象--没有时区信息--所以这很可能不是你想要的。文档甚至对此发出了警告。 - Nickolay
3
我已经编辑了答案,提供了一个naive datetime和一个aware datetime的两个选项。 - Flimm
我必须提到utcnow().timestamp()将返回本地时间戳!因此,它绝对不应该被使用。 - undefined

11

1
根据文档,我需要创建tzinfo类的子类来创建一个对象,然后将其传递给“now”函数,以使其了解我的服务器时区。这似乎有点复杂。有人知道更简单的方法吗?如果我找到更简单的方法,我会在这里发布。 - Elias Zamaria
7
请查看 pytz 模块。它是一个包含所有常见时区的 datetime.tzinfo 时区定义的数据库。 - Joe Kington
@EliasZamaria:要获取本地时区作为pytz tzinfo对象,您可以使用tzlocal.get_localzone() - jfs
这在Python 3.3中得到了简化(它支持.astimezone()将naive datetime对象的时区设置为本地(系统)时区,并在Python 3.6中进一步简化,允许您仅使用dt.astimezone(timezone.utc)--有关详细信息,请参见Carlos A.Ibarra的答案 - Nickolay

6

对于那些想要将日期时间对象转换为UNIX纪元以来的UTC秒数的人:

import time
import datetime

t = datetime.datetime.now()
utc_seconds = time.mktime(t.timetuple())

4
从mktime文档来看,这并不准确,它的含义是将本地时间元组转换为从纪元以来的秒数。 - Esteban Feldman
2
这不是回答OP所问的问题。:( - sneak
注意:本地时间可能存在歧义(例如,在“夏令时候退”DST转换期间),而且有50%的可能性mktime()会返回错误的值。如果本地时区在过去/未来有/将有不同的UTC偏移量(许多时区都存在此问题),则它也会失败并且C mktime()不使用tz数据库(例如,在Windows上)。将表示本地时间的无时区datetime对象转换为UTC的可移植解决方案是使用tzlocal.get_localzone()获取本地时区作为pytz tzinfo对象 - jfs

3
请使用以下内容:
from datetime import timezone
utc_datetime = local_datetime.astimezone().astimezone(timezone.utc).replace(tzinfo=None)

假设有一个日期时间对象是假定为本地日期时间,你可以使用以下一系列方法调用将其转换为表示相同 UTC 时间的原始 UTC 日期时间(已在 Python 3.6.3 中测试)。

  1. astimezone() 添加本地时区,使其不再是原始状态。
  2. astimezone(timezone.utc) 将其从本地转换为UTC。
  3. replace(tzinfo=None) 移除时区,使其再次为原始状态,但现在是UTC

示例:

>>> local_datetime = datetime.now()
>>> local_datetime
datetime.datetime(2019, 12, 14, 10, 30, 37, 91818)
>>> local_datetime.astimezone()
datetime.datetime(2019, 12, 14, 10, 30, 37, 91818, tzinfo=datetime.timezone(datetime.timedelta(-1, 68400), 'Eastern Standard Time'))
>>> local_datetime.astimezone().astimezone(timezone.utc)
datetime.datetime(2019, 12, 14, 15, 30, 37, 91818, tzinfo=datetime.timezone.utc)
>>> local_datetime.astimezone().astimezone(timezone.utc).replace(tzinfo=None)
datetime.datetime(2019, 12, 14, 15, 30, 37, 91818)

注意:第一个astimezone()实际上是不需要的,因为Python文档中有这样的说明:
在版本3.6中更改:现在可以在假定表示系统本地时间的无时区实例上调用astimezone()方法。

谢谢!如果您希望拥有一个时区感知的日期时间对象并且正在运行Python 3.6或更高版本,则只需使用local_datetime.astimezone(timezone.utc)即可。此答案不适用于Python < 3.3。 - Nickolay

2

这里是一个标准库解决方案(没有第三方模块),适用于Python 2和3。

要以RFC 2822格式获取当前的UTC时间:

>>> from email.utils import formatdate
>>> formatdate(usegmt=True)
'Fri, 27 Mar 2015 08:29:20 GMT'

要获取未来5分钟的UTC时间:

#!/usr/bin/env python
import time
from email.utils import formatdate

print(formatdate(time.time() + 300, usegmt=True)) # 5 minutes into the future
# -> Fri, 27 Mar 2015 08:34:20 GMT

2
我找到了一种方法,可以获取当前时间,添加一个timedelta对象,将结果转换为UTC,并以RFC 2822格式输出:
time.strftime("%a, %d-%b-%Y %H:%M:%S GMT",
    time.gmtime(time.time() + datetime.timedelta(minutes=5).seconds))

这并没有完全回答我的问题,但我把它放在这里是因为它可能会帮助到其他处于类似情况的人。

编辑:我想补充一点,这个技巧只适用于时间差小于一天的情况。如果你想要一个适用于任何时间差值的方法,你可以使用timedelta.total_seconds()(适用于Python 2.7及以上版本),或者使用86400*timedelta.days + timedelta.seconds。我实际上还没有尝试过这个方法,所以不能确定它是否有效。


注意:%b 可能与语言环境有关。使用 email.utils.formatdate 替代。无关的提示:如果您需要支持 Python 2.6+ 并且不关心微秒,86400*timedelta.days + timedelta.seconds 总是有效的。 - jfs

1
您可以像下面这样在email.Utils模块中使用formatdate方法。
>>> from email.Utils import formatdate
>>> print formatdate()
Sun, 25 Jul 2010 04:02:52 -0000

上面是 RFC 2822 格式的日期时间。默认情况下返回的是 UTC时间,但如果需要本地时间,可以调用 formatdate(localtime=True)。
有关更多信息,请查看 http://docs.python.org/library/email.mime.html#module-email.util

1
它在Python 3中不起作用;您可以改用email.utils(小写)代替。参考链接:https://dev59.com/rHA75IYBdhLWcg3wYH7I#29296267 - jfs

1

将日期字符串转换为UTC:

from time import mktime
from datetime import datetime

mktime(datetime.utctimetuple(datetime.strptime("20110830_1117","%Y%m%d_%H%M")))

1
这样做不起作用---mktime使用本地时区。请参见https://dev59.com/mHA85IYBdhLWcg3wEPRL。 - teu

0
使用具有令人惊叹功能的solutionDelorean lib:
>>> import datetime
>>> import delorean
>>> dt = datetime.datetime.now()
>>> dl = delorean.Delorean(dt, timezone='US/Pacific')
>>> dl.shift('UTC')
Delorean(datetime=2015-03-27 03:12:42.674591+00:00, timezone=UTC)

>>> dl.shift('UTC').datetime
datetime.datetime(2015, 3, 27, 3, 12, 42, 674591, tzinfo=<UTC>)

>>> dl.shift('EST').datetime
datetime.datetime(2015, 3, 26, 22, 12, 42, 674591, tzinfo=<StaticTzInfo 'EST'>)

它可以轻松地在不同的时区之间转换日期时间


2
我不会太相信它,因为delorean的作者不理解.now().now(tz)之间的区别 - jfs

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