场景
一项业务有多个状态,不同时段分别处于某个状态,按状态统计每个小时内的持续时长。
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import time ,datetime
def count_hours(hournum,data_list):
# 状态列表
status_list = list(set([status for status ,t_start ,t_end in data_list]))
# 列表时间转换为时间戳
datanum_map ={status0 :[[time.mktime(time.strptime(j ,"%Y-%m-%d %H:%M:%S")) for j in i[1:]] for i in data_list if i[0 ]==status0] for status0 in status_list}
# 计算24小时的开始结束时间、列表中的开始结束时间的并集求和
# 单行:
# res ={status0:{hour:sum([max(int(min(hournum[hour]+3600 ,t_end) -max(hournum[hour],t_start)) ,0) for t_start,t_end in datanum_map[status0]]) for hour in range(24)} for status0 in status_list}
# 拆分:
res={status0:{} for status0 in status_list}
for status0 in status_list:
for hour in range(24):
count_list = []
for t_start, t_end in datanum_map[status0]:
# max(hournum[hour],t_start) 取 hournum和datanum开始时间最大值作为并集的开始时间
# min(hournum[hour]+3600,t_end) 取 hournum+3600和datanum结束时间最大值作为并集的结束时间
# max(int(***-***),0) 并集为结束时间-开始时间,如果小于0则取0
count_list.append(max(int(min(hournum[hour] + 3600, t_end) - max(hournum[hour], t_start)), 0))
res[status0][hour]=sum(count_list)
return res
def count_date(date0 ,data_list):
# 24小时的开始时间转换为时间戳
# f"{date0} {'0' if hour<10 else ''}{hour}:00:00" 日期+小时+:00:00,其中小时小于10需补0
# time.mktime(time.strptime(***,"%Y-%m-%d %H:%M:%S")) 将时间字符串转换为时间戳
hournum = {hour:time.mktime(time.strptime(f"{date0}{' 0' if hour <10 else ' '}{hour}:00:00","%Y-%m-%d %H:%M:%S")) for hour in range(24)}
return count_hours(hournum,data_list)
def count_today(data_list):
# 计算每个小时的秒数
# 24小时的开始时间转换为时间戳
# datetime.datetime.today().replace(hour=1, minute=0, second=0, microsecond=0) 1点的开始时间对象
# int(***.timestamp()) 将时间字符串转换为时间戳
hournum = {hour: int(datetime.datetime.today().replace(hour=hour, minute=0, second=0, microsecond=0).timestamp()) for hour in range(24)}
return count_hours(hournum, data_list)
# 测试数据
today=str(datetime.datetime.today())[:10]
data_list = [(0, "2024-04-06 20:42:47", "2024-04-07 10:42:47"), (1, "2024-04-07 15:42:47", "2024-04-07 20:42:47"),
(0, f"{today} 15:42:47", f"{today} 20:42:47")]
res = count_today(data_list)
print(today,"\t"+"\n\t\t\t".join([f"{k} {v}" for k, v in res.items()]))
for data0 in ("2024-04-06", "2024-04-07",today):
res = count_date(data0, data_list)
print(data0, "\t"+"\n\t\t\t".join([f"{k} {v}" for k, v in res.items()]))
执行结果:
2024-04-10 0 {0: 0, 1: 0, 2: 0, 3: 0, 4: 0, 5: 0, 6: 0, 7: 0, 8: 0, 9: 0, 10: 0, 11: 0, 12: 0, 13: 0, 14: 0, 15: 1033, 16: 3600, 17: 3600, 18: 3600, 19: 3600, 20: 2567, 21: 0, 22: 0, 23: 0}
1 {0: 0, 1: 0, 2: 0, 3: 0, 4: 0, 5: 0, 6: 0, 7: 0, 8: 0, 9: 0, 10: 0, 11: 0, 12: 0, 13: 0, 14: 0, 15: 0, 16: 0, 17: 0, 18: 0, 19: 0, 20: 0, 21: 0, 22: 0, 23: 0}
2024-04-06 0 {0: 0, 1: 0, 2: 0, 3: 0, 4: 0, 5: 0, 6: 0, 7: 0, 8: 0, 9: 0, 10: 0, 11: 0, 12: 0, 13: 0, 14: 0, 15: 0, 16: 0, 17: 0, 18: 0, 19: 0, 20: 1033, 21: 3600, 22: 3600, 23: 3600}
1 {0: 0, 1: 0, 2: 0, 3: 0, 4: 0, 5: 0, 6: 0, 7: 0, 8: 0, 9: 0, 10: 0, 11: 0, 12: 0, 13: 0, 14: 0, 15: 0, 16: 0, 17: 0, 18: 0, 19: 0, 20: 0, 21: 0, 22: 0, 23: 0}
2024-04-07 0 {0: 3600, 1: 3600, 2: 3600, 3: 3600, 4: 3600, 5: 3600, 6: 3600, 7: 3600, 8: 3600, 9: 3600, 10: 2567, 11: 0, 12: 0, 13: 0, 14: 0, 15: 0, 16: 0, 17: 0, 18: 0, 19: 0, 20: 0, 21: 0, 22: 0, 23: 0}
1 {0: 0, 1: 0, 2: 0, 3: 0, 4: 0, 5: 0, 6: 0, 7: 0, 8: 0, 9: 0, 10: 0, 11: 0, 12: 0, 13: 0, 14: 0, 15: 1033, 16: 3600, 17: 3600, 18: 3600, 19: 3600, 20: 2567, 21: 0, 22: 0, 23: 0}
2024-04-10 0 {0: 0, 1: 0, 2: 0, 3: 0, 4: 0, 5: 0, 6: 0, 7: 0, 8: 0, 9: 0, 10: 0, 11: 0, 12: 0, 13: 0, 14: 0, 15: 1033, 16: 3600, 17: 3600, 18: 3600, 19: 3600, 20: 2567, 21: 0, 22: 0, 23: 0}
1 {0: 0, 1: 0, 2: 0, 3: 0, 4: 0, 5: 0, 6: 0, 7: 0, 8: 0, 9: 0, 10: 0, 11: 0, 12: 0, 13: 0, 14: 0, 15: 0, 16: 0, 17: 0, 18: 0, 19: 0, 20: 0, 21: 0, 22: 0, 23: 0}