如何在不带dateutil的Python中将时区感知字符串转换为datetime?


77

我必须将类似时区的字符串转换"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")

2
当一个依赖项完全满足您的需求时,添加一个依赖项有什么问题?当然,如果不使用额外的模块就可以实现相同的结果,那么就没有理由完全存在该模块了吗?添加依赖项有多难?
乔恩·斯基特

我认为这可能是个人利益?我真的不想在项目中引入一个大模块,因为我只需要一个很小的功能。
lxyu 2012年

2
与使您的代码更难理解而不是需要的代码相比,向项目中添加依赖项的具体成本是多少?忽略您当前仅需要一个功能的事实-将精力集中在成本上。
乔恩·斯基特

Answers:


86

从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小。比较该totpython-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)))

Python版本15873中正在跟踪缺少正确的ISO 8601解析的问题


在我看来,似乎datetime可以包含iso8601处理ISO 8601时区的功能-有点解析和两个tzinfo子类。
Eryk Sun

@eryksun:ISO8601确实简化了时区,但是一旦在python stdlib中包含了这些偏移量,就会误解现实时区(不仅仅是偏移量)为什么不起作用等原因。
马丁·皮特斯

1
定义一个FixedOffset 类并不是那么痛苦。这是代码示例
jfs 2015年


12

原始问题中的代码有两个问题::时区中不应存在​​a ,“ timezone as a offset”的格式字符串应为小写%z而不是upper %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

如果输入错误,为什么print(t)要在utc偏移量中加上冒号?
moooeeeep

@moooeeeep因为默认情况下datetime使用 isoformat(sep=' ')用于__str__打印出作为UTC偏移功能“+ HH:MM”。使用时print(t.strftime("%Y-%m-%dT%H:%M:%S%z"))将在时区中不带“:”的情况下打印。
Jamie Czuy '17

3
在时区中有一个冒号是没有错的。许多资源都以字符串形式显示其时间:2012-11-01T04:16:13-04:00。OP正在寻求解析该表格。
DaveL17

2

您可以像这样转换。

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')

1

我是Python的新手,但是找到了一种转换方法

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)

我敢肯定有更好的方法可以做到这一点,而不必将字符串切得太多,但这已经完成了工作。

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.