java 计算某个时间段在多个时间段中分别用时

本文介绍了一个根据时间段不同收费的充电桩计费算法实现。通过校验和排序时间段,确定充电开始和结束时间所在时间段,然后计算每个时间段的充电时长。代码中包括对时间段的合法性检查、排序和计算充电总时长的逻辑。该算法适用于24小时制,处理了时间段首尾不相连的情况。
摘要由CSDN通过智能技术生成

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

大概逻辑:
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:00
            return 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:00
            if (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:00
            if (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、定义了太多变量,容易乱,比如校验首尾相连的时候,没有什么好的办法

有没有大佬能指教下?

  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
这段代码是一个 Java GUI 程序,主要实现了一个基于 Swing 框架的小游戏,游戏的目标是用户需要在规定的时间内将显示在标签上的字符重新排列组合成正确的单词,并在文本框输入答案。如果用户输入的答案正确,程序会弹出一个对话框提示用户答案正确,否则提示用户答案错误。此外,游戏还包含了计时器和计分器,用户需要在规定时间内尽可能多地猜对单词,游戏结束后会显示用户的得分和用时。 具体实现上,这段代码包含了以下几个方法: 1. `initComponents()`:初始化 GUI 组件,包括标签、文本框、按钮等。 2. `startButtonActionPerformed()`:点击“开始”按钮后触发的事件处理方法,随机生成一个单词并将其打乱,然后在标签上显示出来,同时启用“提交”按钮并禁用“开始”按钮,记录游戏开始时间。 3. `submitButtonActionPerformed()`:点击“提交”按钮后触发的事件处理方法,判断用户输入的答案是否正确,如果正确则弹出提示框并更新得分,否则弹出错误提示框。 4. `checkAnswer()`:判断用户输入的答案是否正确的方法,其用到了 Java 的字符串比较方法 `equals()`。 5. `main()`:程序的入口方法,创建了一个 `WordGame` 对象并显示出来。 在实现过程,涉及到的知识点包括 Java Swing GUI 编程、字符串操作、随机数生成、时间处理等。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值