настроить логику логического вывода 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)
 Two-Bit Alchemist25 июл. 2016 г., 23:00
Эй, круто Великие умы думают одинаково! (Я не знал об этом сообщении.)
 C8H10N4O225 июл. 2016 г., 23:36
@ Пол теперь работает - спасибо за помощь!
 Paul25 июл. 2016 г., 23:21
@ C8H10N4O2 Похоже, что изменение было в 2.5.0. замещать**kwargs с*args или же*args, **kwargs и тебе должно быть хорошо.
 Paul25 июл. 2016 г., 23:25
Кроме того, обратите внимание, что если возможно, что вы получите лет, как0095 или же057 (в первом веке нашей эры), вы должны явно изменить подпись наyear, century_specified=False и обрабатывать соответственно.
 C8H10N4O225 июл. 2016 г., 23:14
Я получаюTypeError: convertyear() takes 2 positional arguments but 3 were given на вышеуказанном решении. Тем не менее, я только на2.5.1 изdateutil так что давайте посмотрим, если обновление имеет значение
 Paul25 июл. 2016 г., 23:13
Вероятно, стоит отметить, что в следующей версии 2.6.0century_specified флаг также будет переданconvertyear, чтобы различать0099-04-20 а также99-04-20, Эта реализация с**kwargs должен покрыть это.
 Paul25 июл. 2016 г., 22:59
Увидетьэтот отчет об ошибке, Рекомендуемый курс действий состоит в том, чтобы создать подкласс и переопределитьconvertyear.
 C8H10N4O225 июл. 2016 г., 23: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. ИМХО реализация по умолчанию довольно умная.

 miraculixx26 июл. 2016 г., 08:58
Я понимаю вашу точку зрения, однако вы всегда можете реализовать свои собственныеparserinfo.convertyear и, таким образом, сохранить поведение, если dateutil решит изменить их.
 Paul26 июл. 2016 г., 02:08
Я бы не рекомендовал полагаться на частные переменные, так как они не гарантированно существуют в более поздних версиях. В случае этих переменных, я думаю, они скоро будут удалены в пользу общедоступного интерфейса.

Вы также можетепостобработка извлеченных дат вручную изменив век, если извлеченный год превышает указанный порог, в вашем случае - 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
 Two-Bit Alchemist25 июл. 2016 г., 22:59
Это кажется настраиваемым, но неясным способом. Документация вряд ли понятна. Мне пришлось покопаться в исходном коде, чтобы выяснить способ (который, честно говоря, связан с документами).
 alecxe25 июл. 2016 г., 23:00
@ Two-BitAlchemist действительно хорошая находка! Спасибо!
 alecxe25 июл. 2016 г., 23:02
@ C8H10N4O2 хорошие примеры, которые разбивают это решение на части. Благодарю.
 C8H10N4O225 июл. 2016 г., 22:56
Спасибо - за мой случай использования, который имеет смешанные типы, я не могу позволить себе закреплять каждую дату сверх порога, потому что иногда век явный. Рассматривать:print(dparser.parse("The Soviets tested their first A-bomb on 8/29/49", fuzzy = True)); print(dparser.parse("Scientists promise flying atomic cars by the year 2020", fuzzy = True))

Ваш ответ на вопрос