一、案例背景
现有电动汽车充电站订单记录数据集,包含很多站场很多天的数据,数据截取了早上6点至晚上19点的数据,字段包括充电站名称,充电桩名称,充电枪名称,开始充电时间,结束充电时间。充电站里面很多充电枪,雨棚上搭建了光伏发电,光伏发的电全部用于汽车充电,充电站里只要有大于1条枪充电,充电期间光伏发的电都会被使用。当所有枪都没有充电时,光伏发的电将被浪费掉。通过这些数据计算每个充电站场每天有人充电时间占比,即光伏时间利用率。示例数据:假设场站有两条枪,A枪和B枪,在某一天这些枪有下面的充电订单:
充电枪 | 开始充电时间 | 结束充电时间 |
A枪 | 2023-10-21 11:32:22 | 2023-10-21 12:22:20 |
B枪 | 2023-10-21 11:45:25 | 2023-10-21 13:15:24 |
A枪 | 2023-10-21 13:50:21 | 2023-10-21 14:30:21 |
以上三条计算实际的光伏利用时间段为【2023-10-21 11:32:22,2023-10-21 13:15:24】、【2023-10-21 13:50:21,2023-10-21 14:30:21】。最终计算这些光伏利用时间段占一天中的百分比。
二、解题思路
1、将开始充电时间和结束充电时间转换为在一天当中第几秒。比如开始时间为2023-10-21 10:01:21转换为10*60*60+1*60+21=36081,即这个时间是在当天的36081秒。全天共60*60*25=86400秒。
1、日期转换
'''
datetime.strptime(start_time,"%Y-%m-%d %H:%M:%S"): 这一行将start_time字符串解析为一个datetime对象。%Y-%m-%d %H:%M:%S是Python的日期和时间格式,其中:
%Y 表示四位数的年份 (例如, 2023)
%m 表示两位数的月份 (例如, 07)
%d 表示两位数的日期 (例如, 06)
%H 表示24小时制的小时数 (例如, 13)
%M 表示分钟数 (例如, 30)
%S 表示秒数 (例如, 45)
'''
t1=datetime.strptime(start_time,"%Y-%m-%d %H:%M:%S") #2023-10-21 11:55:23
2、日期拼接
t2=datetime.combine(t1.date(),datetime.min.time()) #2023-10-21 00:00:00
3、计算秒数
'''
这行代码计算了两个datetime对象之间的差值,得到的结果是一个timedelta对象,该对象包含了两个时间点之间的时间差。这个差值是以秒为单位的。
'''
total_seconds=int((t1-t2).total_seconds()) #total_seconds()方法返回总秒数
2、编写函数,接受一个时间间隔列表作为输入,并返回一个合并后的时间间隔列表。这在日程安排或时间段合并等应用中可能会有用。
#输入[[3,7],[2,6],[4,5],[12,19]]输出[[2,7],[12,19]]
def merge_time_intervals(intervals):
if not intervals:
return []
# 根据时间区间的起始时间进行排序
intervals.sort(key=lambda x: x[0])
merged = [intervals[0]]
for interval in intervals[1:]:
if interval[0] <= merged[-1][1]:
print("merged[-1][1]:",merged[-1][1])
merged[-1][1] = max(merged[-1][1], interval[1])
else:
merged.append(interval)
return merged
input=[[3,7],[2,6],[4,5],[12,19]]
print(merge_time_intervals(input))
3、计算合并后的时间间隔列表的总秒数
#计算时间间隔列表merged里面的总秒数
#输入[[3,7],[2,6],[4,5],[12,19]]输出[[2,7],[12,19]]
def merge_time_intervals(intervals):
if not intervals:
return []
# 根据时间区间的起始时间进行排序
intervals.sort(key=lambda x: x[0])
merged = [intervals[0]]
for interval in intervals[1:]:
if interval[0] <= merged[-1][1]:
#print("merged[-1][1]:",merged[-1][1])
merged[-1][1] = max(merged[-1][1], interval[1])
else:
merged.append(interval)
print(merged)
return merged
l=[[3,7],[2,6],[4,5],[12,19]]
merged=merge_time_intervals(l)
'''
merged 是一个元组列表[[2,7],[12,19]],每个元组包含两个元素,我们假设它们是时间戳。
列表中的元组表示一系列的时间段。
end - start 对每个元组中的 start 和 end 时间戳进行操作,得到每个时间段的持续时间。
sum(end - start for start, end in merged)
使用了 Python 的生成器表达式(也称为“列表推导式”)来生成一个包含所有时间差值的列表,
然后使用 sum() 函数计算这个列表中所有值的总和。
'''
total_duration = sum(end - start for start, end in merged)
print(total_duration)
#输出:[[2, 7], [12, 19]]
# 12
#(7-2) + (19-12) =5+7=12
三、完整代码
import pandas as pd
from datetime import datetime
df = pd.read_excel(r'E:\SynologyDrive\python\计算光伏时间利用率\用于光伏利用率计算的数据集-发csdn.xlsx')
grouped = df.groupby(['场站名称',df['开始充电时间'].apply(lambda x: datetime.strptime(x, '%Y-%m-%d %H:%M:%S').date())])
# 计算开始时间和结束时间在一天当中第几秒
def get_time_difference(start_time, end_time):
#start_time=2023-08-26 10:11:32
r1=int((datetime.strptime(start_time,"%Y-%m-%d %H:%M:%S") - datetime.combine(datetime.strptime(start_time,"%Y-%m-%d %H:%M:%S").date(),datetime.min.time())).total_seconds())
if datetime.strptime(start_time,"%Y-%m-%d %H:%M:%S").date()<datetime.strptime(end_time,"%Y-%m-%d %H:%M:%S").date():
r2=86400 #开始时间的日期小于结束时间的日期,即充电订单时间跨了一天
else:
r2=int((datetime.strptime(end_time,"%Y-%m-%d %H:%M:%S") - datetime.combine(datetime.strptime(end_time,"%Y-%m-%d %H:%M:%S").date(),datetime.min.time())).total_seconds())
#print(r1,r2)
return [r1,r2]
# 对每个分组中的开始时间和结束时间放到一个列表中
result = {
'场站名称': [],
'日期': [],
'开始时间': [],
'结束时间': [],
'填充区间':[],
'合并区间':[],
'时长':[],
'光伏时间利用率':[]
}
#输入[[3,7],[2,6],[4,5],[12,19]]输出[[2,7],[12,19]]
def merge_time_intervals(intervals):
if not intervals:
return []
# 根据时间区间的起始时间进行排序
intervals.sort(key=lambda x: x[0])
merged = [intervals[0]]
for interval in intervals[1:]:
if interval[0] <= merged[-1][1]:
#print("merged[-1][1]:",merged[-1][1])
merged[-1][1] = max(merged[-1][1], interval[1])
else:
merged.append(interval)
total_duration = sum(end - start for start, end in merged)
时间利用率=total_duration/86400
return merged,total_duration,时间利用率
for name, group in grouped:
result['场站名称'].append(name[0])
result['日期'].append(name[1])
result['开始时间'].append(group['开始充电时间'].tolist())
result['结束时间'].append(group['结束充电时间'].tolist())
r=[]
for i,item in enumerate(group['开始充电时间'].tolist()):
timerange=get_time_difference(group['开始充电时间'].tolist()[i],group['结束充电时间'].tolist()[i])
r.append(timerange)
result['填充区间'].append(r)
t=merge_time_intervals(r)
result['合并区间'].append(t[0])
result['时长'].append(t[1])
result['光伏时间利用率'].append(t[2])
# 打印结果
for i, v in enumerate(result['场站名称']):
#print(f'场站名称: {v}, 日期: {result["日期"][i]}, 开始时间: {result["开始时间"][i]}, 结束时间: {result["结束时间"][i]},填充区间:{result["填充区间"][i]}')
print(f'场站名称: {v}, 日期: {result["日期"][i]}, 合并区间:{result["合并区间"][i]},时长:{result["时长"][i]},光伏时间利用率:{result["光伏时间利用率"][i]}')
df = pd.DataFrame(result)
# 将DataFrame写入Excel文件
df.to_excel('光伏时间利用率计算结果result.xlsx', index=False)
四、相关数据集及计算结果
本文绑定两个资源:
1、数据集
2、计算结果