处理闰年2月29日生日引发的ValueError: day is out of range for month问题
问题:闰年2月29日出生日期计算带小数年龄报错
处理存储人员信息的DataFrame时,需根据CSV文件名提取的特定日期计算人员带小数形式的年龄。现有代码在非闰年数据下运行正常,但当数据中包含闰年2月29日的出生日期(dob)时,会抛出ValueError: day is out of range for month错误。
原代码
# get csv from directory df = pd.read_csv(csv, index_col=0, parse_dates=["dob"]) # form date string date_string = re.split(r'\s|-', csv)[0] + '0915' d_date = pd.to_datetime(int(date_string),format='%Y%m%d', errors='coerce') # adding age column df['age'] = df['dob'].apply( lambda x: (d_date.year - x.year - ((d_date.month, d_date.day) < (x.month, x.day))) ) # calculating fraction of year passed since last birthday df['fractional_age'] = df['dob'].apply( lambda x: (d_date - pd.to_datetime(x.replace(year=d_date.year))).days / 365.25 if (x.month, x.day) <= (d_date.month, d_date.day) else (d_date - pd.to_datetime(x.replace(year=d_date.year - 1))).days / 365.25 ) df['age'] = df['age'] + df['fractional_age'] df = df.drop(columns=['fractional_age'])
报错信息
File "...\addage.py", line 22, in add_age df['fractional_age'] = df['dob'].apply( ^^^^^^^^^^^^^^^^ File "...\AppData\Roaming\Python\Python311\site-packages\pandas\core\series.py", line 4630, in apply return SeriesApply(self, func, convert_dtype, args, kwargs).apply() ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "...\AppData\Roaming\Python\Python311\site-packages\pandas\core\apply.py", line 1025, in apply return self.apply_standard() ^^^^^^^^^^^^^^^^^^^^^ File "...\AppData\Roaming\Python\Python311\site-packages\pandas\core\apply.py", line 1076, in apply_standard mapped = lib.map_infer( ^^^^^^^^^^^^^^ File "pandas\_libs\lib.pyx", line 2834, in pandas._libs.lib.map_infer File "...\addage.py", line 23, in <lambda> lambda x: (d_date - pd.to_datetime(x.replace(year=d_date.year))).days / 365.25 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "pandas\_libs\tslibs\timestamps.pyx", line 2279, in pandas._libs.tslibs.timestamps.Timestamp.replace File "pandas\_libs\tslibs\timestamps.pyx", line 155, in pandas._libs.tslibs.timestamps.create_timestamp_from_ts ValueError: day is out of range for month
报错原因
非闰年不存在2月29日,当代码执行x.replace(year=d_date.year)时,如果目标年份(d_date.year)不是闰年,直接替换2月29日的年份会导致日期无效,触发ValueError。
解决方案
编写一个辅助函数,处理2月29日的日期替换逻辑:如果目标年份是闰年,保留2月29日;如果是非闰年,将日期调整为2月28日(或根据业务需求调整为3月1日)。
修改后的完整代码
import pandas as pd import re def get_adjusted_birthday(dob, target_year): """调整出生日期到目标年份,处理闰年2月29日的情况""" if dob.month == 2 and dob.day == 29: try: # 尝试直接替换年份,闰年则成功 return dob.replace(year=target_year) except ValueError: # 非闰年时调整为2月28日,可根据需求改为3月1日 return dob.replace(year=target_year, month=2, day=28) else: return dob.replace(year=target_year) # get csv from directory df = pd.read_csv(csv, index_col=0, parse_dates=["dob"]) # form date string date_string = re.split(r'\s|-', csv)[0] + '0915' d_date = pd.to_datetime(int(date_string), format='%Y%m%d', errors='coerce') # adding age column df['age'] = df['dob'].apply( lambda x: (d_date.year - x.year - ((d_date.month, d_date.day) < (x.month, x.day))) ) # calculating fraction of year passed since last birthday df['fractional_age'] = df['dob'].apply( lambda x: (d_date - get_adjusted_birthday(x, d_date.year)).days / 365.25 if (x.month, x.day) <= (d_date.month, d_date.day) else (d_date - get_adjusted_birthday(x, d_date.year - 1)).days / 365.25 ) df['age'] = df['age'] + df['fractional_age'] df = df.drop(columns=['fractional_age'])
关键修改点
- 新增
get_adjusted_birthday函数,专门处理日期替换时的闰年边界情况 - 将原代码中
x.replace(year=...)替换为调用该辅助函数,避免直接替换导致的日期无效错误
内容的提问来源于stack exchange,提问作者d-fws
相关产品推荐
相关产品推荐

