自定义 dateutil.parser 世纪推理逻辑
customize dateutil.parser century inference logic
我正在处理具有 2 位数年份的旧文本文件,其中 dateutil.parser
中的默认世纪逻辑似乎无法正常工作。例如,对珍珠港的袭击不在 dparser.parse("12/7/41")
(returns 2041-12-7)。
回滚到 1900 年代的内置世纪 "threshold" 似乎发生在 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
出于我的目的,我想将此 "threshold" 设置为 17,以便:
"12/31/16"
解析为 2016-12-31 (yyyy-mm-dd
)
"1/1/17"
解析为 1917-01-01
但我想继续使用这个模块,因为它的模糊匹配似乎运行良好。
documentation 没有确定执行此操作的参数...是否有我忽略的参数?
如果提取的年份超过指定的阈值,您还可以post-处理提取的日期手动更改世纪,在您的情况下 - 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
这没有很好的记录,但您实际上可以使用 dateutil.parser
覆盖它。第二个参数是一个 parserinfo
对象,您要关注的方法是 convertyear
。 default implementation 是导致您出现问题的原因。您可以看到它基于当前年份(加上或减去五十年)对世纪的解释。这就是您在 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)
除了编写您自己的 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。任何年份距 _years
至少 50 年,即差异为
< _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 年期间的中间.使用这两个设置,您可以指定任何您喜欢的截止点。
*) 请注意,这两个变量未记录,但在撰写本文时的最新稳定版本 2.5.3 中用于 parserinfo.convertyear
的默认实现。恕我直言,默认实现非常聪明。
我正在处理具有 2 位数年份的旧文本文件,其中 dateutil.parser
中的默认世纪逻辑似乎无法正常工作。例如,对珍珠港的袭击不在 dparser.parse("12/7/41")
(returns 2041-12-7)。
回滚到 1900 年代的内置世纪 "threshold" 似乎发生在 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
出于我的目的,我想将此 "threshold" 设置为 17,以便:
"12/31/16"
解析为 2016-12-31 (yyyy-mm-dd
)"1/1/17"
解析为 1917-01-01
但我想继续使用这个模块,因为它的模糊匹配似乎运行良好。
documentation 没有确定执行此操作的参数...是否有我忽略的参数?
如果提取的年份超过指定的阈值,您还可以post-处理提取的日期手动更改世纪,在您的情况下 - 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
这没有很好的记录,但您实际上可以使用 dateutil.parser
覆盖它。第二个参数是一个 parserinfo
对象,您要关注的方法是 convertyear
。 default implementation 是导致您出现问题的原因。您可以看到它基于当前年份(加上或减去五十年)对世纪的解释。这就是您在 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)
除了编写您自己的 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。任何年份距 _years
至少 50 年,即差异为
< _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 年期间的中间.使用这两个设置,您可以指定任何您喜欢的截止点。
*) 请注意,这两个变量未记录,但在撰写本文时的最新稳定版本 2.5.3 中用于 parserinfo.convertyear
的默认实现。恕我直言,默认实现非常聪明。