You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

处理闰年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'])

关键修改点

  1. 新增get_adjusted_birthday函数,专门处理日期替换时的闰年边界情况
  2. 将原代码中x.replace(year=...)替换为调用该辅助函数,避免直接替换导致的日期无效错误

内容的提问来源于stack exchange,提问作者d-fws

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 13:23:12