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

Pandas:计算中间In/Out记录的总timedelta(total_seconds())

解决方案

步骤1:数据预处理

首先将日期和时间合并为可计算的datetime类型,并按日期、姓名、时间排序,确保打卡序列的正确性:

import pandas as pd

# 加载示例数据
example_df = pd.DataFrame([
    ['2024-01-01', 'Homer', 'in', '07:30'],
    ['2024-01-01', 'Homer', 'out' ,'09:00'],
    ['2024-01-01', 'Homer', 'in' ,'09:30'],
    ['2024-01-01', 'Homer', 'out' ,'16:00'],
    ['2024-01-01', 'Marge', 'in' , '06:20'],
    ['2024-01-01', 'Marge', 'out' ,'16:00'],
    ['2024-01-01', 'Bart', 'in' ,'07:10'],
    ['2024-01-01', 'Bart', 'out' ,'08:00'],
    ['2024-01-01', 'Bart', 'in' ,'08:20'],
    ['2024-01-01', 'Bart', 'out' ,'17:00'],
    ['2024-01-01', 'Barney', 'in' ,'08:10'],
    ['2024-01-01', 'Lisa', 'in' ,'08:05'],
    ['2024-01-01', 'Lisa', 'out' ,'14:00'],
    ['2024-01-01', 'Lisa', 'in' ,'14:15'],
    ['2024-01-01', 'Lisa', 'out' ,'18:10'],
    ['2024-01-01', 'Millhouse', 'out' ,'19:10'],
    ['2024-02-01', 'Homer', 'in', '07:30'],
    ['2024-02-01', 'Homer', 'out' ,'09:00'],
    ['2024-02-01', 'Marge', 'in' , '06:30'],
    ['2024-02-01', 'Marge', 'out' ,'09:10'],
    ['2024-02-01', 'Marge', 'in' ,'10:10'],
    ['2024-02-01', 'Marge', 'out' ,'16:10'],
    ['2024-02-01', 'Bart', 'in' ,'07:10'],
    ['2024-02-01', 'Bart', 'out' ,'15:00'],
    ['2024-02-01', 'Barney', 'in' ,'08:10'],
    ['2024-02-01', 'Lisa', 'in' ,'08:05'],
    ['2024-02-01', 'Lisa', 'out' ,'16:00'],
    ['2024-02-01', 'Millhouse', 'in' ,'08:10'],
    ['2024-02-01', 'Millhouse', 'in' ,'08:10'],
    ['2024-02-01', 'Millhouse', 'in' ,'16:15']],
    columns=['Date', 'Name', 'In/Out', 'Time'])

# 合并日期与时间为datetime列
example_df['Datetime'] = pd.to_datetime(example_df['Date'] + ' ' + example_df['Time'])
# 按日期、姓名、时间排序
example_df = example_df.sort_values(by=['Date', 'Name', 'Datetime']).reset_index(drop=True)

步骤2:计算中间记录的总时间差

这里针对用户离岗后再返回的间隔时长(即out后接in的时间段)进行计算,这与你示例中Homer对应1800秒的逻辑匹配:

def calculate_middle_interval(group):
    if len(group) < 2:
        return 0
    # 获取下一条记录的时间和打卡状态
    group['next_datetime'] = group['Datetime'].shift(-1)
    group['next_inout'] = group['In/Out'].shift(-1)
    # 筛选出out后接in的有效间隔,计算总秒数
    valid_rows = group[(group['In/Out'] == 'out') & (group['next_inout'] == 'in')]
    total_seconds = (valid_rows['next_datetime'] - valid_rows['Datetime']).dt.total_seconds().sum()
    return total_seconds

# 按日期和姓名分组计算
result = example_df.groupby(['Date', 'Name']).apply(calculate_middle_interval).reset_index(name='Total_Seconds')

# 过滤无中间记录的条目
result = result[result['Total_Seconds'] > 0].reset_index(drop=True)

最终结果

运行上述代码后,result将只包含有中间打卡记录的用户,输出格式如下:

Date    Name  Total_Seconds
0  2024-01-01    Bart         1200.0
1  2024-01-01    Homer        1800.0
2  2024-01-01     Lisa         900.0
3  2024-02-01    Marge        3600.0

调整说明

如果你的“中间记录”指的是除首次入岗和末次离岗外的工作时长(即中间in-out对的工作时间总和),可替换为以下分组处理函数:

def calculate_middle_work_time(group):
    # 提取有效的in-out工作配对
    valid_pairs = []
    prev_in = None
    for _, row in group.iterrows():
        if row['In/Out'] == 'in':
            prev_in = row['Datetime']
        elif row['In/Out'] == 'out' and prev_in is not None:
            valid_pairs.append((prev_in, row['Datetime']))
            prev_in = None
    # 仅保留中间的工作配对(排除首尾)
    if len(valid_pairs) < 2:
        return 0
    middle_pairs = valid_pairs[1:-1] if len(valid_pairs) > 2 else valid_pairs[1:]
    total_seconds = sum((end - start).total_seconds() for start, end in middle_pairs)
    return total_seconds

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 09:55:57