使用Java的Calendar类计算两段时间之间的工作日的天/小时/分钟/秒数

计算两段时间之间的工作日的天/小时/分钟/秒数

我们能经常遇到一些需求,让获取工作日的时间(当然,调休也上班也是工作日哈!),之前自己给这搞得头大,所以整理总结,把该工具类记录下来,希望大家能用到的时候可以直接使用!

在该工具类中主要用到了 java.util 包下的Calendar 这个日期类

大致实现原理:

  • 首先我们需要使用两个List将一年的工作日和非工作日的日期存起来,以便后面的判断。
    • (SPECIAL_WORK_DAYS)特别的工作日(周六,周日上班的日期集合)
    • (SPECIAL_OFF_DAYS)特别的休息日(周一到周五休息的日期集合)
  • 其次,定义一个变量,代表工作日的天数(若日期是yy-MM-dd格式的,Integer类型就可以,如果是yy-MM-dd HH:mm:ss格式的,想更精确的,则定义成Double类型即可)。
    • workDaysNum (工作日天或小时)
  • 其次,获取两个时间段,进行循环比较,判断距现在较远的日期是否是非工作日。(开始时间–startTime,结束时间–endTime)
动手搞起来

新建CalcWorkDaysUtil.java类

方案一:

计算 时间格式为(yy-MM-dd) 的两时间段工作日天数的 完整代码:

/**
 * @Title: 计算时间周期之间工作日的时间
 * @Author: Sophia
 * #Description: CalcWorkDaysUtil
 * #Date: 2022/6/2 14:42
 */
public class CalcWorkDaysUtil {
    // 定义2个List用于存储特殊的工作日和非工作日
    // 特别的工作日(周六,周日上班的日期集合)
    private static List<String> SPECIAL_WORK_DAYS = new ArrayList<>();

    // 特别的休息日(周一到周五休息的日期集合)
    private static List<String> SPECIAL_OFF_DAYS = new ArrayList<>();

    // 在这里我就使用静态将2022年所有的节假日存到相应的list中
    // 大多是都是从数据库中获取的(这里就这样演示,大家后期可以从数据库获取)
    static {
        // 特殊的工作日(周六,周日上班的日期集合)
        SPECIAL_WORK_DAYS.add("2022-01-29");
        SPECIAL_WORK_DAYS.add("2022-01-30");
        SPECIAL_WORK_DAYS.add("2022-04-02");
        SPECIAL_WORK_DAYS.add("2022-04-24");
        SPECIAL_WORK_DAYS.add("2022-05-07");
        SPECIAL_WORK_DAYS.add("2022-10-08");
        SPECIAL_WORK_DAYS.add("2022-10-09");

        // 特殊的休息日(周一到周五休息的日期集合)
        SPECIAL_OFF_DAYS.add("2022-01-01");
        SPECIAL_OFF_DAYS.add("2022-01-02");
        SPECIAL_OFF_DAYS.add("2022-01-03");
        SPECIAL_OFF_DAYS.add("2022-01-31");
        SPECIAL_OFF_DAYS.add("2022-02-01");
        SPECIAL_OFF_DAYS.add("2022-02-02");
        SPECIAL_OFF_DAYS.add("2022-02-03");
        SPECIAL_OFF_DAYS.add("2022-02-04");
        SPECIAL_OFF_DAYS.add("2022-02-05");
        SPECIAL_OFF_DAYS.add("2022-02-06");
        SPECIAL_OFF_DAYS.add("2022-04-03");
        SPECIAL_OFF_DAYS.add("2022-04-04");
        SPECIAL_OFF_DAYS.add("2022-04-05");
        SPECIAL_OFF_DAYS.add("2022-04-30");
        SPECIAL_OFF_DAYS.add("2022-05-01");
        SPECIAL_OFF_DAYS.add("2022-05-02");
        SPECIAL_OFF_DAYS.add("2022-05-03");
        SPECIAL_OFF_DAYS.add("2022-05-04");
        SPECIAL_OFF_DAYS.add("2022-06-03");
        SPECIAL_OFF_DAYS.add("2022-06-04");
        SPECIAL_OFF_DAYS.add("2022-06-05");
        SPECIAL_OFF_DAYS.add("2022-09-10");
        SPECIAL_OFF_DAYS.add("2022-09-11");
        SPECIAL_OFF_DAYS.add("2022-09-12");
        SPECIAL_OFF_DAYS.add("2022-10-01");
        SPECIAL_OFF_DAYS.add("2022-10-01");
        SPECIAL_OFF_DAYS.add("2022-10-02");
        SPECIAL_OFF_DAYS.add("2022-10-03");
        SPECIAL_OFF_DAYS.add("2022-10-04");
        SPECIAL_OFF_DAYS.add("2022-10-05");
        SPECIAL_OFF_DAYS.add("2022-10-06");
        SPECIAL_OFF_DAYS.add("2022-10-07");
    }

    // 日期格式化方法(非线程安全的,可根据情况在方法内使用,或使用DateTimeFormatter)
    private static SimpleDateFormat SDF = new SimpleDateFormat("yyyy-MM-dd");
	/**
     * 计算两时间段的工作日的天数
     * @param startTimeStr 开始时间
     * @param endTimeStr 结束时间
     * @return
     */
    private static Integer getWorkDaysNum(String startTimeStr, String endTimeStr) {
        // 准备工作
        // 定义Integer类型的工作日天数标识 (注:如果精确小时、分、秒,可用double)
        Integer workDaysNum = 0; // 默认0天

        // 获取两个日期对象
        Calendar cale1 = Calendar.getInstance();
        Calendar cale2 = Calendar.getInstance();

        // 将开始时间和结束时间转换成Date类型并设置到日历中
        try {
            // 格式转换
            Date startDate = SDF.parse(startTimeStr);
            Date endDate = SDF.parse(endTimeStr);
            // 设置到日历
            cale1.setTime(startDate);
            cale2.setTime(endDate);
        } catch (ParseException e) {
            System.out.println("日期转换异常,请检查日期格式!");
            e.printStackTrace();
        }

        // 准备工作已准备完毕
        // 当开始时间小于等于结束时间时,进行循环判断
        while (cale1.compareTo(cale2) <= 0) {
            // 如果cale1不是周六日, workDaysNum则加一天
            // 周日 --> 1,周一 --> 2,周二 --> 3,周三 --> 4,周四 --> 5,周五 --> 6,周六 --> 7
            if (cale1.get(Calendar.DAY_OF_WEEK) != 7 && cale1.get(Calendar.DAY_OF_WEEK) != 1) {
                // 不是周六日,workDaysNum + 1
                workDaysNum++;

                // 判断是不是特殊的休息日(周一到周五休息的日期)
                //如果不是周六日,判断该日是否属于国家法定节假日或特殊放假日,是 workDaysNum - 1
                if (SPECIAL_OFF_DAYS.contains(SDF.format(cale1.getTime()))) {
                    // 是,则 - 1
                    workDaysNum--;
                }
            }
            // 如果改日是周六日,则判断改日是否是特别的工作日(周六,周日上班的日期)
            if (SPECIAL_WORK_DAYS.contains(SDF.format(cale1.getTime()))) {
                // 如果是改日是特殊的工作日,则 + 1
                workDaysNum++;
            }
            // 将时间向后设置一天继续判断
            cale1.add(Calendar.DAY_OF_MONTH, 1);
        }
        // 循环结束,将这两时间段的工作日返回出去
        return workDaysNum;
    }

    public static void main(String[] args) {
        String startTimeStr = "2022-05-20";
        String endTimeStr = "2022-06-09";
        Integer workDaysNum = getWorkDaysNum(startTimeStr, endTimeStr);
        System.out.println(startTimeStr + " 到 " + endTimeStr + " 之间的工作日为:" + workDaysNum + "天");
    }
}
方案二:

计算 时间格式为(yy-MM-dd HH:mm:ss) 的两时间段工作日的天/小时/分钟/秒数的 完整代码:

package fit.clover.blog.util;

import org.apache.commons.lang3.StringUtils;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

/**
 * @Title: 计算时间周期之间工作日的时间
 * @Author: Sophia
 * #Description: CalcWorkDaysUtil
 * #Date: 2022/6/2 14:42
 */
public class CalcWorkDaysUtil {
    // 定义2个List用于存储特殊的工作日和非工作日
    // 特别的工作日(周六,周日上班的日期集合)
    private static List<String> SPECIAL_WORK_DAYS = new ArrayList<>();

    // 特别的休息日(周一到周五休息的日期集合)
    private static List<String> SPECIAL_OFF_DAYS = new ArrayList<>();

    // 在这里我就使用静态将2022年所有的节假日存到相应的list中
    // 大多是都是从数据库中获取的(这里就这样演示,大家后期可以从数据库获取)
    static {
        // 特殊的工作日(周六,周日上班的日期集合)
        SPECIAL_WORK_DAYS.add("2022-01-29");
        SPECIAL_WORK_DAYS.add("2022-01-30");
        SPECIAL_WORK_DAYS.add("2022-04-02");
        SPECIAL_WORK_DAYS.add("2022-04-24");
        SPECIAL_WORK_DAYS.add("2022-05-07");
        SPECIAL_WORK_DAYS.add("2022-10-08");
        SPECIAL_WORK_DAYS.add("2022-10-09");

        // 特殊的休息日(周一到周五休息的日期集合)
        SPECIAL_OFF_DAYS.add("2022-01-01");
        SPECIAL_OFF_DAYS.add("2022-01-02");
        SPECIAL_OFF_DAYS.add("2022-01-03");
        SPECIAL_OFF_DAYS.add("2022-01-31");
        SPECIAL_OFF_DAYS.add("2022-02-01");
        SPECIAL_OFF_DAYS.add("2022-02-02");
        SPECIAL_OFF_DAYS.add("2022-02-03");
        SPECIAL_OFF_DAYS.add("2022-02-04");
        SPECIAL_OFF_DAYS.add("2022-02-05");
        SPECIAL_OFF_DAYS.add("2022-02-06");
        SPECIAL_OFF_DAYS.add("2022-04-03");
        SPECIAL_OFF_DAYS.add("2022-04-04");
        SPECIAL_OFF_DAYS.add("2022-04-05");
        SPECIAL_OFF_DAYS.add("2022-04-30");
        SPECIAL_OFF_DAYS.add("2022-05-01");
        SPECIAL_OFF_DAYS.add("2022-05-02");
        SPECIAL_OFF_DAYS.add("2022-05-03");
        SPECIAL_OFF_DAYS.add("2022-05-04");
        SPECIAL_OFF_DAYS.add("2022-06-03");
        SPECIAL_OFF_DAYS.add("2022-06-04");
        SPECIAL_OFF_DAYS.add("2022-06-05");
        SPECIAL_OFF_DAYS.add("2022-09-10");
        SPECIAL_OFF_DAYS.add("2022-09-11");
        SPECIAL_OFF_DAYS.add("2022-09-12");
        SPECIAL_OFF_DAYS.add("2022-10-01");
        SPECIAL_OFF_DAYS.add("2022-10-01");
        SPECIAL_OFF_DAYS.add("2022-10-02");
        SPECIAL_OFF_DAYS.add("2022-10-03");
        SPECIAL_OFF_DAYS.add("2022-10-04");
        SPECIAL_OFF_DAYS.add("2022-10-05");
        SPECIAL_OFF_DAYS.add("2022-10-06");
        SPECIAL_OFF_DAYS.add("2022-10-07");
    }

    // 日期格式化方法(非线程安全的,可根据情况在方法内使用,或使用DateTimeFormatter)
    private static SimpleDateFormat SDF = new SimpleDateFormat("yyyy-MM-dd");

    private static SimpleDateFormat SDFS = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    /**
     * 计算两时间段的工作日的天/小时/分钟/秒数
     * @param startTimeStr 开始时间
     * @param endTimeStr 结束时间
     * @param flag d为天,h为小时,m为分钟,s为秒
     * @return
     */
    private static Double getWorkDaysNum(String startTimeStr, String endTimeStr, String flag) {
        // 准备工作
        // 定义Long类型的工作日天数标识 (注:如果精确小时、分、秒,可用double)
        Long workDaysNum = 0l; // 默认0秒
        // 定义Double类型的工作日秒数标识
        Double workDaysSecond = 0d; // 默认0秒

        // 获取两个日期对象
        Calendar cale1 = Calendar.getInstance();
        Calendar cale2 = Calendar.getInstance();

        // 将开始时间和结束时间转换成Date类型并设置到日历中
        try {
            // 设置到日历
            cale1.setTime(SDF.parse(startTimeStr));
            cale2.setTime(SDF.parse(endTimeStr));
            // 格式转换
            Date startDate = SDFS.parse(startTimeStr);
            Date endDate = SDFS.parse(endTimeStr);

            // 设置时间开始区间的0时,如startDateStr 为2022-05-10 10:00:00, 则距2022-05-10 0:00:00点为10个小时,也是600分钟,也是36000秒
            startTimeStr = StringUtils.substringBeforeLast(startTimeStr, " ") + " 00:00:00";
            // 设置时间结束区间的24时,如endTimeStr 为2022-06-06 12:00:00 则距2022-06-06 23:59:59点为12个小时,也是720分钟,也是43200秒
            endTimeStr = StringUtils.substringBeforeLast(endTimeStr, " ") + " 23:59:59";

            Date startDateZero = SDFS.parse(startTimeStr);
            Date endDateZero = SDFS.parse(endTimeStr);

            // 计算开始区间时间距0时的毫秒值
            long startLong = (startDate.getTime() - startDateZero.getTime());
            // 计算结束区间时间距24时的毫秒值
            long endLong = (endDateZero.getTime() - endDate.getTime());

            // 准备工作已准备完毕
            // 当开始时间小于等于结束时间时,进行循环判断
            while (cale1.compareTo(cale2) <= 0) {
                // 如果cale1不是周六日, workDaysNum则加一天
                // 周日 --> 1,周一 --> 2,周二 --> 3,周三 --> 4,周四 --> 5,周五 --> 6,周六 --> 7
                if (cale1.get(Calendar.DAY_OF_WEEK) != 7 && cale1.get(Calendar.DAY_OF_WEEK) != 1) {
                    // 不是周六日,workDaysNum + 1
                    workDaysNum++;

                    // 判断是不是特殊的休息日(周一到周五休息的日期)
                    //如果不是周六日,判断该日是否属于国家法定节假日或特殊放假日,是 workDaysNum - 1
                    if (SPECIAL_OFF_DAYS.contains(SDF.format(cale1.getTime()))) {
                        // 是,则 - 1
                        workDaysNum--;
                    }
                }
                // 如果改日是周六日,则判断改日是否是特别的工作日(周六,周日上班的日期)
                if (SPECIAL_WORK_DAYS.contains(SDF.format(cale1.getTime()))) {
                    // 如果是改日是特殊的工作日,则 + 1
                    workDaysNum++;
                }
                // 将时间向后设置一天继续判断
                cale1.add(Calendar.DAY_OF_MONTH, 1);
            }
            // 将天转成毫秒值
            workDaysNum = workDaysNum * 86400000; // 一天等于86400000毫秒
            // 天数计算完毕,使用BigDecimal将天数换成秒
            BigDecimal daysNumDec = new BigDecimal(workDaysNum);
            // 将天转换成秒
            BigDecimal tempNum = daysNumDec;// .multiply(secondDec);
            tempNum = tempNum.subtract(new BigDecimal(startLong));
            tempNum = tempNum.subtract(new BigDecimal(endLong));
            if ("d".equals(flag)) {
                // 天
                workDaysSecond = tempNum.divide(new BigDecimal("86400000"), 2, RoundingMode.HALF_UP).doubleValue(); // 24*60*60秒 = 1天
            } else if ("h".equals(flag)) {
                // 小时
                workDaysSecond = tempNum.divide(new BigDecimal("3600000"), 2, RoundingMode.HALF_UP).doubleValue(); // 60*60秒 = 1小时
            } else if ("m".equals(flag)) {
                // 分钟
                workDaysSecond = tempNum.divide(new BigDecimal("60000"), 2, RoundingMode.HALF_UP).doubleValue(); // 60秒 = 1分钟
            } else if ("s".equals(flag)) {
                // 秒
                workDaysSecond = tempNum.divide(new BigDecimal("1000"), 2, RoundingMode.HALF_UP).doubleValue();
            }

        } catch (ParseException e) {
            System.out.println("日期转换异常,请检查日期格式!");
            e.printStackTrace();
        }
        // 循环结束,将这两时间段的工作日返回出去
        return workDaysSecond;
    }

    public static void main(String[] args) {
        String startTimeStr = "2022-06-01 03:00:00";
        String endTimeStr = "2022-06-06 12:00:00";
        Double days = getWorkDaysNum(startTimeStr, endTimeStr, "d");
        Double hour = getWorkDaysNum(startTimeStr, endTimeStr, "h");
        Double min = getWorkDaysNum(startTimeStr, endTimeStr, "m");
        Double second = getWorkDaysNum(startTimeStr, endTimeStr, "s");
        System.out.println(startTimeStr + " 到 " + endTimeStr + " 之间的工作日为:" + days + "天");
        System.out.println(startTimeStr + " 到 " + endTimeStr + " 之间的工作日为:" + hour + "小时");
        System.out.println(startTimeStr + " 到 " + endTimeStr + " 之间的工作日为:" + min + "分钟");
        System.out.println(startTimeStr + " 到 " + endTimeStr + " 之间的工作日为:" + second + "秒");
    }
}

运行结果:
运行结果

总结:当然还是推荐使用方案二的,因为方案二可根据不同的标识获取不同的单位数的!
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

醒省行

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值