dateutil.parser: как обращаться с дд / мм и мм / дд в одном столбце? - PullRequest
0 голосов
/ 29 июня 2018

Я анализирую 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, не имеет значения. Будет правильно, если я не укажу формат, потому что библиотека распознает, что «месяца 28» нет, поэтому она сама выберет правильный формат.

Но как справиться со случаями, когда день и месяц действительны для обоих слотов формата?

2018-02-04 и 04-02-2018 имеют одинаковую дату, но у одного есть %m-%d, а у другого - %d-%m.

Могу я сказать парсеру, что формат будет либо %y-%m-%d ИЛИ %d-%m-%y?

Есть ли дополнительный параметр, который я могу использовать при синтаксическом анализе, чтобы сообщить парсеру, что если сначала появляются 4 цифры для %y, то используйте %y-%m-%d, в противном случае используйте %d-%m-%y?

1 Ответ

0 голосов
/ 29 июня 2018

В настоящее время параметры настройки синтаксического анализатора 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)
...