我需要将RFC 3339字符串(如“2008-09-03T20:56:55.450686Z”)解析为Python的datetime类型。
我在Python标准库中找到了strptime,但它不是很方便。
最好的方法是什么?
我需要将RFC 3339字符串(如“2008-09-03T20:56:55.450686Z”)解析为Python的datetime类型。
我在Python标准库中找到了strptime,但它不是很方便。
最好的方法是什么?
当前回答
另一种方法是为ISO-8601使用专用解析器,即使用dateutil解析器的等参函数:
from dateutil import parser
date = parser.isoparse("2008-09-03T20:56:35.450686+01:00")
print(date)
输出:
2008-09-03 20:56:35.450686+01:00
标准Python函数datetime.fromisoformat的文档中也提到了该函数:
一个功能更全面的ISO 8601解析器dateutil.parser.isose是在第三方包dateutil中提供。
其他回答
感谢Mark Amery的出色回答,我设计了一个函数来解释所有可能的ISO日期时间格式:
class FixedOffset(tzinfo):
"""Fixed offset in minutes: `time = utc_time + utc_offset`."""
def __init__(self, offset):
self.__offset = timedelta(minutes=offset)
hours, minutes = divmod(offset, 60)
#NOTE: the last part is to remind about deprecated POSIX GMT+h timezones
# that have the opposite sign in the name;
# the corresponding numeric value is not used e.g., no minutes
self.__name = '<%+03d%02d>%+d' % (hours, minutes, -hours)
def utcoffset(self, dt=None):
return self.__offset
def tzname(self, dt=None):
return self.__name
def dst(self, dt=None):
return timedelta(0)
def __repr__(self):
return 'FixedOffset(%d)' % (self.utcoffset().total_seconds() / 60)
def __getinitargs__(self):
return (self.__offset.total_seconds()/60,)
def parse_isoformat_datetime(isodatetime):
try:
return datetime.strptime(isodatetime, '%Y-%m-%dT%H:%M:%S.%f')
except ValueError:
pass
try:
return datetime.strptime(isodatetime, '%Y-%m-%dT%H:%M:%S')
except ValueError:
pass
pat = r'(.*?[+-]\d{2}):(\d{2})'
temp = re.sub(pat, r'\1\2', isodatetime)
naive_date_str = temp[:-5]
offset_str = temp[-5:]
naive_dt = datetime.strptime(naive_date_str, '%Y-%m-%dT%H:%M:%S.%f')
offset = int(offset_str[-4:-2])*60 + int(offset_str[-2:])
if offset_str[0] == "-":
offset = -offset
return naive_dt.replace(tzinfo=FixedOffset(offset))
你得到的确切错误是什么?它像下面这样吗?
>>> datetime.datetime.strptime("2008-08-12T12:20:30.656234Z", "%Y-%m-%dT%H:%M:%S.Z")
ValueError: time data did not match format: data=2008-08-12T12:20:30.656234Z fmt=%Y-%m-%dT%H:%M:%S.Z
如果是,您可以将输入字符串拆分为“.”,然后将微秒添加到获得的日期时间中。
试试看:
>>> def gt(dt_str):
dt, _, us= dt_str.partition(".")
dt= datetime.datetime.strptime(dt, "%Y-%m-%dT%H:%M:%S")
us= int(us.rstrip("Z"), 10)
return dt + datetime.timedelta(microseconds=us)
>>> gt("2008-08-12T12:20:30.656234Z")
datetime.datetime(2008, 8, 12, 12, 20, 30, 656234)
自Python 3.7以来,datetime标准库有一个用于反转datetime.isoformat()的函数。
classmethod datetime.fromisoformat(date_string):以任何有效的ISO 8601格式返回与date_string对应的日期时间,但以下情况除外:时区偏移可能有小数秒。T分隔符可以由任何单个unicode字符替换。当前不支持顺序日期。不支持分数小时和分钟。示例:>>>从datetime导入datetime>>>日期时间。来自同一格式(“2011-11-04”)datetime.datetime(2011,11,4,0,0)>>>datetime.fromisoformat('20111104')datetime.datetime(2011,11,4,0,0)>>>日期时间。来自同一格式('2011-11-04T00:05:23')datetime.datetime(2011,11,4,0,5,23)>>>日期时间。来自同一格式('2011-11-04T00:05:23Z')datetime.datetime(2011,11,4,0,5,23,tzinfo=datetime.timezone.utc)>>>日期时间。来自同一格式('20111104T000523')datetime.datetime(2011,11,4,0,5,23)>>>datetime.fromisoformat('2011-W01-2T0:05:32.283')datetime.datetime(2011,1,4,0,5,23,283000)>>>日期时间。来自同一格式('2011-11-04 00:05:23.283')datetime.datetime(2011,11,4,0,5,23,283000)>>>日期时间。来自同一格式('2011-11-04 00:05:23.283+00:00')datetime.datetime(2011,11,4,0,5,23,283000,tzinfo=datetime.timezone.utc)>>>日期时间。来自同一格式('2011-11-04T00:05:23+04:00')datetime.datetime(2011,11,4,0,5,23,tzinfo=datetime.timezone(datetime.time增量(秒=1440)))3.7版新增。3.11版本中更改:以前,此方法只支持date.isoformat()或datetime.isoformat()发出的格式。
如果您还没有升级到Python 3.11,请务必阅读文档中的警告!
如果使用熊猫,我可以向熊猫推荐时间戳。在那里你可以
ts_1 = pd.Timestamp('2020-02-18T04:27:58.000Z')
ts_2 = pd.Timestamp('2020-02-18T04:27:58.000')
Rant:令人难以置信的是,我们仍然需要担心2021的日期字符串解析等问题。
我发现ciso8601是解析ISO 8601时间戳的最快方法。
它还完全支持RFC 3339,以及一个用于严格解析RFC 3339时间戳的专用函数。
示例用法:
>>> import ciso8601
>>> ciso8601.parse_datetime('2014-01-09T21')
datetime.datetime(2014, 1, 9, 21, 0)
>>> ciso8601.parse_datetime('2014-01-09T21:48:00.921000+05:30')
datetime.datetime(2014, 1, 9, 21, 48, 0, 921000, tzinfo=datetime.timezone(datetime.timedelta(seconds=19800)))
>>> ciso8601.parse_rfc3339('2014-01-09T21:48:00.921000+05:30')
datetime.datetime(2014, 1, 9, 21, 48, 0, 921000, tzinfo=datetime.timezone(datetime.timedelta(seconds=19800)))
GitHub Repo README显示了它们相对于其他答案中列出的所有其他库的加速。
我的个人项目涉及大量ISO 8601解析。很高兴能够切换通话并加快速度。:)
编辑:我后来成为了ciso8601的维护者。现在比以往任何时候都快!