You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何在Pandas中计算排除周末/节假日的时间小时差?

解决Pandas中计算德国工作日小时差的问题

嘿,我来帮你搞定这个在Pandas里计算德国工作日小时差的需求!你之前遇到的TypeError,主要是因为np.busday_count的使用方式不对——它默认只处理纯日期类型(不带时分秒),而且参数顺序也搞反了,得是起始日期在前,结束日期在后才行。

咱们一步步来实现你的需求,先从你的示例开始,再扩展到更通用的场景,甚至包含德国法定节假日的情况。

第一步:准备数据并确保类型正确

首先得把你的startend列转换成Pandas的datetime类型,不然没法处理时间相关的计算:

import pandas as pd
import numpy as np

# 你的示例数据
data = {'start': ['2019-01-01 08:00:00'], 'end': ['2019-01-08 08:00:00']}
df = pd.DataFrame(data)

# 转换为datetime类型
df[['start', 'end']] = df[['start', 'end']].apply(pd.to_datetime)

第二步:计算基础工作日小时差(不含德国法定假日)

德国的工作日是周一到周五,和np.busday_count默认的weekmask='1111100'(周一到周五为工作日)一致,所以咱们直接用这个规则:

  1. 先提取日期部分,计算两个日期之间的工作日天数:
# 提取纯日期,传入busday_count,注意顺序是start在前,end在后
bus_days = np.busday_count(df['start'].dt.date, df['end'].dt.date)

你的示例中,2019-01-01到2019-01-08之间有5个工作日(1号是周二,8号是周二,中间跳过了两个周末),所以bus_days的值是5。

  1. 再处理时间部分的差值:
    如果你的startend时间点相同(比如都是08:00),直接用bus_days * 24就能得到小时数。如果时间点不同,就得提取时分秒转换成小时数,再做调整:
# 把时间部分转换成小时数(包含分钟、秒的小数)
start_hour = df['start'].dt.hour + df['start'].dt.minute/60 + df['start'].dt.second/3600
end_hour = df['end'].dt.hour + df['end'].dt.minute/60 + df['end'].dt.second/3600

# 计算总工作日小时数
df['Diff'] = bus_days * 24 + (end_hour - start_hour)

运行后你的示例会得到100.0,完全符合预期!

第三步:加入德国法定节假日的排除

如果需要排除德国的法定假日,咱们可以把这些假日整理成数组,传给bus_days_countholidays参数。比如2019年的德国全国性法定假日:

# 2019年德国全国性法定假日(部分州可能有额外假日,可自行补充)
german_holidays_2019 = [
    '2019-01-01', '2019-04-19', '2019-04-22',
    '2019-05-01', '2019-05-30', '2019-06-09',
    '2019-10-03', '2019-12-25', '2019-12-26'
]
# 转换为datetime64[D]类型,符合busday_count的要求
holidays = np.array(german_holidays_2019, dtype='datetime64[D]')

# 计算包含假日排除的工作日天数
bus_days_with_holidays = np.busday_count(
    df['start'].dt.date, 
    df['end'].dt.date, 
    holidays=holidays
)

# 重新计算小时差
df['Diff_with_holidays'] = bus_days_with_holidays * 24 + (end_hour - start_hour)

这样就能精准排除德国的法定假日啦!

为啥你之前的代码报错?

你之前写的np.busday_count(df['end'], df['start'])有两个问题:

  1. 参数顺序反了busday_count的第一个参数是起始日期,第二个是结束日期,反过来会得到负数或者错误结果;
  2. 数据类型不对df['start']是带时分秒的datetime64[ns]类型,而busday_count需要的是纯日期类型(datetime64[D]),所以得用dt.date或者dt.floor('D')转换后再传入。

内容的提问来源于stack exchange,提问作者PV8

火山引擎 最新活动