为什么python 2.7不包括Z字符(Zulu或零偏移量)在UTC datetime对象的isoformat字符串结束不像JavaScript?
>>> datetime.datetime.utcnow().isoformat()
'2013-10-29T09:14:03.895210'
而在javascript中
>>> console.log(new Date().toISOString());
2013-10-29T09:38:41.341Z
为什么python 2.7不包括Z字符(Zulu或零偏移量)在UTC datetime对象的isoformat字符串结束不像JavaScript?
>>> datetime.datetime.utcnow().isoformat()
'2013-10-29T09:14:03.895210'
而在javascript中
>>> console.log(new Date().toISOString());
2013-10-29T09:38:41.341Z
当前回答
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'
请注意,这确实符合ISO 8601格式,该格式允许Z或+00:00作为UTC的后缀。注意,后者实际上更好地符合标准,一般来说,时区是如何表示的(UTC是一个特殊情况)。
其他回答
Python日期时间有点笨拙。使用箭头。
> 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的日期。Parse将悄悄地从时间戳中删除微秒。
通过结合以上所有答案,我得到了以下函数:
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)
选择: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.s isoformat(sep=' ')相同
参见:Datetime, Python标准库
选项: strftime()
或者你可以使用strftime来达到同样的效果:
In [4]: d.strftime('%Y-%m-%dT%H:%M:%SZ')
Out[4]: '2014-12-10T12:00:00Z'
注意:此选项仅在您知道指定的日期为UTC时有效。
看到:datetime.strftime ()
附加:人可读时区
更进一步,你可能对显示人类可读的时区信息感兴趣,带strftime %Z时区标志的pytz:
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'
您的目标不应该是添加一个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'
看起来不错,让我们看看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
注意,您需要从dateutil使用isopparse()。因为datetime.fromisoformat()的Python文档说它“不支持解析任意ISO 8601字符串”。
好的,Python datetime对象和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
注:
我有几个目标来解决这个问题:
生成ISO 8601格式的UTC“感知”日期时间字符串 仅使用Python标准库函数创建datetime对象和字符串 使用Django的timezone实用函数、dateutil解析器和JavaScript函数验证datetime对象和字符串
注意,这种方法不包括Z后缀,也不使用utcnow()。但是它是基于Python文档中的建议,并且它在Django和JavaScript中都是合格的。
参见:
停止使用utcnow和utcfromtimestamp 什么是“正确的”JSON日期格式?
下面的javascript和python脚本给出相同的输出。我觉得这就是你想要的。
JavaScript
new Date().toISOString()
Python
from datetime import datetime
datetime.utcnow().isoformat()[:-3]+'Z'
它们给出的输出是格式化为ISO字符串的UTC (zulu)时间,其中有一个3毫秒的有效数字,并附加一个Z。
2019-01-19T23:20:25.459Z