Настроить логику логического вывода dateutil.parser

Я работаю над старыми текстовыми файлами с двузначными годами, в которых логика столетия по умолчанию dateutil.parser кажется, не работает хорошо. Например, нападение на Перл-Харбор не было dparser.parse("12/7/41") (который возвращает 2041-12-7).

Похоже, что "порог" постройки столетия, откатившийся в 1900-е годы, наступил в 66:

import dateutil.parser as dparser
print(dparser.parse("12/31/65")) # goes forward to 2065-12-31 00:00:00
print(dparser.parse("1/1/66")) # goes back to 1966-01-01 00:00:00

Для моих целей я бы хотел установить этот "порог" на 17, чтобы:

  • "12/31/16" парсит до 2016-12-31 (yyyy-mm-dd)
  • "1/1/17" разбирает до 1917-01-01

Но я хотел бы продолжать использовать этот модуль, так как его нечеткое совпадение, кажется, работает хорошо.

В документации не указан параметр для этого... есть ли аргумент, который я пропускаю?

3 ответа

Решение

Это не очень хорошо задокументировано, но вы можете переопределить это, используя dateutil.parser, Второй аргумент parserinfo объект, и метод, который вы будете иметь дело с convertyear, Реализация по умолчанию - это то, что вызывает у вас проблемы. Вы можете видеть, что он основывает свою интерпретацию века на текущем году, плюс-минус пятьдесят лет. Вот почему вы видите переход в 1966 году. В следующем году это будет 1967 год.:)

Так как вы используете это лично и можете иметь очень специфические потребности, вам не нужно быть супер-универсальным. Вы можете сделать что-то простое, как это, если это работает для вас:

from dateutil.parser import parse, parserinfo

class MyParserInfo(parserinfo):
    def convertyear(self, year, *args, **kwargs):
        if year < 100:
            year += 1900
        return year

parse('1/21/47', MyParserInfo())
# datetime.datetime(1947, 1, 21, 0, 0)

Вы также можете обработать извлеченные даты вручную, изменив столетие, если извлеченный год превышает указанный порог, в вашем случае - 2016:

import dateutil.parser as dparser

THRESHOLD = 2016

date_strings = ["12/31/65", "1/1/66", "12/31/16", "1/1/17"]
for date_string in date_strings:
    dt = dparser.parse(date_string)
    if dt.year > THRESHOLD:
        dt = dt.replace(year=dt.year - 100)
    print(dt)

Печать:

1965-12-31 00:00:00
1966-01-01 00:00:00
2016-12-31 00:00:00
1917-01-01 00:00:00

Кроме написания собственного parserinfo.convertyear метод, вы можете настроить это, передав стандарт parserinfo объект с измененным _century а также _year настройки *):

from dateutil.parser import parse, parserinfo
info = parserinfo()
info._century = 1900
info._year  = 1965
parse('12/31/65', parserinfo=info)
=> 1965-12-31 00:00:00

_century определяет годы по умолчанию, добавленные к любому номеру года, то есть 65 + 1900 = 1965,

_year указывает год закрытия +- 50. Любой год, по крайней мере, 50 лет от _years т.е. где разница

  • < _year будет переключен на следующее столетие
  • >= _year будет переключен на предыдущий век

Думайте об этом как о временной шкале:

1900          1916          1965          2015
+--- (...) ---+--- (...) ---+--- (...) ---+
^             ^             ^             ^
_century      _year - 49    _year         _year + 50

parsed years:
              16,17,...             99,00,...15

Другими словами, годы 00, 01, ..., 99 сопоставлены с временным диапазоном _year - 49.. _year + 50 с _year установить в середине этого 100-летнего периода. Используя эти две настройки, вы можете указать любой отрезок, который вам нравится.

*) Обратите внимание, что эти две переменные недокументированы, однако используются в реализации по умолчанию для parserinfo.convertyear в новейшей стабильной версии на момент написания 2.5.3. ИМХО реализация по умолчанию довольно умная.

Другие вопросы по тегам