如何判断dateutil parser解析月/年格式字符串时是否使用了默认参数值
如何判断dateutil.parser是否使用了默认的日份值?
当我们用dateutil.parser.parse解析像'Sep-2020'这种仅包含月份和年份的日期字符串时,解析器会自动补充日份信息——要么取自default参数里的日份,要么用当前日期的日份。但麻烦的是,就算输入里明确指定了日份(比如'1-Sep-2020'),最终的解析结果可能和用默认值的情况完全一样,我们没法直接从结果判断日份的来源。
比如下面这三个示例,输出的datetime对象完全相同,但第一个是用了默认的日份,后两个是输入里明确提供的:
>>> from datetime import datetime >>> from dateutil import parser >>> d = datetime(1978, 1, 1, 0, 0) >>> parser.parse('Sep-2020', default=d) datetime.datetime(2020, 9, 1, 0, 0) >>> parser.parse('1-Sep-2020', default=d) datetime.datetime(2020, 9, 1, 0, 0) >>> parser.parse('Sep-1-2020', default=d) datetime.datetime(2020, 9, 1, 0, 0)
下面给你两个可行的解决方案:
方法1:自定义解析器跟踪已解析字段
dateutil.parser本身没有直接提供这个功能,但我们可以通过继承parser.parserinfo类,重载字段解析方法来跟踪哪些字段是从输入中解析出来的,哪些是用了默认值。
举个具体的实现例子:
from datetime import datetime from dateutil import parser class TrackingParserInfo(parser.parserinfo): def __init__(self): super().__init__() # 用集合记录解析到的字段 self.parsed_fields = set() def parse_month(self, text, *args, **kwargs): self.parsed_fields.add('month') return super().parse_month(text, *args, **kwargs) def parse_day(self, text, *args, **kwargs): self.parsed_fields.add('day') return super().parse_day(text, *args, **kwargs) def parse_year(self, text, *args, **kwargs): self.parsed_fields.add('year') return super().parse_year(text, *args, **kwargs) # 测试验证 default_date = datetime(1978, 1, 1, 0, 0) # 案例1:仅月年输入 tracker1 = TrackingParserInfo() result1 = parser.parse('Sep-2020', default=default_date, parserinfo=tracker1) print(f"解析结果:{result1}") print(f"从输入中解析到的字段:{tracker1.parsed_fields}") # 输出 {'month', 'year'} → 说明day用了默认值 # 案例2:带日份的输入(日-月-年) tracker2 = TrackingParserInfo() result2 = parser.parse('1-Sep-2020', default=default_date, parserinfo=tracker2) print(f"解析结果:{result2}") print(f"从输入中解析到的字段:{tracker2.parsed_fields}") # 输出 {'day', 'month', 'year'} → 说明day来自输入 # 案例3:带日份的输入(月-日-年) tracker3 = TrackingParserInfo() result3 = parser.parse('Sep-1-2020', default=default_date, parserinfo=tracker3) print(f"解析结果:{result3}") print(f"从输入中解析到的字段:{tracker3.parsed_fields}") # 输出 {'day', 'month', 'year'} → 说明day来自输入
这个方法的核心思路是:每成功解析一个字段(日/月/年),就把它记录到集合里。最后检查集合里有没有'day',就能知道日份是来自输入还是默认值。
方法2:先按指定格式尝试解析(更简单直接)
如果你能明确枚举输入的可能格式(比如要么是月-年,要么是日-月-年/月-日-年),可以先用datetime.strptime按指定格式尝试解析,失败了再换其他格式。这样就能直接判断输入里是否包含日份:
from datetime import datetime from dateutil import parser def parse_with_day_check(date_str, default_date): # 先尝试解析仅月年的格式 try: parsed_dt = datetime.strptime(date_str, '%b-%Y') return parsed_dt, False # False表示日份是默认补充的 except ValueError: pass # 尝试解析日-月-年格式 try: parsed_dt = datetime.strptime(date_str, '%d-%b-%Y') return parsed_dt, True # True表示日份来自输入 except ValueError: pass # 尝试解析月-日-年格式 try: parsed_dt = datetime.strptime(date_str, '%b-%d-%Y') return parsed_dt, True except ValueError: pass # 如果都匹配不上,再用dateutil的默认解析(可结合方法1跟踪字段) tracker = TrackingParserInfo() parsed_dt = parser.parse(date_str, default=default_date, parserinfo=tracker) has_day_from_input = 'day' in tracker.parsed_fields return parsed_dt, has_day_from_input # 测试验证 default_date = datetime(1978, 1, 1) dt1, has_day1 = parse_with_day_check('Sep-2020', default_date) print(f"{dt1},日份来自输入:{has_day1}") # 输出:2020-09-01 00:00:00,日份来自输入:False dt2, has_day2 = parse_with_day_check('1-Sep-2020', default_date) print(f"{dt2},日份来自输入:{has_day2}") # 输出:2020-09-01 00:00:00,日份来自输入:True dt3, has_day3 = parse_with_day_check('Sep-1-2020', default_date) print(f"{dt3},日份来自输入:{has_day3}") # 输出:2020-09-01 00:00:00,日份来自输入:True
这种方法适合输入格式比较固定的场景,优点是简单直观,不需要深入dateutil的内部实现。
内容的提问来源于stack exchange,提问作者vkkodali
相关产品推荐
相关产品推荐

