充电桩设备升级扩展多段计费

news2024/11/15 21:35:34

 一 项目背景   

         某省某市的一个充电桩项目近日收到业主需求,需在国庆节增加一个时间段(深谷计费段),但充电桩设备仅支持4段(尖时段,峰时段,平时段,谷时段),今天已是23号下周就是国庆了任务时间紧,如果改充电桩设备并不能保证可以按时交付完成,原因:硬件升级开发不好评估:开发,与平台调试对接,测试,还要升级每台桩…最后决定使用软件扩展实现,下面我们详细介绍。

二 项目升级

1 需求与分析

        先看业主方的的需求:在原有的计费基础(尖时段,峰时段,平时段,谷时段)上增加一段计费,如下:

 从上图看,这个需求应该早就有了,只是业主现在才传达到我们开发这边。

        这个需求本身不是很难,但今天已是23号下周就是国庆了任务时间紧,由于充电设备厂家这边实现与对接不敢保证可以按时交付完成,经分析软件实现也存在一些小问题,在深谷段充电时由于深谷时间段的价格是最低的,我们下发深谷时段的价格只能使用最接近的谷段价格代替,这就会存在充电桩设备计算出来的金额(谷段电价*电量)大于平台计算金额(深谷段电价*电量),会引起充电桩设备提前结束充电(至少不会出现超充,保证业主权益,客户钱包则可能留有少量余额),之前我们也有类似实现案例,在经过和老板的讨论与业主确认后同意了,最最终决定使用软件扩展实现。

2 平台实现

         平台实现包含了运营管理平台,订单数据,报表,都要升级增加相应的字段,这里只列出涉及本次升级的关键点解释:

1 操作平台界面升级实现

先看平台已实现的需求图:

 平台只需增加深谷段即可:

在操作上原来的功能不变,只是追加了深谷字段。深谷时间设置要在谷时段的范围内,这是因为谷段的价格与深谷时段最接近,桩计算时误差也少,后台数据库增加相应的字段即可。 

2 充电订单数据生成实现

  确认业务逻辑

  充电订单的实现逻辑大体不需要改变,只需要在生成订单前的分段时间时增加以下逻辑。

   首先明确:谷时间 包含了深谷,具体业务逻辑:

  1. 软处理需要准确提取订单中含有区域时间范围
  2. 软处理需要准确提取订单中含有深谷区域时间范围
  3. 按平均计算电量(充电功率随着soc的变化会有偏差,业主同意) :谷每分钟充电量=谷电量/谷时间(分钟)。
  4. 对比谷 与 深谷 时长,正常是谷大于或等于深谷,当时长相等不用直接移到深谷即可,不作计算。深谷电量=深谷 时长*谷每分钟充电量谷电量=原谷电量-深谷电量 即可。

实现关键点:

多个深谷段,跨天时某个区域在时间范围的计算:

用java实现计算多个深谷段,跨天时某个区域在时间范围具体测试代码:

import java.time.Duration;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;

/**
 * @author hua
 * @date 2024-09-23 14:18
 */
public class TimeCheckDemo {


    /**
     * 计算在给定时间范围内的重叠分钟数
     * @param inputStartTime
     * @param inputEndTime
     * @param timeRange
     * @return
     */
    public static int calculateOverlapMinutes(String inputStartTime, String inputEndTime, String timeRange) {
        // 时间格式化器
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        // 将输入的字符串转换为LocalDateTime对象
        LocalDateTime startTime = LocalDateTime.parse(inputStartTime, formatter);
        LocalDateTime endTime = LocalDateTime.parse(inputEndTime, formatter);


        // 解析时间范围字符串,格式: "01:30,04:30"
        String[] rangeParts = timeRange.split(",");
        LocalTime rangeStart = LocalTime.parse(rangeParts[0]);
        LocalTime rangeEnd = LocalTime.parse(rangeParts[1]);

        // 时间范围跨天判断
        boolean isRangeCrossMidnight = rangeEnd.isBefore(rangeStart);

        // 初始化总重叠分钟数
        int totalOverlapMinutes = 0;

        // 处理当前天的重叠部分
        totalOverlapMinutes += calculateDayOverlapMinutes(startTime, endTime, rangeStart, rangeEnd, isRangeCrossMidnight);

        // 如果开始时间和结束时间不在同一天,处理跨天的重叠部分
        if (!startTime.toLocalDate().equals(endTime.toLocalDate())) {
            // 第二天的00:00到结束时间的部分
            LocalDateTime midnight = startTime.toLocalDate().plusDays(1).atStartOfDay();
            totalOverlapMinutes += calculateDayOverlapMinutes(midnight, endTime, rangeStart, rangeEnd, isRangeCrossMidnight);
        }

        return totalOverlapMinutes;
    }

    /**
     * 计算一天内的重叠分钟数
     * @param startTime
     * @param endTime
     * @param rangeStart
     * @param rangeEnd
     * @param isRangeCrossMidnight
     * @return
     */
    private static long calculateDayOverlapMinutes(LocalDateTime startTime, LocalDateTime endTime, LocalTime rangeStart, LocalTime rangeEnd, boolean isRangeCrossMidnight) {
        // 获取开始时间和结束时间的本地时间部分
        LocalTime startTimeOfDay = startTime.toLocalTime();
        LocalTime endTimeOfDay = endTime.toLocalTime();

        if (isRangeCrossMidnight) {
            // 如果时间范围跨越午夜,将时间范围分成两部分处理
            long overlapMinutes1 = calculateOverlap(startTimeOfDay, endTimeOfDay, rangeStart, LocalTime.MAX);
            long overlapMinutes2 = calculateOverlap(startTimeOfDay, endTimeOfDay, LocalTime.MIN, rangeEnd);
            return overlapMinutes1 + overlapMinutes2;
        } else {
            // 非跨天的正常重叠计算
            return calculateOverlap(startTimeOfDay, endTimeOfDay, rangeStart, rangeEnd);
        }
    }

    // 计算两个时间段的重叠部分
    private static long calculateOverlap(LocalTime start1, LocalTime end1, LocalTime start2, LocalTime end2) {
        LocalTime effectiveStart = start1.isAfter(start2) ? start1 : start2;
        LocalTime effectiveEnd = end1.isBefore(end2) ? end1 : end2;

        if (effectiveStart.isBefore(effectiveEnd)) {
            return Duration.between(effectiveStart, effectiveEnd).toMinutes();
        }
        return 0;
    }

    public static void main(String[] args) {


        // 假设谷段的时间范围格式:"01:30,04:30"
        String timeRange = "01:30,04:30";

        // 输入的开始时间和结束时间
        String inputStartTime = "2024-09-02 02:00:00";
        String inputEndTime = "2024-09-02 04:00:00";

        int overlapMinutes = calculateOverlapMinutes(inputStartTime, inputEndTime, timeRange);
        System.out.println("测试1 中部分重叠的分钟数: " + overlapMinutes);


        // 输入的开始时间和结束时间
         inputStartTime = "2024-09-01 23:00:00";
         inputEndTime = "2024-09-02 01:40:00";

         overlapMinutes = calculateOverlapMinutes(inputStartTime, inputEndTime, timeRange);
        System.out.println("测试2 跨天之前半部分重叠的分钟数: " + overlapMinutes);


        // 输入的开始时间和结束时间
        inputStartTime = "2024-09-02 04:10:00";
        inputEndTime = "2024-09-02 05:30:00";

        overlapMinutes = calculateOverlapMinutes(inputStartTime, inputEndTime, timeRange);
        System.out.println("测试3 后半部分重叠的分钟数: " + overlapMinutes);


        // 输入的开始时间和结束时间
        inputStartTime = "2024-09-01 23:10:00";
        inputEndTime = "2024-09-02 05:30:00";

        overlapMinutes = calculateOverlapMinutes(inputStartTime, inputEndTime, timeRange);
        System.out.println("测试4 跨天包含重叠的分钟数: " + overlapMinutes);

    }


}

代码解释:

  1. calculateOverlapMinutes 方法用于计算两个时间段的重叠部分(以分钟为单位)。它接收三个参数:

    • startTime:开始时间
    • endTime:结束时间
    • timeRange:时间范围的字符串,格式为“HH:mm”。
  2. 解析时间范围并确定在时间段内是否有重叠。如果有重叠,计算重叠部分的分钟数返回。

执行测试结果正确,如下图:

把上面测试代码再封装成一个工具类即可计算出充电时长所在区域范围的时间分钟,也可以方便实现以上业务逻辑了。

三 小结

        通过软件扩展代替硬件升级,项目在时间紧迫的情况下实现了需求,降低了实施风险,并保障了业主与客户的权益。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2161325.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【CoppeliaSim V4.7】The Python interpreter could not handle the wrapper script

[sandboxScript:error] The Python interpreter could not handle the wrapper script (or communication between the launched subprocess and CoppeliaSim could not be established via sockets). Make sure that the Python modules ‘cbor2’ and ‘zmq’ are properly i…

Spring MVC 基本配置步骤 总结

1.简介 本文记录Spring MVC基本项目拉起配置步骤。 2.步骤 在pom.xml中导入依赖&#xff1a; <dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>6.0.6</version><scope>…

关于javascript中防抖和节流的使用详解

防抖&#xff08;Debounce&#xff09;和节流&#xff08;Throttle&#xff09;是两种常见的优化技巧&#xff0c;通常用于控制函数在短时间内频繁触发的场景&#xff0c;尤其是在处理用户输入、滚动、窗口大小调整等事件时。它们的主要目的是减少不必要的函数调用&#xff0c;…

想把泰文从文本上识别,什么软件工具好用呢?

泰文识别技术涉及将泰文图像转换成数字文本&#xff0c;主要通过光学字符识别&#xff08;OCR&#xff09;技术实现。这项技术广泛应用于文档处理、语言学习和翻译服务。实现泰文识别的方法包括使用手机应用程序、在线服务、专业软件&#xff0c;以及结合人工智能和机器学习。此…

UE5 C++: 插件编写04 | 自动增加前缀

准备工作 UObject* Asset UObject* Asset 通常指的是一个指向UObject的指针。UObject是Unreal Engine中的基类&#xff0c;几乎所有的引擎对象都继承自UObject。这个指针可以引用任何派生自UObject的对象&#xff0c;比如蓝图、材质、贴图、音频资源等资产。 如果你看到UObj…

【C++】——set和map的使用

文章目录 set的特性set初始化set迭代器和常见成员函数multisetmap的特性map初始化map迭代器和常见成员函数insert[]运算符重载multimap set的特性 自动排序&#xff1a; set中的元素会默认排升序存储唯一性&#xff1a; set中每个元素都是唯一的&#xff0c;如果插入一个已有元…

如何找到实力突出的建站公司,2024网络建站公司推荐

选择网站建设公司需要考虑公司以下几点&#xff1a; 是否对的业务需求的了解程度如何&#xff1f; 与公司的文化契合度 相同企业文化的公司&#xff0c;往往能取得很好的合作 沟通的方式 考虑&#xff1a;谁将是解决疑虑、查询、反馈的联系人&#xff0c;查询的响应时间是…

ShiroFilterFactoryBean登录认证成功后没有正常跳转到successUrl问题解决

问题出现&#xff1a; 分析&#xff1a;在配置了ShiroFilter之后&#xff0c;直接尝试在页面端访问login.jsp,但是login.jsp需要做认证过滤也就是FormAuthenticationFilter。 应为没有登录信息所以可想而知&#xff0c;会走ShiroFilterFactoryBean定义的loginUrl也就是认定为没…

VBA技术资料MF202:添加右键多按钮弹出菜单

我给VBA的定义&#xff1a;VBA是个人小型自动化处理的有效工具。利用好了&#xff0c;可以大大提高自己的工作效率&#xff0c;而且可以提高数据的准确度。“VBA语言専攻”提供的教程一共九套&#xff0c;分为初级、中级、高级三大部分&#xff0c;教程是对VBA的系统讲解&#…

使用PLSQL Developer快速连接数据库

文章目录 前言一、定义设置方式二、固定用户设置方式三、连接设置方式总结前言 PLSQL Developer是一个集成开发环境,由Allround Automations公司开发,专门面向Oracle数据库存储的程序单元的开发。该工具提供了多种设置方式,便于使用者在不需要输入用户名称、密码的情况下,…

易航网址导航系统V2.45完美去授权版

简介 易航网址导航系统V2.45完美去授权版 界面

2024 年 CSS 终于增加了垂直居中特性,效率翻倍!

在 2024 年的Chrome 123 版本中&#xff0c; CSS 原生可以使用 1 个 CSS 属性 align-content: center进行垂直居中。 有何魅力&#xff1f; 这个特性的魅力在哪儿呢&#xff1f;我举例给你看一下 <div style"align-content:center; height:200px; background: #614e…

18722 稀疏矩阵的运算

思路&#xff1a; 快速转置算法的基本思想是预先计算出转置后的三元组在新数组中的位置&#xff0c;然后直接将元素放到对应的位置上。这样做的好处是只需要遍历一次原数组&#xff0c;就可以完成转置操作。 步骤如下&#xff1a; 1. 初始化一个新的三元组数组&#xff0c;用于…

数据库性能监控如何做?简单3步实现慢SQL、长事务监控!

1.背景说明 对于使用关系型数据库的系统而言&#xff0c;在系统投产上线后&#xff0c;及时发现程序运行中的慢SQL语句&#xff0c;能有效降低系统运行风险&#xff1b;对于分布式应用系统来说&#xff0c;在系统日常运行中&#xff0c;为避免因数据库长事务导致主备切换风险&…

2024年 AI大模型我该买一张什么卡?

有钱啥也不用说&#xff0c;买张最贵的就是了。对囊中羞涩的我还说&#xff0c;我该买张什么样的显卡呢&#xff1f; 我的旧显卡RTX1060 6G&#xff0c;满负荷消耗功率110多瓦&#xff0c;几乎达到设计最大TDP&#xff0c;周日时拿了朋友的RTX3060Ti 8G&#xff0c;发现是锁算…

免费与付费代理IP工具的优缺点分析

面对市场上众多的代理IP工具&#xff0c;选择合适的工具成为一项挑战。本文将深入分析免费与付费代理IP工具的优缺点&#xff0c;协助您做出明智的选择。 一、免费代理IP工具的优缺点 优点&#xff1a; 零成本&#xff1a;最大的优点在于无需任何费用。对于预算有限的用户&a…

【资源一号02C卫星】

资源一号02C卫星 资源一号02C卫星是中国航天科技集团公司所属中国空间技术研究院负责研制生产的一颗重要遥感卫星。以下是关于该卫星的详细介绍&#xff1a; 一、基本信息 发射时间&#xff1a;2011年12月22日11时26分发射地点&#xff1a;中国太原卫星发射中心运载火箭&am…

加载数据模型:在数据采集中实现动态数据处理

介绍 在现代网络爬虫技术中&#xff0c;数据的动态处理成为了提升采集效率和准确性的重要手段。随着目标网站数据的多样性和复杂性增加&#xff0c;静态数据采集方法逐渐无法满足需求。本文以拼多多为例&#xff0c;探讨如何通过加载数据模型实现动态数据处理&#xff0c;并结…

【大模型-驯化】成功搞懂大模型的jsonl数据格式处理和写入,通过pandas读取和保存JSONL文件

【大模型-驯化】成功搞懂大模型的jsonl数据格式处理和写入&#xff0c;通过pandas读取和保存JSONL文件 本次修炼方法请往下查看 &#x1f308; 欢迎莅临我的个人主页 &#x1f448;这里是我工作、学习、实践 IT领域、真诚分享 踩坑集合&#xff0c;智慧小天地&#xff01; &…

文件上传-php

查找方式 ***(1) 黑盒 查找(upload) 扫描 (2) 应用型 窗口 上传中心或者后台中心 上传 Ps:后台是后台 权限是权限 (3) 会员中心 (4) 白盒 基本函数定义 写前端的 Enctype 上传类型Method 提交方式Onsubmit 鼠标的时间Action"放在指定文件"Php 接受表单数据 isset(…