说明:
有时候我们在计算时间时,有让获取两时间段重合的天数这种需求,小编也是遇到了这样的需求,就封装了一个工具类
,希望能帮助到大家。
我们先进行分析
求两个时间段重合的天数,例如求(2022-05-02 00:00:00 至 2022-05-12 23:59:59)
时间段和(2022-05-04 00:00:00 至 2022-05-13 05:00:00)
时间段重合(交叉)的天数。
通过我们脑力计算,可获得重合的时间段为 (2022-05-04 00:00:00 至 2022-05-12 23:59:59)
,也就相当于重合天数为9天
。可是这只是一种情况,接下来。我们会对重合(交叉)
的情况进行分析:
两个时间段分别是:(aStart -- aEnd), [bStart -- bEnd] 若不好理解,可认为[bStart -- bEnd]是固定时间段,则是计算[aStart -- aEnd]时间段与[bStart -- bEnd]交叉的天数 两个时间段之间的重合天数,有以下几种情况: 情况一:[bStart -- bEnd]在(aStart -- aEnd)时间段内 if(aStart <= bStart && bEnd <= aEnd) (aStart -- [bStart -- bEnd] -- aEnd) 情况二:(aStart -- aEnd)在[bStart -- bEnd]时间段内 if(bStart <= aStart && aEnd <= bEnd) [bStart -- (aStart -- aEnd) -- bEnd] 情况三:(aStart -- aEnd)部分时间在[bStart -- bEnd]时间段内 if(aStart <= bStart && aEnd <= bEnd) (aStart -- [bStart -- aEnd) -- bEnd] 情况四:(aStart -- aEnd)部分时间在[bStart -- bEnd]时间段内 if(bStart <= aStart && bEnd <= aEnd) [bStart -- (aStart -- bEnd] -- aEnd)
经分析,两时间段能重合(交叉)的情况只有这四种情况,其他不能重合(交叉)的情况我们都默认重合天数为0即可。
经分析,我们可以根据这四种情况
进行着手计算!
开码
首先,我们需要定义一个方法将String类型的时间
格式化成Date
并返回转换成Date的时间戳
(也就是毫秒值
)
/**
* 时间格式化
* @param dateStr String类型时间格式
* @return 该时间的时间戳
*/
public static Long formatDateStr(String dateStr) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date date = null;
try {
date = sdf.parse(dateStr);
} catch (ParseException e) {
e.printStackTrace();
System.out.println("时间格式化错误");
}
return date.getTime();
}
之后,定义一个方法,根据标识(flag)
计算两个long类型的时间戳之间的天/小时/分钟/秒数
。
其中flag标识为时间单位标识
,“d为天,h为小时,m为分钟,s为秒”
。
/**
* 计算两时间之间的时间 天/小时/分钟/秒数
* @param bStartLong 开始时间时间戳
* @param bEndLong 结束时间时间戳
* @param flag 单位标识 d为天,h为小时,m为分钟,s为秒
* @return 两时间之间的时间 天/小时/分钟/秒数
*/
private static Double calcTime(Long bStartLong, Long bEndLong, String flag) {
Double result = 0d;
Long num = (bEndLong - bStartLong); // 毫秒
BigDecimal tempNum = new BigDecimal(num);
if ("d".equals(flag)) {
// 天
result = tempNum.divide(new BigDecimal("86400000"), 2, RoundingMode.HALF_UP).doubleValue(); // 24*60*60秒 = 1天
} else if ("h".equals(flag)) {
// 小时
result = tempNum.divide(new BigDecimal("3600000"), 2, RoundingMode.HALF_UP).doubleValue(); // 60*60秒 = 1小时
} else if ("m".equals(flag)) {
// 分钟
result = tempNum.divide(new BigDecimal("60000"), 2, RoundingMode.HALF_UP).doubleValue(); // 60秒 = 1分钟
} else if ("s".equals(flag)) {
// 秒
result = tempNum.divide(new BigDecimal("1000"), 2, RoundingMode.HALF_UP).doubleValue();
}
return result;
}
最后,对开头分析的四种情况
进行判断即可。
/**
* 获取两时间段的重合时间
* @param aStartStr 时间段1开始时间
* @param aEndStr 时间段1结束时间
* @param bStartStr 时间段2开始时间
* @param bEndStr 时间段2结束时间
* @param flag 单位标识 d为天,h为小时,m为分钟,s为秒
* @return 重合时间 天/小时/分钟/秒数
*/
public static Double getIntersectDays(String aStartStr, String aEndStr, String bStartStr, String bEndStr, String flag) {
// 时间段1
Long aStartLong = formatDateStr(aStartStr);
Long aEndLong = formatDateStr(aEndStr);
// 时间段2
Long bStartLong = formatDateStr(bStartStr);
Long bEndLong = formatDateStr(bEndStr);
Double num = 0d; // 默认重合(相交)为0
// 当符合常规条件时,才进行判断计算
if ((aStartLong < aEndLong) && (bStartLong < bEndLong)) {
// 四种情况判断
if ((aStartLong <= bStartLong) && (bEndLong <= aEndLong)) {
// 情况一:只需要计算[bStart -- bEnd]之间的时间即可
num = calcTime(bStartLong, bEndLong, flag);
} else if ((bStartLong <= aStartLong) && (aEndLong <= bEndLong)) {
// 情况二:只需要计算(aStart -- aEnd)之间的时间即可
num = calcTime(aStartLong, aEndLong, flag);
} else if ((aStartLong <= bStartLong) && (aEndLong <= bEndLong)) {
// 情况三:只需要计算(bStart -- aEnd)之间的时间即可
num = calcTime(bStartLong, aEndLong, flag);
} else if ((bStartLong <= aStartLong) && (bEndLong <= aEndLong)) {
// 情况四:只需要计算(bStart -- aEnd)之间的时间即可
num = calcTime(aStartLong, bEndLong, flag);
} else {
// 其他情况,不相交,或者时间组合不符合 默认0
}
}
return num;
}
最后进行测试:
public static void main(String[] args) {
String aStartStr = "2022-05-02 00:00:00";
String aEndStr = "2022-05-12 23:59:59";
String bStartStr = "2022-05-04 00:00:00";
String bEndStr = "2022-05-13 05:00:00";
Double days = getIntersectDays(aStartStr, aEndStr, bStartStr, bEndStr, "d");
Double hour = getIntersectDays(aStartStr, aEndStr, bStartStr, bEndStr, "h");
Double min = getIntersectDays(aStartStr, aEndStr, bStartStr, bEndStr, "m");
Double second = getIntersectDays(aStartStr, aEndStr, bStartStr, bEndStr, "s");
System.out.println(days + " 天");
System.out.println(hour + " 小时");
System.out.println(min + " 分钟");
System.out.println(second + " 秒");
}
测试结果:
总结:
如果想要计算两时间段的重合的工作日
时间,可参考小编的另一篇博文(使用Java的Calendar类计算两段时间之间的工作日的天/小时/分钟/秒数)进行结合封装接口。
完整代码:
package fit.clover.blog.util;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* @Title: 计算两时间段的重合天数
* @Author: Sophia
* #Description: DateUtil
* #Date: 2022/6/7 09:34
*/
public class CalcIntersectUtil {
/**
* 两个时间段分别是:(aStart -- aEnd), [bStart -- bEnd]
* 若不好理解,可认为[bStart -- bEnd]是固定时间段,则是计算[aStart -- aEnd]时间段与[bStart -- bEnd]交叉的天数
* 两个时间段之间的重合天数,有以下几种情况:
* 情况一:[bStart -- bEnd]在(aStart -- aEnd)时间段内 if(aStart <= bStart && bEnd <= aEnd)
* (aStart -- [bStart -- bEnd] -- aEnd)
* 情况二:(aStart -- aEnd)在[bStart -- bEnd]时间段内 if(bStart <= aStart && aEnd <= bEnd)
* [bStart -- (aStart -- aEnd) -- bEnd]
* 情况三:(aStart -- aEnd)部分时间在[bStart -- bEnd]时间段内 if(aStart <= bStart && aEnd <= bEnd)
* (aStart -- [bStart -- aEnd) -- bEnd]
* 情况四:(aStart -- aEnd)部分时间在[bStart -- bEnd]时间段内 if(bStart <= aStart && bEnd <= aEnd)
* [bStart -- (aStart -- bEnd] -- aEnd)
* 经过分析,两时间段相交有这4中情况,所以我们可以根据这四种情况进行着手计算
*/
/**
* 获取两时间段的重合时间
* @param aStartStr 时间段1开始时间
* @param aEndStr 时间段1结束时间
* @param bStartStr 时间段2开始时间
* @param bEndStr 时间段2结束时间
* @param flag 单位标识 d为天,h为小时,m为分钟,s为秒
* @return 重合时间 天/小时/分钟/秒数
*/
public static Double getIntersectDays(String aStartStr, String aEndStr, String bStartStr, String bEndStr, String flag) {
// 时间段1
Long aStartLong = formatDateStr(aStartStr);
Long aEndLong = formatDateStr(aEndStr);
// 时间段2
Long bStartLong = formatDateStr(bStartStr);
Long bEndLong = formatDateStr(bEndStr);
Double num = 0d; // 默认重合(相交)为0
// 当符合常规条件时,才进行判断计算
if ((aStartLong < aEndLong) && (bStartLong < bEndLong)) {
// 四种情况判断
if ((aStartLong <= bStartLong) && (bEndLong <= aEndLong)) {
// 情况一:只需要计算[bStart -- bEnd]之间的时间即可
num = calcTime(bStartLong, bEndLong, flag);
} else if ((bStartLong <= aStartLong) && (aEndLong <= bEndLong)) {
// 情况二:只需要计算(aStart -- aEnd)之间的时间即可
num = calcTime(aStartLong, aEndLong, flag);
} else if ((aStartLong <= bStartLong) && (aEndLong <= bEndLong)) {
// 情况三:只需要计算(bStart -- aEnd)之间的时间即可
num = calcTime(bStartLong, aEndLong, flag);
} else if ((bStartLong <= aStartLong) && (bEndLong <= aEndLong)) {
// 情况四:只需要计算(bStart -- aEnd)之间的时间即可
num = calcTime(aStartLong, bEndLong, flag);
} else {
// 其他情况,不相交,或者时间组合不符合 默认0
}
}
return num;
}
/**
* 计算两时间之间的时间 天/小时/分钟/秒数
* @param bStartLong 开始时间时间戳
* @param bEndLong 结束时间时间戳
* @param flag 单位标识 d为天,h为小时,m为分钟,s为秒
* @return 两时间之间的时间 天/小时/分钟/秒数
*/
private static Double calcTime(Long bStartLong, Long bEndLong, String flag) {
Double result = 0d;
Long num = (bEndLong - bStartLong); // 毫秒
BigDecimal tempNum = new BigDecimal(num);
if ("d".equals(flag)) {
// 天
result = tempNum.divide(new BigDecimal("86400000"), 2, RoundingMode.HALF_UP).doubleValue(); // 24*60*60秒 = 1天
} else if ("h".equals(flag)) {
// 小时
result = tempNum.divide(new BigDecimal("3600000"), 2, RoundingMode.HALF_UP).doubleValue(); // 60*60秒 = 1小时
} else if ("m".equals(flag)) {
// 分钟
result = tempNum.divide(new BigDecimal("60000"), 2, RoundingMode.HALF_UP).doubleValue(); // 60秒 = 1分钟
} else if ("s".equals(flag)) {
// 秒
result = tempNum.divide(new BigDecimal("1000"), 2, RoundingMode.HALF_UP).doubleValue();
}
return result;
}
/**
* 时间格式化
* @param dateStr String类型时间格式
* @return 该时间的时间戳
*/
public static Long formatDateStr(String dateStr) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date date = null;
try {
date = sdf.parse(dateStr);
} catch (ParseException e) {
e.printStackTrace();
System.out.println("时间格式化错误");
}
return date.getTime();
}
public static void main(String[] args) {
String aStartStr = "2022-05-02 00:00:00";
String aEndStr = "2022-05-12 23:59:59";
String bStartStr = "2022-05-04 00:00:00";
String bEndStr = "2022-05-13 05:00:00";
Double days = getIntersectDays(aStartStr, aEndStr, bStartStr, bEndStr, "d");
Double hour = getIntersectDays(aStartStr, aEndStr, bStartStr, bEndStr, "h");
Double min = getIntersectDays(aStartStr, aEndStr, bStartStr, bEndStr, "m");
Double second = getIntersectDays(aStartStr, aEndStr, bStartStr, bEndStr, "s");
System.out.println(days + " 天");
System.out.println(hour + " 小时");
System.out.println(min + " 分钟");
System.out.println(second + " 秒");
}
}