parseutil.parser解析不完整日期时需返回None而非默认值
解决parseutil.parser自动补全不完整日期的问题
问题场景
用parseutil.parser解析日期时,完整日期能正常输出:
I was born October 11th 2002 -> date(2002, 10, 11)
但碰到不完整日期,工具会自动填充当天的月和日,比如今天是2月23日的话:
I need documents from 2003 -> date(2003, 2, 23)
我想要的是根据不完整日期生成对应的时间区间:
- 只给年份的话,输出全年区间:
date(2003, 1, 1), date(2003, 12, 31) - 给年月的话,输出当月区间:
date(2003, 3, 1), date(2003, 3, 31)
试过传default=date(None, None, None),但datetime字段不允许为None;传固定默认日期又分不清是真实解析的还是补全的,而且调用parse()后没法知道解析是否完整、匹配了哪些字段。
修复方案
核心思路是先判断解析结果里的年、月、日哪些是真实匹配到的,哪些是自动补全的,再根据这个生成对应区间。下面是具体实现:
from dateutil.parser import parse from datetime import datetime, timedelta def parse_date_to_range(text): # 先拿到基础解析结果 parsed = parse(text, fuzzy=True) text_low = text.lower() # 判断文本中是否包含日、月、年的标识 has_day = any(day_suffix in text_low for day_suffix in ['1st','2nd','3rd','4th','5th','6th','7th','8th','9th','10th','11th','12th','13th','14th','15th','16th','17th','18th','19th','20th','21st','22nd','23rd','24th','25th','26th','27th','28th','29th','30th','31st']) or any(str(d) in text for d in range(1,32)) has_month = any(month in text_low for month in ['january','february','march','april','may','june','july','august','september','october','november','december','jan','feb','mar','apr','may','jun','jul','aug','sep','oct','nov','dec']) has_year = any(str(y) in text for y in range(1900, 2100)) # 根据匹配情况生成区间 if has_year and not has_month and not has_day: start = datetime(parsed.year, 1, 1) end = datetime(parsed.year, 12, 31) return (start, end) elif has_year and has_month and not has_day: start = datetime(parsed.year, parsed.month, 1) # 计算当月最后一天 next_month = parsed.month + 1 if parsed.month < 12 else 1 next_year = parsed.year if parsed.month < 12 else parsed.year + 1 end = datetime(next_year, next_month, 1) - timedelta(days=1) return (start, end) else: # 完整日期直接返回 return (parsed,) # 测试示例 print(parse_date_to_range("I need documents from 2003")) # 输出:(datetime.datetime(2003, 1, 1, 0, 0), datetime.datetime(2003, 12, 31, 0, 0)) print(parse_date_to_range("I need documents from March 2003")) # 输出:(datetime.datetime(2003, 3, 1, 0, 0), datetime.datetime(2003, 3, 31, 0, 0)) print(parse_date_to_range("I was born October 11th 2002")) # 输出:(datetime.datetime(2002, 10, 11, 0, 0),)
如果想要更精准的匹配判断,可以利用dateutil.parser的底层解析信息(比如通过parserinfo类扩展),直接获取哪些字段是被主动匹配的,避免通过文本关键词判断的误差。
内容的提问来源于stack exchange,提问作者StrikerOmega
相关产品推荐
相关产品推荐

