我有一个使用IPDDump创建的Blackberry IPD备份的CSV转储文件。
这里的日期/时间字符串看起来像这样
(其中EST是澳大利亚时区):
1
| Tue Jun 22 07:46:22 EST 2010 |
我需要能够在Python中解析这个日期。 起初,我尝试使用datettime中的strptime()函数。
1
| >>> 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()与时区很好地配合?
-
你不能只...将所有日期转换为GMT?
-
@Robus:嗯,我本来希望这样做 - 但是我假设strftime / datetime能够以某种方式做到这一点? 无论哪种方式,我需要存储/解析日期时间在EST时区,或者它们发生在我身上的任何时区。 该脚本需要能够使用时区信息解析通用日期时间(例如,ETC可以是任何其他时区)。
-
EST也是美国时区的缩写。 (同样地,BST是英国和巴西时区的缩写。)这些缩写本身就是模棱两可的。 使用相对于UTC / GMT的偏移量。 (如果您需要支持缩写,则需要使映射与语言环境相关,这是一个混乱的鼠洞。)
-
EST时区缩写含糊不清。 另请参阅:使用Python中的时区缩写名称解析日期/时间字符串?
我建议使用python-dateutil。它的解析器已经能够解析到目前为止我抛出的每种日期格式。
1 2 3 4 5 6 7 8 9
| >>> 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,抱歉。但我希望这个答案对于那些在解析问题并查看该模块的实用程序时遇到这个问题的人来说仍然有用。
-
+1这个答案已被证明非常有用!谢谢 :-)
-
鉴于有这么多人倾向于使用python-dateutil,我想指出我们对lib的一个限制。 >>> parser.parse("Thu, 25 Sep 2003 10:49:41,123 -0300") Traceback (most recent call last): File"", line 1, in 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你需要用句号替换最后一个逗号。然后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))
-
@flyingfoxlee,是的,我理解。我只是想告诉人们python-dateutil的局限性。它做了神奇的事情,但有时却做不到。所以"只是在它上面约会,它就是正确的事情。"不是100%真实。
-
此外,dateutil可能无法表示不明确的当地时间。如果您的应用程序无法容忍~1h错误,请在Python中使用时区时使用基于pytz的解决方案。
-
这是我的救世主
-
dateutil.parser.parse("10-27-2016 09:06 AM PDT")返回:datetime.datetime(2016, 10, 27, 9, 6)无法确定时区...
-
很好,甚至解析像weirddtstring = '04
ov\2013:16:19:20+0100'这样的字符串成功与parser.parse(weirddtstring, dayfirst=True, fuzzy=True),以防其他人遇到这些相当罕见的日志条目...
-
这取决于一个人的目标。 dateutil parser可能很简单,但strptime()更快。此外,它的格式很容易学习。
-
-1:当然,python-dateutil是一个非常有用的库!但这实际上并没有回答这个问题。并且dateutil解析器的速度要慢一个数量级。
datetime模块文档说:
Return a datetime corresponding to date_string, parsed according to format. This is equivalent to 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起已更新,现在相同的文档也说明如下:
When the %z directive is provided to the strptime() method, an aware datetime object will be produced. The tzinfo of the result will be set to a timezone instance.
请注意,这不适用于%Z,因此这种情况很重要。请参阅以下示例:
1 2 3 4 5 6 7 8 9 10 11
| 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 |
-
相关的Python bug:strptime中的%Z与EST和其他不匹配
您的时间字符串类似于rfc 2822中的时间格式(电子邮件中的日期格式,http标头)。你可以只使用stdlib解析它:
1 2 3
| >>> 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版本生成时区感知日期时间对象的解决方案:使用电子邮件中的时区解析日期。
在这种格式中,EST在语义上等同于-0500。虽然,通常,时区缩写是不够的,但要唯一地标识时区。