Python UTC日期时间对象的ISO格式不包括Z(Zulu或零偏移)

Mur*_*uru 94 python datetime timestamp iso8601 python-2.7

为什么python 2.7在UTC日期时间对象的isoformat字符串末尾不包含Z字符(Zulu或零偏移量)?

>>> datetime.datetime.utcnow().isoformat()
'2013-10-29T09:14:03.895210'
Run Code Online (Sandbox Code Playgroud)

而在javascript中

>>>  console.log(new Date().toISOString()); 
2013-10-29T09:38:41.341Z
Run Code Online (Sandbox Code Playgroud)

Man*_*ria 46

选项: isoformat()

Python datetime不支持军事时区后缀,如UTC的'Z'后缀.以下简单的字符串替换可以解决问题:

In [1]: import datetime

In [2]: d = datetime.datetime(2014, 12, 10, 12, 0, 0)

In [3]: str(d).replace('+00:00', 'Z')
Out[3]: '2014-12-10 12:00:00Z'
Run Code Online (Sandbox Code Playgroud)

str(d) 与...基本相同 d.isoformat(sep=' ')

请参阅:Datetime,Python标准库

选项: strftime()

或者你可以strftime用来达到同样的效果:

In [4]: d.strftime('%Y-%m-%d %H:%M:%SZ')
Out[4]: '2014-12-10 12:00:00Z'
Run Code Online (Sandbox Code Playgroud)

注意:仅当您知道指定的日期是UTC时,此选项才有效.

请参阅:datetime.strftime()


附加:人类可读时区

更进一步,您可能有兴趣显示人类可读的时区信息,pytz带有strftime %Z时区标志:

In [5]: import pytz

In [6]: d = datetime.datetime(2014, 12, 10, 12, 0, 0, tzinfo=pytz.utc)

In [7]: d
Out[7]: datetime.datetime(2014, 12, 10, 12, 0, tzinfo=<UTC>)

In [8]: d.strftime('%Y-%m-%d %H:%M:%S %Z')
Out[8]: '2014-12-10 12:00:00 UTC'
Run Code Online (Sandbox Code Playgroud)

  • 很好,这篇文章实际上回答了OP的初始问题(与其他问题不同). (2认同)
  • 分隔符不应该是‘T’而不是空格吗? (2认同)

小智 43

datetime默认情况下,Python 对象没有时区信息,如果没有它,Python实际上违反了ISO 8601规范(如果没有给出时区信息,则假定为本地时间).您可以使用pytz包获取一些默认时区,或直接子类化您tzinfo自己:

from datetime import datetime, tzinfo, timedelta
class simple_utc(tzinfo):
    def tzname(self,**kwargs):
        return "UTC"
    def utcoffset(self, dt):
        return timedelta(0)
Run Code Online (Sandbox Code Playgroud)

然后,您可以手动将时区信息添加到utcnow():

>>> datetime.utcnow().replace(tzinfo=simple_utc()).isoformat()
'2014-05-16T22:51:53.015001+00:00'
Run Code Online (Sandbox Code Playgroud)

请注意,此DOES符合ISO 8601格式,该格式允许Z+00:00作为UTC的后缀.请注意,后者实际上更符合标准,一般如何表示时区(UTC是一种特殊情况.)

  • 如何包含`Z`而不是'+00:00`? (83认同)
  • **警告!!! ** pytz违反了Python的tzinfo协议,使用起来很危险!参见https://blog.ganssle.io/articles/2018/03/pytz-fastest-footgun.html (9认同)
  • @ivan_pozdeev 感谢您的链接,非常有趣。请注意,允许“dateutil”工作的更改直到带有 PEP 495 的 Python 3.6 才实现,因此说“pytz”没有使用标准接口是不公平的,因为接口发生了变化。在更改之前,使其工作的唯一方法是“pytz”的方式。 (2认同)

hig*_*ost 17

您的目标不应该是添加 Z 字符,而应该是生成 ISO 8601 格式的 UTC“感知”日期时间字符串。解决方案是将 UTC 时区对象传递给datetime.now()而不是使用datetime.utcnow()

from datetime import datetime, timezone

datetime.now(timezone.utc)
>>> datetime.datetime(2020, 1, 8, 6, 6, 24, 260810, tzinfo=datetime.timezone.utc)

datetime.now(timezone.utc).isoformat()
>>> '2020-01-08T06:07:04.492045+00:00'
Run Code Online (Sandbox Code Playgroud)

看起来不错,所以让我们看看 Django 并dateutil思考:

from django.utils.timezone import is_aware
is_aware(datetime.now(timezone.utc))
>>> True

from dateutil.parser import isoparse
is_aware(isoparse(datetime.now(timezone.utc).isoformat()))
>>> True
Run Code Online (Sandbox Code Playgroud)

请注意,您需要使用isoparse()fromdateutil.parser因为 Python 文档中datetime.fromisoformat()说它“不支持解析任意 ISO 8601 字符串”。

好的,Pythondatetime对象和 ISO 8601 字符串都是 UTC“感知”。现在让我们看看 JavaScript 对日期时间字符串的看法。借用这个答案,我们得到:

let date = '2020-01-08T06:07:04.492045+00:00';
const dateParsed = new Date(Date.parse(date))

document.write(dateParsed);
document.write("\n");
// Tue Jan 07 2020 22:07:04 GMT-0800 (Pacific Standard Time)

document.write(dateParsed.toISOString());
document.write("\n");
// 2020-01-08T06:07:04.492Z

document.write(dateParsed.toUTCString());
document.write("\n");
// Wed, 08 Jan 2020 06:07:04 GMT
Run Code Online (Sandbox Code Playgroud)

笔记:

我通过几个目标来解决这个问题:

  • 生成 ISO 8601 格式的 UTC“感知”日期时间字符串
  • 使用Python 标准库函数来创建日期时间对象和字符串
  • 使用 Djangotimezone实用程序函数、dateutil解析器和 JavaScript 函数验证日期时间对象和字符串

请注意,此方法包含 Z 后缀且不使用utcnow(). 但它基于Python 文档中建议,并且通过了 Django 和 JavaScript 的测试。

也可以看看:

  • 坚持基本库函数并跟进旧帖子的奖励。 (2认同)

Zag*_*ags 11

简答

datetime.now(timezone.utc).isoformat().replace("+00:00", "Z")
Run Code Online (Sandbox Code Playgroud)

长答案

不包括“Z”的原因是因为datetime.now()甚至datetime.utcnow()返回时区天真的日期时间,即没有关联时区信息的日期时间。要获得时区感知日期时间,您需要将时区作为参数传递给datetime now. 例如:

from datetime import datetime, timezone

datetime.utcnow()
#> datetime.datetime(2020, 9, 3, 20, 58, 49, 22253)
# This is timezone naive

datetime.now(timezone.utc)
#> datetime.datetime(2020, 9, 3, 20, 58, 49, 22253, tzinfo=datetime.timezone.utc)
# This is timezone aware
Run Code Online (Sandbox Code Playgroud)

一旦您拥有时区感知时间戳,isoformat 将包含时区名称。因此,您可以通过以下方式获得 ISO 8601 时间戳:

datetime.now(timezone.utc).isoformat()
#> '2020-09-03T20:53:07.337670+00:00'
Run Code Online (Sandbox Code Playgroud)

“+00:00”是 UTC 的有效 ISO 8601 时区指定。如果您想使用“Z”而不是“+00:00”,则必须自己进行替换:

datetime.now(timezone.utc).isoformat().replace("+00:00", "Z")
#> '2020-09-03T20:53:07.337670Z'
Run Code Online (Sandbox Code Playgroud)

  • 我喜欢这个答案,因为大多数其他答案要么不演示添加“Z”,要么使用朴素的日期时间对象。我觉得使用感知对象是正确的选择。当我看到“datetime.utcnow().timestamp()”和“datetime.now(timezone.utc).timestamp()”之间的区别时,我决定尝试坚持使用感知对象。 (2认同)
  • 我认为考虑到 API 的限制,这是最好的答案,但是这个库确实应该有一个方法来实现这一点。在非常常见的操作中手动更换琴弦组件感觉很脆弱,应该是不必要的。 (2认同)

U2E*_*EF1 8

Python日期时间有点笨拙.使用arrow.

> str(arrow.utcnow())
'2014-05-17T01:18:47.944126+00:00'
Run Code Online (Sandbox Code Playgroud)

Arrow与datetime基本上具有相同的api,但是时区和一些额外的细节应该在主库中.

可以通过以下方式实现与Javascript兼容的格式:

arrow.utcnow().isoformat().replace("+00:00", "Z")
'2018-11-30T02:46:40.714281Z'
Run Code Online (Sandbox Code Playgroud)

Javascript Date.parse将从时间戳中悄然降低微秒.

  • 这不回答问题,因为字符串不以'Z'结尾. (5认同)
  • “有点笨拙”是有关Python日期和时间处理的最善良的话。 (2认同)

Jam*_*ser 8

以下javascript和python脚本提供相同的输出。我认为这就是您要寻找的。

的JavaScript

new Date().toISOString()
Run Code Online (Sandbox Code Playgroud)

蟒蛇

import datetime

datetime.datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%S.%f')[:-3] + 'Z'
Run Code Online (Sandbox Code Playgroud)

他们提供的输出是utc(zelda)时间,格式为ISO字符串,有效数字为3毫秒,并附加Z。

2019-01-19T23:20:25.459Z
Run Code Online (Sandbox Code Playgroud)

  • @МихаилМуругов 当您运行“.isoformat()”时,它会创建一个具有固定数量字符(包括尾随零)的字符串,因此这确实可以可靠地工作 (3认同)

Mic*_*mia 7

在Python> = 3.2中,您可以简单地使用以下代码:

>>> from datetime import datetime, timezone
>>> datetime.now(timezone.utc).isoformat()
'2019-03-14T07:55:36.979511+00:00'
Run Code Online (Sandbox Code Playgroud)

  • 非常好的解决方案。对于他们关于 `Z` 的问题,您可以剪辑偏移量:`.isoformat()[:-6] + 'Z'` (6认同)

小智 6

我用的是钟摆:

import pendulum


d = pendulum.now("UTC").to_iso8601_string()
print(d)

>>> 2019-10-30T00:11:21.818265Z
Run Code Online (Sandbox Code Playgroud)


Ian*_*dby 5

仅使用标准库,不假设时区已经是 UTC,并返回问题中请求的确切格式:

dt.astimezone(timezone.utc).replace(tzinfo=None).isoformat(timespec='milliseconds') + 'Z'
Run Code Online (Sandbox Code Playgroud)

但这确实需要 Python 3.6 或更高版本。