dateutil.parser:dd/mm和mm/dd在同一列如何处理?

dateutil.parser: how to deal with dd/mm and mm/dd in same column?

我正在解析一个 CSV 文件,其中一列是 "datetime"。这些 CSV 格式错误,一些 CSV 文件有 28-02-2018T00:00:00.000+1000 而其他 CSV 文件有 2018-02-28T00:00:00.000+1000.

如果我这样做:

dateutil.parser.parse(my_csv["timestamp"])

my_csv["timestamp"]02-28-2018T00:00:00.000+1000 还是 2018-02-28T00:00:00.000+1000 是无关紧要的。如果我不指定格式也是正确的,因为库会识别没有 "month 28",因此它会自己选择正确的格式。

但是如何处理日期和月份对两个格式槽都有效的情况?

2018-02-0404-02-2018都是同一个日期,只是一个有%m-%d,一个有%d-%m.

我可以告诉解析器格式是 %y-%m-%d OR %d-%m-%y 吗?

我在解析时是否可以使用其他参数来告诉解析器,如果 %y 的 4 位数字首先出现,则使用 %y-%m-%d 否则使用 %d-%m-%y

目前 dateutil 解析器的自定义选项很少,无法指定您想要的内容。

但是,如果只是这两种格式,我建议根本不要使用 dateutil 的解析器。您可以使用尝试一种然后另一种格式的函数来解析这些日期:

from datetime import datetime

def parse_myformats(dtstr):
    try:
        return datetime.strptime(dtstr, '%Y-%m-%dT%H:%M:%S.%f%z')
    except ValueError:
        return datetime.strptime(dtstr, '%d-%m-%YT%H:%M:%S.%f%z')

这假定 Python 3(%z 指令)。在 Python 2 中,您必须去掉最后 5 位数字并单独解析时区。

也就是说,由于第一个日期时间是 ISO8601 日期时间,您还可以使用 dateutil.parser.isoparse 作为条件的第一个分支,并使用 parse 作为回退:

from datetime import datetime
from dateutil import parser

def parse_myformats_du(dtstr):
    try:
        return parser.isoparse(dtstr)
    except ValueError:
        return parser.parse(dtstr, dayfirst=True)

此版本可在 Python 2 和 3 中使用,无需额外修改,但在调用 dateutil.parser.parse 的分支上可能会更慢。查看实际效果:

>>> parse_myformats('2018-02-04T00:00:00.000+1000')
datetime.datetime(2018, 2, 4, 0, 0, tzinfo=datetime.timezone(datetime.timedelta(0, 36000)))

>>> parse_myformats('04-02-2018T00:00:00.000+1000')
datetime.datetime(2018, 2, 4, 0, 0, tzinfo=datetime.timezone(datetime.timedelta(0, 36000)))

>>> parse_myformats_du('2018-02-04T00:00:00.000+1000')
datetime.datetime(2018, 2, 4, 0, 0, tzinfo=tzoffset(None, 36000))

>>> parse_myformats_du('04-02-2018T00:00:00.000+1000')
datetime.datetime(2018, 2, 4, 0, 0, tzinfo=tzoffset(None, 36000))

如果您关心速度,这里是 IPython %timeit 微基准测试:

%timeit parse_myformats('2018-02-04T00:00:00.000+1000')
31.8 µs ± 1.23 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

%timeit parse_myformats('04-02-2018T00:00:00.000+1000')
45.1 µs ± 2.34 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

%timeit parse_myformats_du('2018-02-04T00:00:00.00+1000')
31.3 µs ± 574 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

%timeit parse_myformats_du('04-02-2018T00:00:00.000+1000')
191 µs ± 2.99 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)