如何不使用datetime计算时间差?Python时间差计算问题求助
问题:时间差计算与设备活跃时长统计
问题描述
使用datetime模块计算时间差时遇到两个核心问题:
- 仅解析时间字符串(如
"00:01:34")时,datetime.strptime(item[1], '%H:%M:%S')会自动附加1900-01-01的默认日期,后续计算差值后程序出现假死(实际是双重循环效率过低)。 - 尝试改用
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
相关产品推荐
相关产品推荐

