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

Pandas中如何拆分跨午夜的时间记录并按日计算时长

跨天时间记录拆分与每日时长计算方案

原始数据集

首先加载示例时间区间数据:

import pandas as pd

df = pd.DataFrame({'Start': ['2022-01-01 08:30:00', '2022-01-01 13:00:00', '2022-01-02 22:00:00'],
                   'Stop': ['2022-01-01 12:00:00', '2022-01-02 10:30:00', '2022-01-04 8:00:00']})
df[['Start', 'Stop']] = df[['Start', 'Stop']].apply(pd.to_datetime)

原始数据结构:

StartStop
2022-01-01 08:30:002022-01-01 12:00:00
2022-01-01 13:00:002022-01-02 10:30:00
2022-01-02 22:00:002022-01-04 08:00:00

目标拆分后结构:

StartStop
2022-01-01 08:30:002022-01-01 12:00:00
2022-01-01 13:00:002022-01-02 00:00:00
2022-01-02 00:00:002022-01-02 10:30:00
2022-01-02 22:00:002022-01-03 00:00:00
2022-01-03 00:00:002022-01-04 00:00:00
2022-01-04 00:00:002022-01-04 08:00:00

方法1:拆分跨午夜记录,得到目标上采样结果

核心逻辑是提取每条时间区间覆盖的所有自然日0点作为切分点,和原起止时间拼接后两两配对生成新的区间,自动适配不跨天、跨1天、跨多天的所有场景:

def split_cross_day_intervals(input_df):
    split_records = []
    for _, row in input_df.iterrows():
        s = row['Start']
        e = row['Stop']
        # 生成区间内所有跨天的0点时间戳
        midnight_points = pd.date_range(
            start=s.normalize() + pd.Timedelta(days=1),
            end=e.normalize(),
            freq='D'
        )
        # 拼接所有切分节点:原开始时间 + 所有午夜点 + 原结束时间
        cut_nodes = [s] + list(midnight_points) + [e]
        # 相邻节点配对生成新的时间区间
        for i in range(len(cut_nodes) - 1):
            split_records.append({
                'Start': cut_nodes[i],
                'Stop': cut_nodes[i+1]
            })
    return pd.DataFrame(split_records)

# 执行拆分
split_df = split_cross_day_intervals(df)

拆分完成后直接计算时长即可:

split_df['duration'] = split_df['Stop'] - split_df['Start']

方法2:直接计算每日时长(无需拆分区间,性能更优)

如果核心需求只是统计每条记录对应的每日时长,不需要保留拆分后的区间结构,可以直接通过时间交集计算,数据量较大时运行效率更高:

# 给每条原始记录加唯一标识
df['record_id'] = df.index

# 生成每条记录覆盖的所有自然日
df['cover_date'] = df.apply(
    lambda x: pd.date_range(start=x['Start'].date(), end=x['Stop'].date(), freq='D'),
    axis=1
)
# 按日期展开行
daily_df = df.explode('cover_date')

# 计算每条记录在对应日期的有效起止点
daily_df['day_start'] = daily_df['cover_date']
daily_df['day_end'] = daily_df['cover_date'] + pd.Timedelta(days=1)
daily_df['valid_start'] = daily_df[['Start', 'day_start']].max(axis=1)
daily_df['valid_end'] = daily_df[['Stop', 'day_end']].min(axis=1)

# 计算当日时长
daily_df['daily_duration'] = daily_df['valid_end'] - daily_df['valid_start']

计算结果中record_id对应原始数据的行号,daily_duration就是该条记录在对应日期的累计时长。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 16:12:24