如何获取包括默认时区的当前ISO格式日期时间字符串?

100

我需要生成匹配ISO格式的时间字符串yyyy-mm-ddThh:mm:ss.ssssss-ZO:NEnow()utcnow()类方法几乎可以满足我的要求。

>>> import datetime
>>> #time adjusted for current timezone
>>> datetime.datetime.now().isoformat()
'2010-08-03T03:00:00.000000'
>>> #unadjusted UTC time
>>> datetime.datetime.utcnow().isoformat()
'2010-08-03T10:00:00.000000'
>>>
>>> #How can I do this?
>>> datetime.datetime.magic()
'2010-08-03T10:00:00.000000-07:00'

对于一个 datetime 实例 dstr(d) 等同于 d.isoformat(' '),但是当使用 "{}".format(d) 时,我想要得到与 d.isoformat() 等价的结果,但我猜这是不可能的。 - undefined
6个回答

150

要在Python 3.2+中获取当前的UTC时间:

>>> from datetime import datetime, timezone
>>> datetime.now(timezone.utc).isoformat()
'2015-01-27T05:57:31.399861+00:00'

获取Python 3.3+中的本地时间:

>>> from datetime import datetime, timezone
>>> datetime.now(timezone.utc).astimezone().isoformat()
'2015-01-27T06:59:17.125448+01:00'

解释: datetime.now(timezone.utc)在UTC时间中生成时区感知的datetime对象。如果没有参数调用,则astimezone()会将datetime对象的时区更改为系统的本地时区。时区感知的datetime对象会自动产生正确的ISO格式。


5
从Python 3.6开始,astimezone()方法现在可以在被认为代表系统本地时间的naive实例上调用。 - Asclepius
即使在 Python 3.6 上,也应该使用可感知的datetime对象,以便在当前本地时间不明确(例如在DST转换期间)时正常工作。 - jfs
对于任何因为它是Apache Airflow的格式而查看此内容的人(就像我一样,因为我不是Python专家而被卡了一个小时),这是正确的答案,以便按照airflows匹配相同格式生成当前日期。在这里记录了一些使用说明/为什么它是安全的 - https://coding-stream-of-consciousness.com/2020/04/01/create-a-date-in-airflows-execution_date-format-iso-with-time-zone/. - John Humphreys
@JohnHumphreys-w00te 格式为RFC 3339 - ISO 8601标准的一个配置文件 - jfs

42
你需要将你的datetime对象变成带有时区信息的。从datetime文档中可以看到:

有两种类型的日期和时间对象:“naive”和“aware”。这个区别指的是对象是否具有任何时间区域、夏令时或其他类型的算法或政治时间调整的概念。无论一个naive datetime对象代表协调世界时(UTC)、本地时间还是其他时区的时间,都纯粹取决于程序,就像确定特定数字代表米、英里还是质量一样。Naive datetime对象易于理解和处理,但代价是忽略了现实中的某些方面。

当你拥有一个带有时区信息的datetime对象,你就可以使用isoformat()获取所需输出。

为了使你的datetime对象带有时区信息,你需要子类化tzinfo,就像这里第二个示例一样,或者更简单的方法是使用一个能够自动完成这一过程的包,例如pytzpython-dateutil

使用pytz,代码看起来是这样的:

import datetime, pytz
datetime.datetime.now(pytz.timezone('US/Central')).isoformat()

如果您使用strftime与'%z'格式指令,您还可以控制输出格式,如下:

datetime.datetime.now(pytz.timezone('US/Central')).strftime('%Y-%m-%dT%H:%M:%S.%f%z')

5
不完全正确:%z格式指令打印没有冒号的时区偏移量,但ISO格式在TZ说明符中使用冒号分隔小时和分钟。但是,在时区感知日期时间上调用isoformat()方法将起作用! - tjollans
4
具有时区信息的日期时间对象可以通过 .isoformat() 正确格式化。 - David K. Hess
1
从@DavidK.Hess的评论中可以得出,你第二个例子中的strftime过于复杂。以下代码可以正常工作,并且(在我看来)更加简洁:datetime.now().replace(tzinfo=pytz.timezone("US/Eastern")).isoformat() - jedwards
3
谢谢@jedwards和David - 我已经将其添加到答案中。 - Ofri Raviv
3
不要在可能有多个UTC偏移量的pytz时区中使用datetime.replace() - jfs
显示剩余2条评论

17

使用 arrow:

>>> import arrow
>>> arrow.now().isoformat()
'2015-04-17T06:36:49.463207-05:00'
>>> arrow.utcnow().isoformat()
'2015-04-17T11:37:17.042330+00:00'

7

您可以在Python 2.7+中使用python-dateutil来实现(这在Mac上默认安装):

>>> from datetime import datetime
>>> from dateutil.tz import tzlocal
>>> datetime.now(tzlocal()).isoformat()
'2016-10-22T12:45:45.353489-03:00'

如果您想要从现有的存储字符串进行转换,可以使用以下方法:
>>> from datetime import datetime
>>> from dateutil.tz import tzlocal
>>> from dateutil.parser import parse
>>> parse("2016-10-21T16:33:27.696173").replace(tzinfo=tzlocal()).isoformat()
'2016-10-21T16:33:27.696173-03:00' <-- Atlantic Daylight Time (ADT) 
>>> parse("2016-01-21T16:33:27.696173").replace(tzinfo=tzlocal()).isoformat()
'2016-01-21T16:33:27.696173-04:00' <-- Atlantic Standard Time (AST)

4
九年后。如果你知道时区的话,我喜欢在日期和时间之间使用T。如果你不需要微秒级别的精度。
Python <= 3.8
pip3 install pytz  # needed!

python3
>>> import datetime
>>> import pytz
>>> datetime.datetime.now(pytz.timezone('Europe/Berlin')).isoformat('T', 'seconds')
'2020-11-09T18:23:28+01:00'

已在Ubuntu 18.04和Python 3.6.9上测试通过。


Python >= 3.9

pip3 install tzdata  # only on Windows needed!

py -3
>>> import datetime
>>> import zoneinfo
>>> datetime.datetime.now(zoneinfo.ZoneInfo('Europe/Berlin')).isoformat('T', 'seconds')
'2020-11-09T18:39:36+01:00'

已在 Windows 10 和 Python 3.9.0 上进行测试。


"T"是默认值,但当然明确比含糊不清更好,例如datetime.datetime.now(pytz.timezone('Europe/Berlin')).isoformat(sep='T', timespec='seconds') - undefined

-15

类似以下示例。请注意,我目前位于澳大利亚东部(UTC + 10小时)。

>>> import datetime
>>> dtnow = datetime.datetime.now();dtutcnow = datetime.datetime.utcnow()
>>> dtnow
datetime.datetime(2010, 8, 4, 9, 33, 9, 890000)
>>> dtutcnow
datetime.datetime(2010, 8, 3, 23, 33, 9, 890000)
>>> delta = dtnow - dtutcnow
>>> delta
datetime.timedelta(0, 36000)
>>> hh,mm = divmod((delta.days * 24*60*60 + delta.seconds + 30) // 60, 60)
>>> hh,mm
(10, 0)
>>> "%s%+02d:%02d" % (dtnow.isoformat(), hh, mm)
'2010-08-04T09:33:09.890000+10:00'
>>>

1
修正一下格式问题:"%s%+03d:%02d" % (dtnow.isoformat(), hh, mm) - iw.kuchin
18
使用减法来确定你所在时区和其他任何时区之间的差异是充满危险的。更好的解决方案是提供时区信息。 - D. A.
4
我同意:不要使用这个解决方案。不要重复造轮子。 - Sergey Orshanskiy
3
这不应该被认为是正确答案,看看其他的回答。 - Pascal

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