Pandas计算工作日时处理空结束日期的报错解决咨询
Pandas计算工作日时处理空结束日期的报错解决咨询
看起来你已经搞定了从固定列宽txt文件读取数据、正常场景下计算工作日的逻辑,但卡在了空结束日期导致的NaT报错上——这个问题我之前处理老系统导出的数据时也碰到过,老数据库的空值经常给日期转换添乱,咱们一步步来解决:
问题根源
你当前的get_Cmplt_Date函数遇到空值时返回空字符串,后续转日期时会变成NaT(Not a Time),而pd.bdate_range完全不接受NaT作为起始/结束参数,所以触发了ValueError。
解决方案分两步:修正空值处理 + 安全计算工作日
1. 简化日期转换,让空值正确转为NaT
首先可以去掉冗余的conv_str和get_Cmplt_Date函数,直接用pd.to_datetime的errors='coerce'参数,自动把空值/无效值转为NaT:
from pandas.tseries.holiday import USFederalHolidayCalendar from pandas.tseries.offsets import CustomBusinessDay import pandas as pd import numpy as np def getCompDataFromFile(): colspecsvalues = ( (0, 9), (10, 34), (35, 45), (46, 56) ) col_names = ["EmpID", "Name", "StartDt", "CompleteDt"] # 直接读入,不需要额外的字符串转换 df = pd.read_fwf(r'path to file', colspecs=colspecsvalues, names=col_names) # 转日期,空值自动转为NaT df['StartDt'] = pd.to_datetime(df['StartDt'], format='%m/%d/%Y', errors='coerce') df['CompleteDt'] = pd.to_datetime(df['CompleteDt'], format='%m/%d/%Y', errors='coerce') # 定义美国工作日日历 us_bus = CustomBusinessDay(calendar=USFederalHolidayCalendar()) # 定义安全计算工作日的函数 def calculate_work_days(row): start = row['StartDt'] end = row['CompleteDt'] # 检查结束日期是否为空 if pd.isna(end): # 这里可以按需修改:比如返回NaN表示未完成,或者计算到当前日期 # 示例1:返回NaN return pd.NA # 示例2:计算到今天的工作日数 # end = pd.Timestamp.today().normalize() # return len(pd.bdate_range(start, end, freq=us_bus)) - 1 # 正常计算工作日(减1是因为bdate_range包含首尾两天) return len(pd.bdate_range(start, end, freq=us_bus)) - 1 # 应用函数生成新列 df['DaysToCmplt'] = df.apply(calculate_work_days, axis=1) return df # 执行函数 DaysToCmplt = getCompDataFromFile() print(DaysToCmplt)
2. 可选:用矢量化操作替代apply提升效率
如果你的数据量很大,apply会比较慢,可以用np.where结合busday_count来实现矢量化计算:
# 替代apply的矢量化写法 holidays = us_bus.holidays(start=df['StartDt'].min(), end=df['CompleteDt'].max()).date df['DaysToCmplt'] = np.where( df['CompleteDt'].notna(), np.busday_count(df['StartDt'].dt.date, df['CompleteDt'].dt.date, holidays=holidays), pd.NA # 空结束日期的处理逻辑 )
这个写法比apply快很多,适合大数据集。
额外提示
- 如果你希望空结束日期显示为“未完成”而不是
NaN,可以把返回值改成字符串:return "未完成" - 注意
pd.Timestamp.today()会包含当前时间,用normalize()可以转成当天的0点,避免时间部分影响计算
备注:内容来源于stack exchange,提问作者RhettBrindle
相关产品推荐
相关产品推荐

