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


120

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

>>> datetime.datetime.utcnow().isoformat()
'2013-10-29T09:14:03.895210'

而在javascript中

>>>  console.log(new Date().toISOString()); 
2013-10-29T09:38:41.341Z

1
Python日期时间值没有时区信息。如果要将时区信息存储在时间戳中,请尝试pytz或Babel。
tnknepp 2013年

67
datetime.datetime.utcnow().isoformat() + 'Z'
jfs


3
..和丢失的Z令人惊讶地导致某些事情不起作用,例如API调用
cardamom

更糟糕的是,如果datetime的最后一部分为0,它将截断它
ntg

Answers:


52

Python datetime对象默认没有时区信息,没有它,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)

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

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

请注意,此DOES符合ISO 8601格式,该格式允许Z+00:00作为UTC的后缀。请注意,后者实际上更好地符合了标准,并以一般方式表示时区(UTC是一种特例)。


108
我该如何Z代替+00:00
leopoodle

14
警告!!! pytz违反Python的tzinfo协议,使用起来很危险!参见blog.ganssle.io/articles/2018/03/pytz-fastest-footgun.html
ivan_pozdeev

@ivan_pozdeev感谢您的链接,非常有趣。请注意,dateutil直到可以使用PEP 495的Python 3.6才实现允许工作的更改,因此说不pytz使用标准接口是不公平的,因为接口已更改。进行更改之前,使其生效的唯一方法就是做到这pytz一点。
马克·兰瑟姆

67

选项: 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'

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

请参阅:日期时间,Python标准库

选项: strftime()

或者您可以使用strftime以达到相同的效果:

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

注意:仅当您知道指定的日期为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'

1
分隔符不应该T代替空格吗?
Marcello Romani

1
它应该d = datetime.datetime(2014, 12, 10, 12, 0, 0, tzinfo=datetime.timezone.utc)在第2行中。顺便说一句,在RFC3339中,它说一个空格是“ ok”(而不是“ T”)。
MrFuppes

16

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

的JavaScript

new Date().toISOString()

蟒蛇

import datetime

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

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

2019-01-19T23:20:25.459Z

12

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

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

3
非常好的解决方案。对于他们有关的问题Z,您可以.isoformat()[:-6] + 'Z'
删除

11

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

> str(arrow.utcnow())
'2014-05-17T01:18:47.944126+00:00'

Arrow具有与datetime基本上相同的api,但是具有时区和一些其他优点,应该在主库中提供。

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

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

Javascript Date.parse将从时间戳悄然下降微秒。


7
这不能回答问题,因为字符串不以'Z'结尾。
kaleissin18年

3

帖子上有很多不错的答案,但我希望格式能像JavaScript一样准确。这就是我正在使用的并且效果很好。

In [1]: import datetime

In [1]: now = datetime.datetime.utcnow()

In [1]: now.strftime('%Y-%m-%dT%H:%M:%S') + now.strftime('.%f')[:4] + 'Z'
Out[3]: '2018-10-16T13:18:34.856Z'

3
pip install python-dateutil
>>> a = "2019-06-27T02:14:49.443814497Z"
>>> dateutil.parser.parse(a)
datetime.datetime(2019, 6, 27, 2, 14, 49, 443814, tzinfo=tzutc())

2

我通过一些目标解决了这个问题:

  • 生成ISO 8601格式的UTC“感知”日期时间字符串
  • 使用只有 Python标准库函数DateTime对象和字符串创建
  • 使用Django timezone实用程序功能和dateutil解析器验证datetime对象和字符串
  • 使用JavaScript函数来验证ISO 8601日期时间字符串是否支持UTC

该方法包含Z后缀,并且不使用utcnow(),但是它基于Python文档中建议,并且通过Django和JavaScript传递了标记。

让我们从传递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'

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

from django.utils.timezone import is_aware

is_aware(datetime.now(timezone.utc))
>>> True

import dateutil.parser

is_aware(dateutil.parser.parse(datetime.now(timezone.utc).isoformat()))
>>> True

好的,Python日期时间对象和ISO 8601字符串都是UTC“可识别的”。现在,让我们看一下JavaScript对datetime字符串的看法。从这个答案中我们得到:

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

您可能还想阅读此博客文章


1
坚持基本库功能并在较旧的帖子上进行跟进的奖励。
维克多·罗密欧

1

通过结合以上所有答案,我得到了以下功能:

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


def getdata(yy, mm, dd, h, m, s) :
    d = datetime(yy, mm, dd, h, m, s)
    d = d.replace(tzinfo=simple_utc()).isoformat()
    d = str(d).replace('+00:00', 'Z')
    return d


print getdata(2018, 02, 03, 15, 0, 14)

1

我使用摆锤:

import pendulum


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

>>> 2019-10-30T00:11:21.818265Z

0
>>> import arrow

>>> now = arrow.utcnow().format('YYYY-MM-DDTHH:mm:ss.SSS')
>>> now
'2018-11-28T21:34:59.235'
>>> zulu = "{}Z".format(now)
>>> zulu
'2018-11-28T21:34:59.235Z'

或者,一口气获得它:

>>> zulu = "{}Z".format(arrow.utcnow().format('YYYY-MM-DDTHH:mm:ss.SSS'))
>>> zulu
'2018-11-28T21:54:49.639Z'
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.