如何在 Python 中不使用 dateutil 将可识别时区的字符串转换为 datetime?

我必须将像 "2012-11-01T04:16:13-04:00"这样的时区感知字符串转换为 Pythondatetime对象。

我看到了 dateutil模块,它有一个解析函数,但我真的不想使用它,因为它添加了一个依赖项。

那么我该怎么做呢? 我尝试了下面这样的方法,但是没有成功。

datetime.datetime.strptime("2012-11-01T04:16:13-04:00", "%Y-%m-%dT%H:%M:%S%Z")
180600 次浏览

从 Python 3.7开始,datetime.datetime.fromisoformat()可以处理您的格式:

>>> import datetime
>>> datetime.datetime.fromisoformat('2012-11-01T04:16:13-04:00')
datetime.datetime(2012, 11, 1, 4, 16, 13, tzinfo=datetime.timezone(datetime.timedelta(days=-1, seconds=72000)))

在较老的 Python 版本中,如果没有大量煞费苦心的手动定义时区,就不可能做到这一点。

Python 不包含时区数据库,因为它过时得太快了。相反,Python 依赖于外部库来为您提供正确配置的时区,这些库的发布周期要快得多。

作为一个副作用,这意味着时区 解析也需要一个外部库。如果 dateutil对你来说太重了,改用 iso8601,它会很好地解析你的特定格式:

>>> import iso8601
>>> iso8601.parse_date('2012-11-01T04:16:13-04:00')
datetime.datetime(2012, 11, 1, 4, 16, 13, tzinfo=<FixedOffset '-04:00'>)

iso8601是一个 巨大的4KB 小。相比之下,总 python-dateutil的148KB。

从 Python 3.2开始,Python 可以处理简单的基于偏移量的时区,而 %z将在一个时间戳中解析 -hhmm+hhmm时区偏移量。这意味着,对于 ISO 8601时间戳,您必须删除时区中的 ::

>>> from datetime import datetime
>>> iso_ts = '2012-11-01T04:16:13-04:00'
>>> datetime.strptime(''.join(iso_ts.rsplit(':', 1)), '%Y-%m-%dT%H:%M:%S%z')
datetime.datetime(2012, 11, 1, 4, 16, 13, tzinfo=datetime.timezone(datetime.timedelta(-1, 72000)))

巨蟒15873期正在跟踪缺乏适当的 ISO8601解析的情况。

下面是使用 dateutil 包的用于 datetime 对象的 Python医生

from dateutil.parser import parse


get_date_obj = parse("2012-11-01T04:16:13-04:00")
print get_date_obj

我刚接触巨蟒,但我找到了改变的方法

2017-05-27T07:20:18.000-04:00

2017-05-27T07:20:18没有下载新的实用程序。

from datetime import datetime, timedelta


time_zone1 = int("2017-05-27T07:20:18.000-04:00"[-6:][:3])
>>returns -04


item_date = datetime.strptime("2017-05-27T07:20:18.000-04:00".replace(".000", "")[:-6], "%Y-%m-%dT%H:%M:%S") + timedelta(hours=-time_zone1)

我相信有更好的方法来做到这一点,而不需要切割这么多的字符串,但这已经完成了工作。

原问题中的代码有两个问题: 在时区中不应该有 :,而且 “时区作为偏移量”的格式字符串是小写的 %z而不是大写的 %Z

我在 Python v3.6就是这样

>>> from datetime import datetime
>>> t = datetime.strptime("2012-11-01T04:16:13-0400", "%Y-%m-%dT%H:%M:%S%z")
>>> print(t)
2012-11-01 04:16:13-04:00

You can convert like this.

date = datetime.datetime.strptime('2019-3-16T5-49-52-595Z','%Y-%m-%dT%H-%M-%S-%f%z')
date_time = date.strftime('%Y-%m-%dT%H:%M:%S.%fZ')

这个通过 Mohideen bin Mohammed使用 dateutil 的建议无疑是最好的解决方案,即使它确实需要一个小的库。已经使用了其他方法在那里容易出现各种形式的失败。这里有一个很好的函数。

from dateutil.parser import parse




def parse_date_convert(date, fmt=None):
if fmt is None:
fmt = '%Y-%m-%d %H:%M:%S' # Defaults to : 2022-08-31 07:47:30
get_date_obj = parse(str(date))
return str(get_date_obj.strftime(fmt))


dates = ['2022-08-31T07:47:30Z','2022-08-31T07:47:29.098Z','2017-05-27T07:20:18.000-04:00','2012-11-01T04:16:13-04:00']


for date in dates:
print(f'Before: {date}  After: {parse_date_convert(date)}')

结果:

Before: 2022-08-31T07:47:30Z  After: 2022-08-31 07:47:30
Before: 2022-08-31T07:47:29.098Z  After: 2022-08-31 07:47:29
Before: 2017-05-27T07:20:18.000-04:00  After: 2017-05-27 07:20:18
Before: 2012-11-01T04:16:13-04:00  After: 2012-11-01 04:16:13

Having tried various forms such as slicing split replacing the T Z like this:

dates = ['2022-08-31T07:47:30Z','2022-08-31T07:47:29.098Z','2017-05-27T07:20:18.000-04:00','2012-11-01T04:16:13-04:00']


for date in dates:
print(f'Before: {date}  After: {date.replace("T", " ").replace("Z", "")}')

You still are left with subpar results. like the below

Before: 2022-08-31T07:47:30Z  After: 2022-08-31 07:47:30
Before: 2022-08-31T07:47:29.098Z  After: 2022-08-31 07:47:29.098
Before: 2017-05-27T07:20:18.000-04:00  After: 2017-05-27 07:20:18.000-04:00
Before: 2012-11-01T04:16:13-04:00  After: 2012-11-01 04:16:13-04:00

You can create a timezone unaware object and replace the tzinfo and make it a timezone aware DateTime object later.

from datetime import datetime
import pytz


unware_time = datetime.strptime("2012-11-01 04:16:13", "%Y-%m-%d %H:%M:%S")
aware_time = unaware_time.replace(tzinfo=pytz.UTC)