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

如何不使用datetime计算时间差?Python时间差计算问题求助

问题:时间差计算与设备活跃时长统计

问题描述

使用datetime模块计算时间差时遇到两个核心问题:

  1. 仅解析时间字符串(如"00:01:34")时,datetime.strptime(item[1], '%H:%M:%S')会自动附加1900-01-01的默认日期,后续计算差值后程序出现假死(实际是双重循环效率过低)。
  2. 尝试改用time模块或.time()方法时,触发TypeError: unsupported operand type(s) for -: 'builtin_function_or_method' and 'builtin_function_or_method'错误,原因是time实例不支持减法操作。

用户提供的代码(存在语法错误):

listaDivisa = [
['2010-01-05', '12:32:05', 'at the kitchen entrance from the dining room', 'ON']
['2010-01-05', '12:32:05', 'in the kitchen', 'ON']
['2010-01-05', '12:32:08', 'in the living room', 'ON']
['2010-01-05', '12:32:08', 'in the kitchen', 'OFF']
['2010-01-05', '12:32:10', 'at the kitchen entrance from the dining room', 'OFF']
['2010-01-05', '12:32:10', 'in the kitchen', 'ON']
['2010-01-05', '12:32:11', 'in the kitchen', 'OFF']
['2010-01-05', '12:32:11', 'in the living room', 'OFF']
['2010-01-06', '02:32:11', 'in the kitchen', 'ON']
['2010-01-06', '02:32:20', 'in the kitchen', 'OFF']
['2010-01-06', '02:34:23', 'in the living room', 'ON']
['2010-01-06', '02:34:42', 'in the living room', 'OFF']]
# this list contains approximately 3000 of this activities, obviously I put only 
# a few just for example

listaDict = {}

for p in listaDivisa:
    if p[2] not in listaDict.keys():
        listaDict[p[2]] = dict()

for i, item in enumerate(listaDivisa):
    for j in range(i + 1, len(listaDivisa) - 1):
        if item[0] == listaDivisa[j][0]:
            if item[2] == listaDivisa[j][2]:
                if item[3] == "ON" and listaDivisa[j][3] == "OFF":
                    t1 = datetime.strptime(item[1], '%H:%M:%S')
                    t2 = datetime.strptime(listaDivisa[j][1], '%H:%M:%S')
                    timedelta = (t2 - t1).seconds

                    listaDict[item[2]][item[
                        0]] = "active for " + str(
                        timedelta) + " seconds"

for key, value in listaDict.items():
    print(key, ' : ', value)

期望输出

生成按设备分组的嵌套字典,统计每个设备每天的总活跃时长:

{
    "in the kitchen": {
        "2010-01-05": "active for 4 seconds",
        "2010-01-06": "active for 9 seconds"
    },
    "in the living room": {
        "2010-01-05": "active for 3 seconds",
        "2010-01-06": "active for 19 seconds"
    },
    "at the kitchen entrance from the dining room": {
        "2010-01-05": "active for 5 seconds"
    }
}

解决方案

第一步:修复基础语法错误

原代码中listaDivisa的子列表之间缺少逗号,这会直接导致语法错误,需补充每个子列表末尾的逗号:

listaDivisa = [
    ['2010-01-05', '12:32:05', 'at the kitchen entrance from the dining room', 'ON'],
    ['2010-01-05', '12:32:05', 'in the kitchen', 'ON'],
    # ... 其余子列表均需添加逗号
]

第二步:重构逻辑,避免低效双重循环

原代码的双重循环(O(n²)复杂度)在3000条数据下会极慢,且会重复匹配ON与后续所有OFF,导致字典值被多次覆盖。正确做法是按设备+日期分组,排序后配对相邻的ON/OFF。

方案1:使用datetime模块(推荐,支持跨天场景)

将日期与时间合并为完整的datetime对象,确保时间差计算的准确性:

import datetime
from collections import defaultdict

listaDivisa = [
    ['2010-01-05', '12:32:05', 'at the kitchen entrance from the dining room', 'ON'],
    ['2010-01-05', '12:32:05', 'in the kitchen', 'ON'],
    ['2010-01-05', '12:32:08', 'in the living room', 'ON'],
    ['2010-01-05', '12:32:08', 'in the kitchen', 'OFF'],
    ['2010-01-05', '12:32:10', 'at the kitchen entrance from the dining room', 'OFF'],
    ['2010-01-05', '12:32:10', 'in the kitchen', 'ON'],
    ['2010-01-05', '12:32:11', 'in the kitchen', 'OFF'],
    ['2010-01-05', '12:32:11', 'in the living room', 'OFF'],
    ['2010-01-06', '02:32:11', 'in the kitchen', 'ON'],
    ['2010-01-06', '02:32:20', 'in the kitchen', 'OFF'],
    ['2010-01-06', '02:34:23', 'in the living room', 'ON'],
    ['2010-01-06', '02:34:42', 'in the living room', 'OFF']
]

# 初始化嵌套字典:设备 -> {日期: 总活跃秒数}
listaDict = defaultdict(lambda: defaultdict(int))

# 按设备+日期分组,存储时间与状态
grouped = defaultdict(lambda: defaultdict(list))
for item in listaDivisa:
    date = item[0]
    device = item[2]
    # 合并日期与时间为datetime对象
    dt = datetime.datetime.strptime(f"{date} {item[1]}", "%Y-%m-%d %H:%M:%S")
    grouped[device][date].append((dt, item[3]))

# 遍历分组,配对ON/OFF并计算总时长
for device, dates in grouped.items():
    for date, records in dates.items():
        # 按时间排序记录
        records.sort(key=lambda x: x[0])
        on_time = None
        for dt, status in records:
            if status == "ON":
                on_time = dt
            elif status == "OFF" and on_time is not None:
                # 累加活跃时长
                delta = (dt - on_time).seconds
                listaDict[device][date] += delta
                on_time = None  # 重置,等待下一个ON

# 转换为期望的字符串格式
result = {
    device: {date: f"active for {seconds} seconds" for date, seconds in dates.items()}
    for device, dates in listaDict.items()
}

# 打印结果
for key, value in result.items():
    print(f"{key}: {value}")

方案2:不使用datetime模块(纯字符串转秒计算)

将时间字符串转换为总秒数,通过整数减法计算差值:

from collections import defaultdict

def time_to_seconds(time_str):
    """将HH:MM:SS格式的时间转换为总秒数"""
    h, m, s = map(int, time_str.split(":"))
    return h * 3600 + m * 60 + s

listaDivisa = [
    # 同方案1的listaDivisa
]

# 初始化嵌套字典
listaDict = defaultdict(lambda: defaultdict(int))

# 按设备+日期分组,存储时间秒数与状态
grouped = defaultdict(lambda: defaultdict(list))
for item in listaDivisa:
    date = item[0]
    device = item[2]
    time_sec = time_to_seconds(item[1])
    grouped[device][date].append((time_sec, item[3]))

# 遍历分组计算总时长
for device, dates in grouped.items():
    for date, records in dates.items():
        records.sort(key=lambda x: x[0])
        on_sec = None
        for t_sec, status in records:
            if status == "ON":
                on_sec = t_sec
            elif status == "OFF" and on_sec is not None:
                delta = t_sec - on_sec
                listaDict[device][date] += delta
                on_sec = None

# 转换为期望格式
result = {
    device: {date: f"active for {seconds} seconds" for date, seconds in dates.items()}
    for device, dates in listaDict.items()
}

# 打印结果
for key, value in result.items():
    print(f"{key}: {value}")

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 10:18:31