最近碰到一个有趣的需求,花了一天时间写了代码实现。
需求:给汽车充电时,充电桩是会根据充电的时间段的不同来收费的,比如晚上用电高峰,这时充电会贵,凌晨没人用电,电费会便宜。大概就是分为尖、峰、平、谷四个类型,每个类型可能有多个时间段,那么,比如我充电一次,如何计算每个时间段内冲了多久的电呢?

大概逻辑:
1、对多个时间段进行校验,必须首尾相连
2、对时间段进行排序。找到最小的时间作为第一个,然后依照首尾进行排序
3、确定开始时间、结束时间所在的时间段,然后按照顺序遍历即可,中间的时间段就是满的。

需要注意的地方:
1、24小时制,所以总会有一个时间段是 结束时间小于开始时间
2、确定开始时间、结束时间所在的时间段时。例如开始时间8:00,那么它所属时间段应该是8:00-10:00,而不是6:00-8:00 ,同样,结束时间是8:00,那么它所属时间段应该是6:00-8:00,而不是8:00-10:00

代码如下:


import java.time.Duration;
import java.time.LocalTime;
import java.util.*;/*** @author hph* @date 2022-11-14  10:52*/
public class TimeSpanCalculateTest {public static void main(String[] args) throws Exception {HashMap<String, String> map = new HashMap<>();map.put("06:00-12:00", "尖");map.put("12:00-16:00", "峰");map.put("16:00-20:30", "平");map.put("20:30-00:00", "峰");map.put("00:00-06:00", "谷");String timeSpan = "00:00-08:10";checkTimeSpan(map);calculateTimeSpan(sortTimeSpan(map), timeSpan);}/*** 检查 时间段 格式是否正确* 1、小时、分钟都是两位 且 小时是0-23,分钟是0-59* 2、首尾相连* 3、共24小时** @param map*/private static void checkTimeSpan(HashMap<String, String> map) throws Exception {System.out.println("######## 开始 校验时间段#########");// 校验格式String regex = "([0-1]+[0-9]|2[0-3]):([0-5][0-9])-([0-1]+[0-9]|2[0-3]):([0-5][0-9])";for (String key : map.keySet()) {String[] tt = key.split("-");if (tt[0].equals(tt[1])) {throw new Exception("开始时间和结束时间不能相同");}if (!key.matches(regex)) {throw new Exception("时间段 格式错误");}}// 校验首尾相连// 以第一个为基准int foundSpan = 0;String span = "";String startSpan = "";String endSpan = "";int index = 0;// 最多循环map.keySet().size()次就能找到所有的// 缺点在于,如果一个时间段一直没找到下一个,还是会循环完,才会退出// 如何 循环一遍就退出整个循环呢// 变量太多,不想再加变量了,太乱for (int i = 0; i < map.keySet().size(); i++) {if (foundSpan == map.keySet().size()) {break;}// 没办法,还是加个变量吧int temp = 0 ;for (String value : map.keySet()) {String[] tt = value.split("-");// 第一次if (index == 0) {span = tt[1];startSpan = tt[0];foundSpan++;index++;}// 找到下一个时间段if (span.equals(tt[0])) {foundSpan++;span = tt[1];// 最后一次if (foundSpan == map.keySet().size()) {endSpan = tt[1];}temp++;continue;}}// 如果 一次循环,temp没有增加,那么就退出,不用再循环了if(temp == 0){break;}}if (foundSpan == map.keySet().size() && startSpan.equals(endSpan)) {System.out.println("######## 时间段 首尾相连#########");} else {System.err.println(String.format("找不到 %s 或 %s 的下一个时间段",span,startSpan));throw new Exception("时间段首尾不相连");}// 校验 是否是 24小时// 按理说 只要首尾相连了,那么肯定是24小时}private static void calculateTimeSpan(TreeMap<String, String> map, String timeSpan) {System.out.println("########开始计算#########");System.out.println("充电时间段:" + timeSpan);String startTime = timeSpan.substring(0, 5);String endTime = timeSpan.substring(6);String startSpan = "";String endSpan = "";for (String key : map.keySet()) {String span = map.get(key);if (isStartTimeInTimeSpan(startTime, span)) {startSpan = key;}if (isEndTimeInTimeSpan(endTime, span)) {endSpan = key;}}System.out.println("开始时间 时间段:" + startSpan);System.out.println("结束时间 时间段:" + endSpan);int totalTime = 0;for (String key : map.keySet()) {String span = map.get(key);int i = Integer.valueOf(key.substring(0, 1));int s = Integer.valueOf(startSpan.substring(0, 1));int e = Integer.valueOf(endSpan.substring(0, 1));// 开始时间 和 结束时间 是同一个时间段if(s == e){int minutes = calculateMinute(startTime, endTime);System.out.println(String.format("没有跨段 , 所属时间段:key: %s %s , 耗时(分钟):%s", startSpan, map.get(startSpan), minutes));totalTime += minutes;break;}if (i == s) {int minutes = calculateMinute(startTime, span.substring(6));System.out.println(String.format("开始时间:%s  时间段:key: %s %s , 耗时(分钟):%s", startTime, key, span, minutes));totalTime += minutes;}if (i == e) {int minutes = calculateMinute(span.substring(0, 5), endTime);System.out.println(String.format("结束时间:%s  时间段:key: %s %s , 耗时(分钟):%s", endTime, key, span, minutes));totalTime += minutes;}if (i > s && i < e) {int minutes = calculateMinute(span.substring(0, 5), span.substring(6));System.out.println(String.format("中间时间  时间段:key: %s %s , 耗时(分钟):%s", key, span, minutes));totalTime += minutes;}if (i < s || i > e) {continue;}}System.out.println("共用时:" + totalTime);}/*** 计算时间 段内的 分钟数** @param s* @param e* @return*/private static int calculateMinute(String s, String e) {int time1 = Integer.valueOf(s.substring(0, 2)) * 60 + Integer.valueOf(s.substring(3));int time2 = Integer.valueOf(e.substring(0, 2)) * 60 + Integer.valueOf(e.substring(3));if (time1 < time2) {return time2 - time1;} else {// 例如 23:00  到  01:00return 24 * 60 + time2 - time1;}}/*** 判断开始时间 是否在 某个时间段内** @param t* @param span* @return*/private static boolean isStartTimeInTimeSpan(String t, String span) {int time = Integer.valueOf(t.substring(0, 2)) * 60 + Integer.valueOf(t.substring(3));int time1 = Integer.valueOf(span.substring(0, 2)) * 60 + Integer.valueOf(span.substring(3, 5));int time2 = Integer.valueOf(span.substring(6, 8)) * 60 + Integer.valueOf(span.substring(9));if (time1 < time2) {// 例如 开始时间 8:00   时间段 8:00 - 12:00if (time >= time1 && time < time2) {return true;} else {return false;}} else {// 时间段 23:00 - 2:00   则只需判断开始时间大于 time1即可if (time >= time1 || time < time2) {return true;} else {return false;}}}/*** 判断结束时间 是否在 某个时间段内** @param t* @param span* @return*/private static boolean isEndTimeInTimeSpan(String t, String span) {int time = Integer.valueOf(t.substring(0, 2)) * 60 + Integer.valueOf(t.substring(3));int time1 = Integer.valueOf(span.substring(0, 2)) * 60 + Integer.valueOf(span.substring(3, 5));int time2 = Integer.valueOf(span.substring(6, 8)) * 60 + Integer.valueOf(span.substring(9));if (time1 < time2) {// 例如 结束时间 8:00   时间段 2:00 - 8:00if (time > time1 && time <= time2) {return true;} else {return false;}} else {// 时间段 23:00 - 2:00   则只需判断开始时间大于 time1即可if (time > time1 || time <= time2) {return true;} else {return false;}}}/*** 把时间段排序** @param map* @return*/private static TreeMap<String, String> sortTimeSpan(Map<String, String> map) {System.out.println("########开始排序#########");String minTime = "30";for (String key : map.keySet()) {String[] tt = key.split("-");if (minTime.compareTo(tt[0]) > 0) {minTime = tt[0];}}System.out.println(String.format("最小的开始时间:%s", minTime));TreeMap<String, String> map1 = new TreeMap<String, String>(new Comparator<String>() {public int compare(String a, String b) {return a.compareTo(b);}});int index = 0;// 最开始用的while true ,但是万一不首尾相连,就会找不到,所以改为for,万一找不到,最多循环map次,for (String test : map.keySet()) {if (map1.size() == map.size()) {break;} else {for (String key : map.keySet()) {String value = map.get(key);if (key.startsWith(minTime)) {map1.put(index + "-" + value, key);minTime = key.substring(6);index++;}}}}System.out.println("########排序后的结果#########");map1.keySet().stream().sorted();for (String key : map1.keySet()) {System.out.println(String.format("key: %s   value : %s", key, map1.get(key)));}return map1;}}

结果:

######## 开始 校验时间段#########
######## 时间段 首尾相连#########
########开始排序#########
最小的开始时间:00:00
########排序后的结果#########
key: 0-谷   value : 00:00-06:00
key: 1-尖   value : 06:00-12:00
key: 2-峰   value : 12:00-16:00
key: 3-平   value : 16:00-20:30
key: 4-峰   value : 20:30-00:00
########开始计算#########
充电时间段:06:00-21:08
开始时间 时间段:1-尖
结束时间 时间段:4-峰
开始时间:06:00  时间段:key: 1-尖 06:00-12:00 , 耗时(分钟):360
中间时间  时间段:key: 2-峰 12:00-16:00 , 耗时(分钟):240
中间时间  时间段:key: 3-平 16:00-20:30 , 耗时(分钟):270
结束时间:21:08  时间段:key: 4-峰 20:30-00:00 , 耗时(分钟):38
共用时:908

总结:
1、已经很注意变量的命名了,可是有些变量真的不知道该怎么命名,比如tt
2、感觉算法还有很大提升空间,但这是我目前能想到的比较靠谱的了
3、代码太多if else,要是用python应该能好很多,java就这点不好
4、定义了太多变量,容易乱,比如校验首尾相连的时候,没有什么好的办法

有没有大佬能指教下?

java 计算某个时间段在多个时间段中分别用时相关推荐

  1. java 计算股票高低点_[转载]股市中常用的一些计算高低点的计算方法

    朋友们观看股评文章时,常常发现那些专家或准专家发出股价在上涨到某某价位会遇到阻力或股价在下跌途中在某一价位会遇到有效支撑的判断,而股价也真的会在这一价位附近掉头向下(上涨途中)或横盘盘整.或下跌途中的 ...

  2. Java计算两个时间段内的工作日天数

    一般在OA系统中都会遇到计算员工这段时间内的工作天数. 这种有两种方式可以解决:一是调用第三方服务接口进行计算,二是自己在系统中写代码计算. 一的好处就是每年的节假日不用自己去维护直接用两个时间段就可 ...

  3. java 计算有效时长,有一时间段不计算时长

    java 计算有效时长,有一时间段不计算时长 计算时效性 计算 2020-08-07 10:10:23 到 2020-08-08 22:10:23 时间段内有多少小时,每天的01:00:00至06:0 ...

  4. Java 计算一段时间段内除去周六日、节假日的工作日数———超详细(全)

    Java 计算一段时间段内除去周六日.节假日的工作日数'' 1.前端界面简介 2.后台处理代码 3.注: <END> 实现功能提要: 本文章记录的是某段时间的起止时间段内的工作日,既是除去 ...

  5. js中计算一个时间点加上一个时间段后的时间

    在实际的项目中,我们常常有这样的需求,计算某个时间点加上某个时间段后(几天几小时几分钟)的时间.如: 2016-04-05 09:29:15 要加上2天4小时5分钟后的时间: 即:2016-04-07 ...

  6. Java计算两个字符串日期之间的天数差

    Java计算两个字符串日期之间的天数差 调用方法: public static void main(String[] args) throws ParseException {String a = & ...

  7. 炒股Java_基于java计算买卖股票的最佳时机

    这篇文章主要介绍了基于java计算买卖股票的最佳时机,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 问题: 可以将问题转化为如下图所示,即求多个累计 ...

  8. java中日期计算时间差,用java计算日期/时间差

    用java计算日期/时间差 我也想计算两个日期之间的差额以小时/分钟/秒为单位. 我的代码有一个小问题,就是:String dateStart = "11/03/14 09:29:58&qu ...

  9. java如何计算时间天数差,java计算两个时间相差天数的方法汇总

    问题描述: 输入:两个日期 输出:两个日期相差的天数 具体代码实现 方法1: 通过calendar类的日期比较.注意:这里需要考虑一下: 日期是跨年份的,如一个是2012年,一个是2015年的 年份是 ...

  10. Java计算时间差、日期差总结(亲测)

    Java计算时间差.日期差总结 最近工作中遇到需要计算时间差,搜索了几种计算时间差的方法,这里总结一下 1.java 7中的日历类Calendar Calendar类使用其静态的getInstance ...

最新文章

  1. linux字符界面教程,打造字符界面的多媒体Linux系统
  2. 同样都是调参,为什么人家的神经网络比我牛逼100倍?
  3. oracle 11g ocfs,Oracle 将不再提供ASMlib和OCFS2软件和支持给红帽 RedHat 6的新发行版
  4. map()和zip()操作
  5. 1032 挖掘机技术哪家强 (20分)——15行代码AC
  6. maven项目中测试代码
  7. SAP UI5不支持delta render
  8. Python中的null类型
  9. 微信小程序富文本组件mp-html
  10. 关于序列化的 10 几个问题,你肯定不知道
  11. Dynamics CRM2013 业务规则的新建、激活与删除
  12. python凹多边形分割_Unity 凹多边形三角剖分
  13. 苹果手机的计算机怎么设置快捷键大全,教程方法;苹果电脑快捷键大全最常用的都在这里了电脑技巧-琪琪词资源网...
  14. 高品质的3D建模和渲染软件——3Dmax!小白须知!
  15. cmake:pkg_check_modules
  16. 安卓中的hander
  17. ACRush 楼天成 回忆录
  18. 从中国制造到中国智造,打通工业互联网的任督二脉
  19. 电商新手做亚马逊要怎样开始?
  20. 实时频谱-3.1实时频谱分析仪测量

热门文章

  1. java中list删除元素_java中,删除一个List中的后n个元素
  2. 关于远心镜头的基础知识
  3. cdn加速以及前后分离SpringBoot+Vue 配置https及SSL证书
  4. 锐速ServerCheck序列号生成原理
  5. Windows解锁网易云音乐客户端变灰歌曲
  6. C#实现格式转换:wmf转png
  7. 构建基于词典的Lucene分类器
  8. obj文件格式与mtl文件格式
  9. 手机录音如何转换成文字?学会这个简单方法,让你事半功倍!
  10. java关于hashmap编程题_在Java中,关于HashMap类的描述,以下说法错误的是( )。...