Pandas计算当前时间与指定日期的营业时间差问题求助
解决营业时间差计算的性能与错误问题
嘿,我来帮你搞定这个问题!你遇到的两个核心问题——程序失败和耗时过长,其实都有明确的原因和解决方案,咱们一步步来拆解:
1. 先解决程序失败:参数顺序搞反了
你的BusHrs函数是计算从start到end的营业时间差,但你调用的时候传的是BusHrs(row['Current Date'], row['Updated Date'])——这里Current Date是2018年(晚的时间),Updated Date是2016年(早的时间),相当于让函数计算"未来到过去"的时间差,这肯定会出问题!
修正方法很简单,调换两个参数的顺序:
df['Time Since Last Update'] = df.apply(lambda row: BusHrs(row['Updated Date'], row['Current Date']), axis=1)
2. 再解决耗时过长:大时间跨度的性能优化
你看示例里的时间跨度是2年左右,businesstimedelta的默认计算方式是逐天遍历检查节假日和工作日,这么大的范围自然会慢到离谱。咱们可以换一种更高效的计算逻辑:先算完整工作天数的总小时,再加上首尾两天的零碎营业时间,不用逐天遍历。
优化后的BusHrs函数如下,速度会提升N倍:
import datetime import pytz import businesstimedelta import holidays as pyholidays workday = businesstimedelta.WorkDayRule( start_time=datetime.time(9), end_time=datetime.time(17), working_days=[0,1,2,3,4] ) vic_holidays = pyholidays.AU(prov='VIC') holidays = businesstimedelta.HolidayRule(vic_holidays) businesshrs = businesstimedelta.Rules([workday, holidays]) def BusHrs(start, end): # 处理start >= end的边界情况 if start >= end: return 0.0 start_date = start.date() end_date = end.date() # 情况1:开始和结束是同一天 if start_date == end_date: # 检查当天是否是工作日且非节假日 if start_date.weekday() >=5 or start_date in vic_holidays: return 0.0 # 计算当天的有效营业时间 work_start = datetime.datetime.combine(start_date, workday.start_time) work_end = datetime.datetime.combine(start_date, workday.end_time) actual_start = max(start, work_start) actual_end = min(end, work_end) return (actual_end - actual_start).total_seconds() / 3600 # 情况2:时间跨度跨多天 # 计算总天数 total_days = (end_date - start_date).days # 计算这段时间内的节假日数量 holiday_count = sum(1 for date in vic_holidays if start_date <= date <= end_date) # 计算周末天数 start_weekday = start_date.weekday() weekend_days = total_days //7 *2 remaining_days = total_days %7 for day in range(remaining_days): if (start_weekday + day) %7 >=5: weekend_days +=1 # 完整工作天数 = 总天数 - 周末 - 节假日 full_work_days = total_days - weekend_days - holiday_count full_work_hrs = full_work_days *8 # 每天8小时 # 计算开始当天的剩余营业时间 start_work_end = datetime.datetime.combine(start_date, workday.end_time) start_work_start = datetime.datetime.combine(start_date, workday.start_time) if start >= start_work_end: start_hrs =0.0 elif start <= start_work_start: start_hrs =8.0 else: start_hrs = (start_work_end - start).total_seconds()/3600 # 计算结束当天的营业时间 end_work_start = datetime.datetime.combine(end_date, workday.start_time) end_work_end = datetime.datetime.combine(end_date, workday.end_time) if end <= end_work_start: end_hrs =0.0 elif end >= end_work_end: end_hrs =8.0 else: end_hrs = (end - end_work_start).total_seconds()/3600 # 总时间 = 完整工作小时 + 开始当天剩余 + 结束当天时间 - 8(因为完整工作天包含了首尾两天的全天,要减去重复计算的部分) total_hrs = full_work_hrs + start_hrs + end_hrs -8.0 return total_hrs
3. 额外注意:时区一致性问题
如果你的Current Date是带时区的datetime,而Updated Date是不带时区的naive datetime,这会导致datetime运算出错。建议统一所有日期的时区:
# 统一转换为墨尔本时区 melb_tz = pytz.timezone('Australia/Melbourne') df['Updated Date'] = df['Updated Date'].apply(lambda x: melb_tz.localize(x, is_dst=None)) df['Current Date'] = df['Current Date'].apply(lambda x: melb_tz.localize(x, is_dst=None))
按照这几步操作,应该就能解决你的问题了——既不会报错,计算速度也会快很多!
内容的提问来源于stack exchange,提问作者swifty
相关产品推荐
相关产品推荐

