import time import json import re import pendulum import datetime import pandas as pd from pot_libs.logger import log from pot_libs.common.components.responses import success_res from unify_api.modules.elec_charge.dao.syncretize_energy_es_dao import \ load_compy_power, load_spfv_price from unify_api.modules.elec_charge.dao.syncretize_energy_dao import \ get_annual_sunshine_hours, get_p, insert_price_policy_data_dao, \ inset_algorithm_power_factor_dao, get_elec_price_dao, \ get_algorithm_power_factor_dao, get_max_demand_by_inlid from unify_api.modules.elec_charge.components.syncretize_energy_cps import \ PvEvaluateComputeResp, Optimizecurve, ElectrovalenceResp, \ EssEvaluateComputeResp, OptCurve, PvEvaluateTwoResp from unify_api.modules.elec_charge.utils.pv_evaluate_tool import PvEvaluateTool from unify_api.modules.elec_charge.utils.ess_evaluate_tool import \ EssEvaluateTool from unify_api.utils.common_utils import ChineseCalendar from unify_api.modules.elec_charge.utils.co2_response import get_co2_price from unify_api.modules.common.dao.common_dao import inline_zdu_all_by_cid from unify_api.modules.zhiwei_u.service.scope_operations_service import \ dataframe_excl_download from unify_api.modules.zhiwei_u.dao.order_operations_dao import \ select_cname_by_cid # 综合能源-光伏-页面 async def pv_evaluate_service(cid, start, end): try: start_list = start.split("-") end_list = end.split("-") pendulum_start = pendulum.date(int(start_list[0]), int(start_list[1]), 1) pendulum_end = pendulum.date(int(end_list[0]), int(end_list[1]), 1) day_num = pendulum_end.days_in_month except: return success_res(code=4008, msg="日期输入错误") if (pendulum_end - pendulum_start).in_months() < 1: return success_res(code=4008, msg="日期最少选择2个月") elif (pendulum_end - pendulum_start).in_months() > 12: return success_res(code=4008, msg="日期最多选择12个月") else: p_datas = await load_compy_power(cid, f"{start}-01", f"{end}-{day_num}") if not p_datas: return PvEvaluateTwoResp(kwh_slot=[], p_slot=[], p=[], kwh=[], electrovalence={}, sum_kwh_p="", sum_kwh_s="", rule="") p_slots = {"%02d:%02d" % (i, j): [] for i in range(24) for j in range(0, 60, 15)} kwh_slots = {"%02d" % i: [] for i in range(24)} num, flag = 0, "00" for data in p_datas: create_time = data["create_time"].strftime("%Y-%m-%d %H:%M:%S") if data["p"]: p_slots[create_time[11:16]].append(data["p"]) if data["kwh"]: if flag == create_time[11:13]: num += data["kwh"] else: kwh_slots[flag].append(num) num = data["kwh"] flag = create_time[11:13] for key, value in kwh_slots.items(): kwh_slots[key] = round(sum(value) / len(value), 2) if value else "" # 获取峰时段 elec_price = await get_elec_price_dao(cid) if not elec_price: log.error(f"该厂还未设置电价, cid:{cid}, table:price_policy") return success_res(code=4008, msg="该厂还未设置电价") section_time_range = get_section_time_range(elec_price["quarters"]) elecs = get_section_time_slot(section_time_range) # 峰时段总用电量 sum_kwh_p = 0 for p in elecs["p"]: mid_kwh = kwh_slots.get(p[:2], 0) or 0 sum_kwh_p += mid_kwh return PvEvaluateTwoResp( kwh_slot=[f"{slot}:00" for slot in kwh_slots], p_slot=[slot for slot in p_slots], electrovalence=elecs, sum_kwh_p=round(sum_kwh_p, 2), p=[round(sum(p) / len(p), 2) if p else "" for p in p_slots.values()], kwh=list(kwh_slots.values())) # 综合能源-光伏-测算 async def pv_evaluate_compute_service(download=None, url=None, **body): try: start_list = body.get("start").split("-") end_list = body.get("end").split("-") pendulum_start = pendulum.datetime(int(start_list[0]), int(start_list[1]), 1) pendulum_end = pendulum.datetime(int(end_list[0]), int(end_list[1]), 1) day_num = pendulum_end.days_in_month except: return success_res(code=4008, msg="日期输入错误") try: # 面积 total_capacity = float(body.get("install_space")) * \ float(body.get("area_conversion_ratio")) # 工厂容量 =屋顶面积*折算系数*单位面积容量 invest_capacity = total_capacity * body.get( "capacity_per_meter") / 1000 if not invest_capacity: return success_res(code=4008, msg="场地面积/面积折算系数/单位面积容量不能为0") except: return success_res(code=4008, msg="工厂容器参数有误") if (pendulum_end - pendulum_start).in_months() < 1: return success_res(code=4008, msg="日期最少选择2个月") elif (pendulum_end - pendulum_start).in_months() > 12: return success_res(code=4008, msg="日期最多选择12个月") else: # 获取年有效日照小时数 hours = await get_annual_sunshine_hours(body.get("cid")) if not hours: log.error(f"未找到该城市日照时间 cid:{body.get('cid')}") return success_res(code=4008, msg="未找到该城市日照时间") annual_sunshine_hours = hours.get("annual_effective_hours") # 获取光伏典型出力曲线 负荷曲线df_pv ps = await get_p(body.get("cid")) if not ps: log.error(f"未找到该城市光伏典型出力曲线 cid:{body.get('cid')}") return success_res(code=4008, msg="未找到该城市光伏典型出力曲线") p_slots = {"%02d:%02d:00" % (i, j): [] for i in range(24) for j in range(0, 60, 15)} df_pv_curve = [p["p"] for p in ps for _ in range(4)] df_pv = pd.DataFrame( {"quarter_time": list(p_slots.keys()), "pv_curve": df_pv_curve}, columns=["quarter_time", "pv_curve"]) # 获取电量和负荷15分钟数据 datas = await load_compy_power(body.get("cid"), f"{body.get('start')}-01", f"{body.get('end')}-{day_num}") if not datas: return success_res(code=4008, msg="未找到数据") for data in datas: create_time = data["create_time"].strftime("%Y-%m-%d %H:%M:%S") if data["p"]: p_slots[create_time[11:19]].append(data["p"]) for index, value in p_slots.items(): p_slots[index] = sum(value) / len(value) if value else None # 负荷曲线df_load df_load = pd.DataFrame({"quarter_time": list(p_slots.keys()), "load_curve": list(p_slots.values())}, columns=["quarter_time", "load_curve"]) # 获取这段时间平均价格 charge_price, kwh_price = await load_spfv_price(body.get("cid"), f"{body.get('start')}-01", f"{body.get('end')}-{day_num}") spfv_price = charge_price / kwh_price if charge_price and kwh_price else 0 pv_system = { "user_type": "工商业", # 建筑类型 "install_space": body.get("install_space"), # 屋顶面积m2 "area_conversion_ratio": body.get("area_conversion_ratio"), # 面积折算系数 "capacity_per_meter": body.get("capacity_per_meter"), # 单位面积容量 "self_use_ratio": body.get("self_use_ratio"), # 自发自用比例 "efficiency": body.get("efficiency"), # 发电效率 "evaluate_year": body.get("evaluate_year"), # 评估年限 "first_3year_decay_rate": 0.015, # 前3年衰减率 "other_year_decay_rate": 0.008, # 4-25年衰减率 "annual_sunshine_hours": annual_sunshine_hours # 年峰值日照小数数 } price = { "rmb_per_wp": body.get("rmb_per_w"), # 建设单价 "maintenance_per_wp": body.get('maintenance_per_wp'), # 运维单价 "coal_in_grid": body.get("coal_in_grid"), # 脱硫电价 "self_use_price_discout": 1.0, # 自发自用电价折扣 "spfv_price": spfv_price, # 测算时段平均电价 "bank_interest": 0.085 } log.info(f"pv_system:{pv_system}, price:{price}, " f"invest_capacity:{invest_capacity}") obj = PvEvaluateTool(pv_system, price, invest_capacity, df_load, df_pv) obj.output() # 测算表 evaluate_table = ( obj.evaluate_table.where(obj.evaluate_table.notnull(), None)).round(2) # 下载 if download: company = await select_cname_by_cid(body.get("cid")) table_name = f"{company['shortname']}_" \ f"{body.get('start')}_{body.get('end')}分布式光伏测算表" return await dataframe_excl_download(evaluate_table, table_name) # 碳排放(吨) 碳排放系数 0.67 2020年该指标为305.5g/kWh,及0.3055kg/kWh c_emissions = obj.first_year_kwh * 0.67 * 0.3055 / 1000 # co2排放(吨) 碳元素(C)分子量为12,二氧化碳(CO2)分子量为44,两者折算比例为3.67 co2_emissions = c_emissions * 3.67 # 年收益 爬虫获取价格 co2_price = await get_co2_price() year_earnings = co2_emissions * co2_price # 优化曲线 curve = obj.curve curve["after_curve"] = curve["load_curve"] - curve["pv_curve"] curve = curve.round(2).where(curve.notnull(), None) optimizecurve = Optimizecurve( slot=curve["quarter_time"].values.tolist(), before_curve=curve["load_curve"].values.tolist(), after_curve=curve["after_curve"].values.tolist(), pv_curve=curve["pv_curve"].values.tolist() ) # 累计碳减排 co2 all_elec = sum(evaluate_table["年发电量"].values.tolist()) all_c_emissions = all_elec * 0.67 * 0.3055 / 1000 * 3.67 # 植树 tree = all_c_emissions * 1000 / 18.3 compute_table = evaluate_table.to_dict("records") return PvEvaluateComputeResp( optimize_curve=optimizecurve, compute_table=compute_table, invest_capacity=round(invest_capacity, 2), first_year_kwh=round(obj.first_year_kwh, 2), static_period=round(obj.static_period, 2), total_capacity=round(total_capacity, 2), invest_charge=round(obj.invest_charge, 2), c_emissions=round(c_emissions, 2), co2_emissions=round(co2_emissions, 2), year_earnings=round(year_earnings, 2), all_c_emissions=round(all_c_emissions, 2), tree=round(tree), download_url=url ) # 综合能源-储能-页面 async def ess_evaluate_service(cid, start, end, work_day): try: start_list = start.split("-") end_list = end.split("-") pendulum_start = pendulum.datetime(int(start_list[0]), int(start_list[1]), 1) pendulum_end = pendulum.datetime(int(end_list[0]), int(end_list[1]), 1) day_num = pendulum_end.days_in_month except: return success_res(code=4008, msg="日期输入错误") if (pendulum_end - pendulum_start).in_months() < 1: return success_res(code=4008, msg="日期最少选择2个月") elif (pendulum_end - pendulum_start).in_months() > 12: return success_res(code=4008, msg="日期最多选择12个月") else: elec = await get_elec_price_dao(cid) if not elec: rule = 1 else: elec_list = [i for i in re.findall("p*", elec["quarters"]) if i] rule = 2 if len(elec_list) > 1 else 1 p_datas = await load_compy_power(cid, f"{start}-01", f"{end}-{day_num}") if not p_datas: return PvEvaluateTwoResp(kwh_slot=[], p_slot=[], p=[], kwh=[], electrovalence={}, sum_kwh_p="", sum_kwh_s="", rule="") p_slots = {"%02d:%02d" % (i, j): [] for i in range(24) for j in range(0, 60, 15)} kwh_slots = {"%02d" % i: [] for i in range(24)} num, flag = 0, "00" # 1全部 2工作日 3非工作日 if work_day == 2: for data in p_datas: create_time = data["create_time"].strftime("%Y-%m-%d %H:%M:%S") if ChineseCalendar(create_time[:10]).is_workday(): if data["p"]: p_slots[create_time[11:16]].append(data["p"]) if data["kwh"]: if flag == create_time[11:13]: num += data["kwh"] else: kwh_slots[flag].append(num) num = data["kwh"] flag = create_time[11:13] elif work_day == 3: for data in p_datas: create_time = data["create_time"].strftime("%Y-%m-%d %H:%M:%S") if not ChineseCalendar(create_time[:10]).is_workday(): if data["kwh"]: if flag == create_time[11:13]: num += data["kwh"] else: kwh_slots[flag].append(num) num = data["kwh"] flag = create_time[11:13] if data["p"]: p_slots[create_time[11:16]].append( data["p"]) else: for data in p_datas: create_time = data["create_time"].strftime("%Y-%m-%d %H:%M:%S") if data["p"]: p_slots[create_time[11:16]].append(data["p"]) if data["kwh"]: if flag == create_time[11:13]: num += data["kwh"] else: kwh_slots[flag].append(num) num = data["kwh"] flag = create_time[11:13] for key, value in kwh_slots.items(): kwh_slots[key] = round(sum(value) / len(value), 2) if value else "" # 获取峰时段 elec_price = await get_elec_price_dao(cid) if not elec_price: log.error(f"该厂还未设置电价, cid:{cid}, table:price_policy") return success_res(code=4008, msg="该厂还未设置电价") section_time_range = get_section_time_range(elec_price["quarters"]) elecs = get_section_time_slot(section_time_range) # 峰时段总用电量 sum_kwh_p = 0 for p in elecs["p"]: mid_kwh_p = kwh_slots.get(p[:2], 0) or 0 sum_kwh_p += mid_kwh_p # 尖时段总用电量 sum_kwh_s = "" if elec_price.get("price_s") and elecs.get("s"): sum_kwh_s = 0 for s in elecs["s"]: mid_kwh_s = kwh_slots.get(s[:2], 0) or 0 sum_kwh_s += mid_kwh_s sum_kwh_s = round(sum_kwh_s, 2) return PvEvaluateTwoResp( rule=rule, p_slot=[slot for slot in p_slots], kwh_slot=[f"{slot}:00" for slot in kwh_slots], electrovalence=elecs, sum_kwh_p=round(sum_kwh_p, 2), sum_kwh_s=sum_kwh_s, p=[round(sum(p) / len(p), 2) if p else "" for p in p_slots.values()], kwh=list(kwh_slots.values())) # 综合能源-储能-测算 async def ess_evaluate_compute_service(download=None, url=None, **body): try: start_list = body.get("start").split("-") end_list = body.get("end").split("-") pendulum_start = pendulum.datetime(int(start_list[0]), int(start_list[1]), 1) pendulum_end = pendulum.datetime(int(end_list[0]), int(end_list[1]), 1) day_num = pendulum_end.days_in_month except: return success_res(code=4008, msg="日期输入错误") if (pendulum_end - pendulum_start).in_months() < 1: return success_res(code=4008, msg="日期最少选择2个月") elif (pendulum_end - pendulum_start).in_months() > 12: return success_res(code=4008, msg="日期最多选择12个月") else: # 查找电价 elec_prices = await get_elec_price_dao(body.get("cid")) # elec_price = {key: ";".join(value) for key, value in elec_prices.items() if value} if not elec_prices: log.error( f"该厂还未设置电价, cid:{body.get('cid')}, table:price_policy") return success_res(code=4008, msg="该厂还未设置电价") section_time_range = get_section_time_range(elec_prices["quarters"]) # 获取工厂容量 inline_zdu_dic = await inline_zdu_all_by_cid(body.get("cid")) capacity = sum([inline["inline_tc"] if inline.get("inline_tc") else 0 for inline in inline_zdu_dic]) # 需量信息 inlids = [inline["inlid"] for inline in inline_zdu_dic] max_demand = await get_max_demand_by_inlid(inlids) max_demand_flag = False max_demand_pmax = 0 if max_demand: max_demand_list = [json.loads(demand["has_space"]) for demand in max_demand if demand["has_space"]] for demand in max_demand_list: if len(demand) == 0: continue if demand[0] and max_demand_flag is False: max_demand_flag = True max_demand_pmax += demand[1] max_demand_var = {"flag": max_demand_flag, "pmax": max_demand_pmax} # 获取电量和负荷15分钟数据 datas = await load_compy_power(body.get("cid"), f"{body.get('start')}-01", f"{body.get('end')}-{day_num}") if not datas: return success_res(code=4008, msg="未找到数据") p_slots = {"%02d:%02d:00" % (i, j): [] for i in range(24) for j in range(0, 60, 15)} for data in datas: create_time = data["create_time"].strftime("%Y-%m-%d %H:%M:%S") # 1全部 2工作日 3非工作日 if body.get("work_day") == "2": if ChineseCalendar(create_time[:10]).is_workday() and data[ "p"]: p_slots[create_time[11:19]].append( data["p"]) elif body.get("work_day") == "3": if not ChineseCalendar( create_time[:10]).is_workday() and data["p"]: p_slots[create_time[11:19]].append( data["p"]) else: if data["p"]: p_slots[create_time[11:19]].append(data["p"]) for index, value in p_slots.items(): p_slots[index] = sum(value) / len(value) if value else None # 负荷典型用电曲线 df_curve df_curve = pd.DataFrame( {"quarter_time": list(p_slots.keys()), "p": list(p_slots.values())}, columns=["quarter_time", "p"]) df_curve.loc[:, "quarter_time"] = pd.to_datetime( df_curve.loc[:, "quarter_time"]) if elec_prices.get("price_s") and section_time_range.get("s"): peak_valley_price = elec_prices["price_s"] - elec_prices["price_v"] peak_flat_price = elec_prices["price_s"] - elec_prices["price_f"] else: peak_valley_price = elec_prices["price_p"] - elec_prices["price_v"] peak_flat_price = elec_prices["price_p"] - elec_prices["price_f"] log.info(f"cid:{body.get('cid')}, 峰谷价差:{peak_valley_price}, " f"峰平价差:{peak_flat_price}") price = { "epc_price": body.get("epc_price"), # epc单价,元/Wh "bank_interest": 0.085, # 折现率 "capacity_price": elec_prices["price_tc"], # 容量电费 "max_demand_price": elec_prices["price_md"], # 需量电费 # 峰谷价差,元/kWh 或者尖谷价差 "peak_valley_price": peak_valley_price, # 峰平价差,元/kWh 或者尖平价差 "peak_flat_price": peak_flat_price, "kwh_subsidy": body.get("kwh_subsidy"), # 度电补贴 # "section_s":{"time_range": "14:00-17:00;19:00-22:00"}, "section_f": {"time_range": ";".join(section_time_range["f"])}, "section_p": {"time_range": ";".join(section_time_range["p"])}, "section_v": {"time_range": ";".join(section_time_range["v"])} } if section_time_range.get("s"): price["section_s"] = \ {"time_range": ";".join(section_time_range.get("s"))} evaluate_year = 5000 // (int(body.get("rule")) * int(body.get("year_use_days"))) ess_system = { "capacity": capacity, # 工厂容量,kVA, "rule": body.get("rule"), # 一充一放或两充两放 "install_capacity": body.get("install_capacity"), # kWh "bat_efficiency": 0.95, # 电池效率 "pcs_efficiency": 0.95, # pcs转换效率 "DOD": body.get("DOD"), # 放电深度 "decay_rate": body.get("decay_rate"), # 衰减率 # 年运维费用占静态投资额比例 "maintenance_ratio_per_year": body.get( "maintenance_ratio_per_year"), "year_use_days": body.get("year_use_days"), # 一年可利用时间 "evaluate_year": evaluate_year, # 评估年限 "subsidy_year": body.get("subsidy_year"), # 补贴年限 # "invest_income_rate": (15, 12, 10, 8, 6), #投资收益率 "loop_time": 5000 # 循环次数 } obj = EssEvaluateTool(ess_system, price, max_demand_var, df_curve) obj.output() # 测算表 etable = obj.evaluate_table evaluate_table = etable.where(etable.notnull(), None).round(2) evaluate_table["固定成本"] = evaluate_table["固定成本"].abs() # 下载 if download: company = await select_cname_by_cid(body.get("cid")) table_name = f"{company['shortname']}_{body.get('start')}" \ f"_{body.get('end')}储能测算表" return await dataframe_excl_download(evaluate_table, table_name) curve = (obj.opt_curve.where(obj.opt_curve.notnull(), None)).round( 2).reset_index() opt_curve = OptCurve( slot=curve["quarter_time"].values.tolist(), load_curve=curve["load_curve"].values.tolist(), bat_curve=curve["bat_curve"].values.tolist(), load_bat_curve=curve["load_bat_curve"].values.tolist(), ) ess_compute_table = evaluate_table.to_dict("records") return EssEvaluateComputeResp( evaluate_table=opt_curve, ess_compute_table=ess_compute_table, invest_capacity=round(obj.invest_capacity, 2), static_period=round(obj.static_period, 2), pcs_capacity=round(obj.pcs_capacity, 2), month_average_dc_kwh=round(obj.month_average_dc_kwh, 2), month_dc_benefit=round(obj.month_dc_benefit, 2), download_url=url, ) # 电价设置 async def electrovalence_setting_service(cid, price_md, price_tc, std_cos, electrovalence): if std_cos not in (0.8, 0.85, 0.9): return success_res(code=4008, msg="功率因数错误") if price_md < 15 or price_md > 50: return success_res(code=4008, msg="容量单价范围应该在15-50之间") if price_tc < 15 or price_tc > 50: return success_res(code=4008, msg="需量单价范围应该在15-50之间") t = {} price_s, price_p, price_f, price_v = None, None, None, None for elec in electrovalence: if elec["name"] == "s": # 尖 price_s = elec.get("price", None) # s可能没有 if elec["name"] == "p": # 峰 price_p = elec["price"] if elec["name"] == "f": # 平 price_f = elec["price"] if elec["name"] == "v": # 谷 price_v = elec["price"] for slot in elec["slot"]: if slot[1] == "00:00": slot[1] = "24:00" start = slot[0].split(":") end = slot[1].split(":") if int(end[0]) < int(start[0]) or \ (int(end[0]) == int(start[0]) and int(end[1]) <= int( start[1])): return success_res(code=400, msg="结束时间需要大于开始时间") fina = int(end[0]) + 1 if end[1] != "00" else int(end[0]) for index, num in enumerate(range(int(start[0]), fina)): num = int(num) # 开始时间的分钟数不是0 if index == 0: for j in range(int(start[1]), 60, 15): now_time = f"%02d:%02d" % (num, j) if now_time in t.keys(): print(now_time) print(t) return success_res(code=400, msg="电价配置信息有误,存在重叠时间") t[now_time] = elec["name"] # 结束时间的分钟数不是0 elif index == (fina - 1) and end[1] != "00": for j in range(0, int(end[1]), 15): now_time = f"%02d:%02d" % (num, j) if now_time in t.keys(): print(now_time) print(t) return success_res(code=400, msg="电价配置信息有误,存在重叠时间") t[now_time] = elec["name"] else: for j in range(0, 60, 15): now_time = f"%02d:%02d" % (num, j) if now_time in t.keys(): print(now_time) print(t) return success_res(code=400, msg="电价配置信息有误,存在重叠时间") t[now_time] = elec["name"] if len(t.keys()) != 24 * 4: return success_res(code=400, msg="电价配置信息有误,缺少时间段") quarters = "".join([i[1] for i in sorted(t.items(), key=lambda x: x[0])]) start_month = int(time.time()) effect_time = datetime.date.today() + datetime.timedelta(days=1) effect_date = datetime.datetime(effect_time.year, effect_time.month, effect_time.day, 0, 0, 0).timestamp() # 找出cid 的所有inline_id inline_zdu_dic = await inline_zdu_all_by_cid(cid) # 1 设置电度电费 生效时间为明天凌晨 for inline in inline_zdu_dic: inline_id = inline["inlid"] # 插入数据 await insert_price_policy_data_dao(cid, inline_id, start_month, quarters, price_s, price_p, price_f, price_v, price_md, price_tc, effect_date) # 2 设置力调电价 await inset_algorithm_power_factor_dao(inline_id, start_month, std_cos) return success_res(code=200, msg="设置电价成功") async def electrovalence_service(cid): # 查找力调电费 datas = await get_algorithm_power_factor_dao(cid) std_cos = float(datas.get("std_cos")) if datas.get("std_cos") else None # 查找电价 elec_price = await get_elec_price_dao(cid) if not elec_price: log.error(f"该厂还未设置电价, cid:{cid}, table:price_policy") return success_res(code=4008, msg="该厂还未设置电价") section_time_range = get_section_time_range(elec_price["quarters"]) electrovalence = [] for section, value in section_time_range.items(): electrovalence.append({ "name": section, "price": elec_price.get(f"price_{section}"), "slot": [v.split("-") for v in value], }) return ElectrovalenceResp( price_md=elec_price["price_md"], price_tc=elec_price["price_tc"], std_cos=std_cos, electrovalence=electrovalence ) def get_section_time_range(quarters): # vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvffffffffppppssssffffffffppppssssssssppppppppffffffffffffffffffff # 转化成 {'v': '00:00-08:00', 's': '11:00-12:00;15:00-17:00', # 'p': '10:00-11:00;14:00-15:00;17:00-19:00', # 'f': '08:00-10:00;12:00-14:00;19:00-24:00'} d = {"v": [], "s": [], "p": [], "f": []} last_i, last_t = "", "" for index, i in enumerate(quarters): num = index % 4 q = index // 4 t = "%02d:%02d" % (q, num * 15) if index == 0: last_i = i last_t = t elif last_i != i: d[i].append(f"{t}-{t}") last_i = i last_t = t if d[i]: if (num + 1) * 15 == 60: q += 1 end = 0 else: end = (num + 1) * 15 end_t = "%02d:%02d" % (q, end) q = d[i][-1][:5] d[i].pop() d[i].append(f"{q}-{end_t}") else: d[i].append(f"{last_t}-{t}") return d def get_section_time_slot(elecs): d = {"v": [], "s": [], "p": [], "f": []} for name, value in elecs.items(): for slot in value: start, end = slot.split("-") start_h, start_m = [int(i) for i in start.split(":")] end_h, end_m = [int(i) for i in end.split(":")] if start_m != 0: start_h += 1 if end_m != 0: end_h += 1 for i in range(start_h, end_h): d[name].append("%02d:00" % i) return d