Python strptime()和时区?


157

我有一个使用IPDDump创建的Blackberry IPD备份中的CSV转储文件。这里的日期/时间字符串看起来像这样(EST澳大利亚时区):

Tue Jun 22 07:46:22 EST 2010

我需要能够在Python中解析此日期。首先,我尝试strptime()从datettime 开始使用该功能。

>>> datetime.datetime.strptime('Tue Jun 22 12:10:20 2010 EST', '%a %b %d %H:%M:%S %Y %Z')

但是,由于某种原因,返回的datetime对象似乎没有任何tzinfo关联。

我确实在该页面上阅读了显然是datetime.strptime默默丢弃的内容tzinfo,但是,我检查了文档,但找不到此处记录的任何相关信息

我已经能够使用第三方Python库dateutil来解析日期,但是我仍对如何strptime()错误地使用内置函数感到好奇?有什么办法可以使strptime()时区与时俱进吗?


1
您不能...将所有日期都转换为格林尼治标准时间吗?
Robus

2
@Robus:嗯,我希望这样做-但我假设strftime / datetime可以以某种方式做到这一点?无论哪种方式,我都需要存储/解析日期时间在EST时区或它们在我身上遇到的任何时区的事实。该脚本必须能够解析带有时区信息的通用日期时间(例如ETC可以是任何其他时区)。
victorhooi 2010年

3
EST也是美国时区的缩写。(类似地,BST既是英国的时区缩写,也是巴西的时区缩写。)这种缩写本质上是模棱两可的。请使用相对于UTC / GMT的偏移量。(如果需要支持缩写,则需要使映射依赖于语言环境,这是一个麻烦的
棘手问题

Answers:


58

datetime模块的文件说:

返回对应于date_string的datetime,并根据格式进行解析。等同于datetime(*(time.strptime(date_string, format)[0:6]))

看到了[0:6]吗?那让你(year, month, day, hour, minute, second)。没有其他的。没有提及时区。

有趣的是,[Win XP SP2,Python 2.6、2.7]将您的示例传递给您time.strptime不起作用,但是如果您剥离了“%Z”和“ EST”,它将起作用。也可以使用“ UTC”或“ GMT”代替“ EST”。“ PST”和“ MEZ”无效。令人费解。

值得注意的是,此功能已从3.2版开始进行更新,并且同一文档现在也声明以下内容:

将%z指令提供给strptime()方法时,将生成一个可感知的datetime对象。结果的tzinfo将设置为时区实例。

请注意,这不适用于%Z,因此大小写很重要。请参见以下示例:

In [1]: from datetime import datetime

In [2]: start_time = datetime.strptime('2018-04-18-17-04-30-AEST','%Y-%m-%d-%H-%M-%S-%Z')

In [3]: print("TZ NAME: {tz}".format(tz=start_time.tzname()))
TZ NAME: None

In [4]: start_time = datetime.strptime('2018-04-18-17-04-30-+1000','%Y-%m-%d-%H-%M-%S-%z')

In [5]: print("TZ NAME: {tz}".format(tz=start_time.tzname()))
TZ NAME: UTC+10:00

13

353

我建议使用python-dateutil。到目前为止,它的解析器已经能够解析我抛出的每种日期格式。

>>> from dateutil import parser
>>> parser.parse("Tue Jun 22 07:46:22 EST 2010")
datetime.datetime(2010, 6, 22, 7, 46, 22, tzinfo=tzlocal())
>>> parser.parse("Fri, 11 Nov 2011 03:18:09 -0400")
datetime.datetime(2011, 11, 11, 3, 18, 9, tzinfo=tzoffset(None, -14400))
>>> parser.parse("Sun")
datetime.datetime(2011, 12, 18, 0, 0)
>>> parser.parse("10-11-08")
datetime.datetime(2008, 10, 11, 0, 0)

等等。不用处理strptime()格式废话……只要在它上面加上一个日期,它就可以解决问题。

更新:糟糕。我错过了您提到您使用过的原始问题dateutil,对此感到抱歉。但是,我希望这个答案对那些有日期解析问题并看到该模块实用程序的人仍然有用。


鉴于有太多人倾向于使用python-dateutil,我想向我们指出该lib的一个局限性。>>> parser.parse("Thu, 25 Sep 2003 10:49:41,123 -0300") Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/Users/wanghq/awscli/lib/python2.7/site-packages/dateutil/parser.py", line 748, in parse return DEFAULTPARSER.parse(timestr, **kwargs) File "/Users/wanghq/awscli/lib/python2.7/site-packages/dateutil/parser.py", line 310, in parse res, skipped_tokens = self._parse(timestr, **kwargs) TypeError: 'NoneType' object is not iterable
wanghq 2014年

1
@wanghq,您需要用句号替换最后一个逗号。然后parser.parse("Thu, 25 Sep 2003 10:49:41.123 -0300") returns: datetime.datetime(2003, 9, 25, 10, 49, 41, 123000, tzinfo=tzoffset(None, -10800))
flyfoxlee 2014年

7
@flyingfoxlee,是的,我知道。我只想告诉人们python-dateutil的局限性。它做神奇的事情,但有时却做不到。因此,“只要给它加个约会,它就做对了。” 不是100%正确。
wanghq 2014年

4
dateutil.parser.parse("10-27-2016 09:06 AM PDT")返回:datetime.datetime(2016, 10, 27, 9, 6)无法找出时区...
HaPsantran '16

2
这取决于一个人的目标。dateutil parser可能简单易用,但strptime()速度更快。此外,它的格式很容易学习。
狂喜

9

您的时间字符串类似于rfc 2822中的时间格式(电子邮件,http标头中的日期格式)。您可以仅使用stdlib对其进行解析:

>>> from email.utils import parsedate_tz
>>> parsedate_tz('Tue Jun 22 07:46:22 EST 2010')
(2010, 6, 22, 7, 46, 22, 0, 1, -1, -18000)

请参阅针对各种Python版本产生可识别时区的datetime对象的解决方案:从电子邮件中解析带时区的date

在此格式下, EST在语义上等效于-0500。尽管通常来说,时区缩写还不足以唯一地标识时区


0

遇到这个确切的问题。

我最终要做的是:

# starting with date string
sdt = "20190901"
std_format = '%Y%m%d'

# create naive datetime object
from datetime import datetime
dt = datetime.strptime(sdt, sdt_format)

# extract the relevant date time items
dt_formatters = ['%Y','%m','%d']
dt_vals = tuple(map(lambda formatter: int(datetime.strftime(dt,formatter)), dt_formatters))

# set timezone
import pendulum
tz = pendulum.timezone('utc')

dt_tz = datetime(*dt_vals,tzinfo=tz)
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.