首先这篇文章不是介绍hutool的DateUtil的between()的api怎么用的文章,想看这个的可以百度其他文章。这篇文章是你在开始使用hutool的DateUtil的between()以及betweenDay()后,发现不太好用,那么可以接着看下去。
计算两个日期时间相差N天、N月、N年.....,一般目前想到的就是用目前流行的工具类库hutool,看下面的api
between():可以设置是否取绝对值(默认是取绝对值),不能设置是否重置(默认不重置)
betweenDay():一系列带单位的方法,必须设置是否重置,不能设置是否取绝对值(默认是取绝对值)
是否已经觉得,在取绝对值和是否重置的时候,想要比较清晰的调用对应的api,是不太容易的。
使用举例:
/**
* 计算两个java.util.Date相差,日期格式:yyyy-MM-dd HH:mm:ss
* between():可以设置是否取绝对值(默认是取绝对值),不能设置是否重置(默认不重置)
* betweenDay():一系列带单位的方法,必须设置是否重置,不能设置是否取绝对值(默认是取绝对值)
* 如果需要重置并且不取绝对值,可以先调用日期时间的 beginOfDay()等相当于重置的方法,再调用between()
*/
@Test
public void between() {
//注意:使用时必须对两个Date进行非空判断,否则会报空指针异常
Date date1 = DateUtil.parse("2017-03-02 23:01:01");
Date date2 = DateUtil.parse("2017-03-03 23:01:01");
Date date3 = DateUtil.parse("2017-04-01 23:02:02");
//不足一天,between()底层就是两个时间的时间戳相减,再除以一天的毫秒数,取商
Assert.assertEquals(0, DateUtil.between(date1,
DateUtil.parse("2017-03-03 23:01:00"), DateUnit.DAY));
//公式:|endDate - beginDate| ,取绝对值,用在不用区分开始结束日期的顺序的场景
Assert.assertEquals(1, DateUtil.between(date1, date2, DateUnit.DAY));
Assert.assertEquals(1, DateUtil.between(date2, date1, DateUnit.DAY));
//公式:endDate - beginDate ,不取绝对值,用在必须区分正负值的场景
Assert.assertEquals(-30, DateUtil.between(date3, date1, DateUnit.DAY, false));
//betweenMonth()
//isReset参数很有用,重置时间为起始时间(如果是betweenMonth()则重置为月初第1天0时0分0秒)
Assert.assertEquals(1, DateUtil.betweenMonth(date3, date1, true));
Assert.assertEquals(0, DateUtil.betweenMonth(date3, date1, false));
//取的绝对值
Assert.assertEquals(1, DateUtil.betweenMonth(date1, date3, true));
//between()默认isReset=false
Assert.assertEquals(29, DateUtil.between(DateUtil.parse("2017-03-02 23:59:59"), date3, DateUnit.DAY));
//betweenDay()
Date date4 = DateUtil.parse("2017-04-01 02:02:02");
Assert.assertEquals(0, DateUtil.betweenDay(date3, date4, true));
Assert.assertEquals(0, DateUtil.betweenDay(date3, date4, false));
}
使用中总是记不清楚到底哪个方法是要取绝对值,哪个方法要重置,到底该用带日期单位的还是不带日期单位的,每次都要看官方demo或者百度,于是在实际项目中封装了该工具类,可以直接使用。
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import java.time.temporal.ChronoUnit;
import java.util.Date;
/**
* 计算两个日期时间间隔
* 使用范例(链式调用,使用方便):
* new DateBetweenUtil().beginDate("2022-07-08 23:51:01").endDate("2022/07/09 23:50:02").isReset(true).isAbs(false).betweenDay();
*
* @author Dean
*/
public class DateBetweenUtil {
private Date beginDate;
private Date endDate;
/**
* 默认不重置
*/
private boolean isReset = false;
/**
* 默认取绝对值
*/
private boolean isAbs = true;
/**
* 日期时间单位
*/
private ChronoUnit chronoUnit;
/**
* 设置开始日期时间
*
* @param beginDate 日期时间
* @return this
*/
public DateBetweenUtil beginDate(Date beginDate) {
this.beginDate = beginDate;
return this;
}
/**
* 设置开始日期时间
*
* @param beginDate 日期时间,支持多种常用字符串格式
* @return this
*/
public DateBetweenUtil beginDate(String beginDate) {
this.beginDate = DateUtil.parse(beginDate);
return this;
}
/**
* 设置结束日期时间
*
* @param endDate 结束日期时间
* @return this
*/
public DateBetweenUtil endDate(Date endDate) {
this.endDate = endDate;
return this;
}
/**
* 设置结束日期时间
*
* @param endDate 日期时间,支持多种常用字符串格式
* @return this
*/
public DateBetweenUtil endDate(String endDate) {
this.endDate = DateUtil.parse(endDate);
return this;
}
/**
* 是否重置
* 举例:取相差天数,如果重置则开始和结束日期时间的时分秒都会重置为0
*
* @param isReset true重置 false不重置
* @return this
*/
public DateBetweenUtil isReset(boolean isReset) {
this.isReset = isReset;
return this;
}
/**
* 时间间隔结果是否取绝对值
*
* @param isAbs true是 false否
* @return this
*/
public DateBetweenUtil isAbs(boolean isAbs) {
this.isAbs = isAbs;
return this;
}
public long betweenYear() {
chronoUnit = ChronoUnit.YEARS;
return between();
}
public long betweenMonth() {
chronoUnit = ChronoUnit.MONTHS;
return between();
}
public long betweenWeek() {
chronoUnit = ChronoUnit.WEEKS;
return between();
}
public long betweenDay() {
chronoUnit = ChronoUnit.DAYS;
return between();
}
public long betweenHour() {
chronoUnit = ChronoUnit.HOURS;
return between();
}
public long betweenMinute() {
chronoUnit = ChronoUnit.MINUTES;
return between();
}
public long betweenSecond() {
chronoUnit = ChronoUnit.SECONDS;
return between();
}
private long between() {
preCheck();
long time;
if (chronoUnit == ChronoUnit.YEARS) {
time = DateUtil.betweenYear(beginDate, endDate, isReset);
time = isAbs ? Math.abs(time) : time;
} else if (chronoUnit == ChronoUnit.MONTHS) {
time = DateUtil.betweenMonth(beginDate, endDate, isReset);
time = isAbs ? Math.abs(time) : time;
} else {
if (isReset) {
time = reset();
} else {
time = DateUtil.between(beginDate, endDate, DateUnit.of(chronoUnit), isAbs);
}
}
return time;
}
private void preCheck() {
if (beginDate == null) {
throw new IllegalArgumentException("BeginDate must not be null");
}
if (endDate == null) {
throw new IllegalArgumentException("EndDate must not be null");
}
}
private long reset() {
Date begin = beginDate;
Date end = endDate;
switch (chronoUnit) {
case WEEKS:
begin = DateUtil.beginOfWeek(beginDate);
end = DateUtil.beginOfWeek(endDate);
break;
case DAYS:
begin = DateUtil.beginOfDay(beginDate);
end = DateUtil.beginOfDay(endDate);
break;
case HOURS:
begin = DateUtil.beginOfHour(beginDate);
end = DateUtil.beginOfHour(endDate);
break;
case MINUTES:
begin = DateUtil.beginOfMinute(beginDate);
end = DateUtil.beginOfMinute(endDate);
break;
case SECONDS:
begin = DateUtil.beginOfSecond(beginDate);
end = DateUtil.beginOfSecond(endDate);
break;
default:
break;
}
return DateUtil.between(begin, end, DateUnit.of(chronoUnit), isAbs);
}
}
单元测试用例
public class DateBetweenUtilTest {
/**
* 简单使用
*/
@Test
public void testSimple() {
//最简单的使用方式,默认不重置,取绝对值
long time = new DateBetweenUtil()
//支持多种不同的日期格式,或者直接传Date日期对象
.beginDate("2022-07-08 23:51:01").endDate("2022/07/09 23:50:02")
.betweenDay();
//相差不满1天
assertEquals(0, time);
}
/**
* 测试重置
*/
@Test
public void testReset() {
//支持日期类型的不同
String beginDate = "2022-07-08 23:51:01";
Date endDate = DateUtil.parse("2022/07/09 23:50:02");
long time = new DateBetweenUtil()
.beginDate(beginDate).endDate(endDate)
//自由控制是否重置
.isReset(true)
.betweenDay();
//重置后变为 2022-07-08 00:00:00 与 2022-07-09 00:00:00 相差天数
assertEquals(1, time);
}
/**
* 测试不取绝对值
*/
@Test
public void testAbs() {
//开始日期大于结束日期
Date beginDate = DateUtil.parse("2022-07-09 23:01:02");
Date endDate = DateUtil.parse("2022-07-08 23:51:01");
long time = new DateBetweenUtil()
//支持Date型
.beginDate(beginDate).endDate(endDate)
.isReset(true)
//自由控制是否取绝对值,设置为不取绝对值
.isAbs(false)
.betweenDay();
assertEquals(-1, time);
}
/**
* 测试各种日期时间单位
*/
@Test
public void testDateUnit() {
Date beginDate = DateUtil.parse("2021-07-09 23:01:02");
Date endDate = DateUtil.parse("2022-08-08 23:51:01");
//初始化工具对象
DateBetweenUtil dateBetweenUtil = new DateBetweenUtil()
//支持Date型
.beginDate(beginDate).endDate(endDate)
.isReset(false)
//设置为不取绝对值
.isAbs(false);
assertEquals(1, dateBetweenUtil.betweenYear());
assertEquals(12, dateBetweenUtil.betweenMonth());
//与标准的Builder设计模式不同,此对象构造好后可以修改属性值
dateBetweenUtil.isReset(true);
assertEquals(13, dateBetweenUtil.betweenMonth());
dateBetweenUtil.beginDate("2021-07-09 23:01:02").endDate("2021-07-09 23:59:01").isReset(false);
assertEquals(0, dateBetweenUtil.betweenHour());
assertEquals(57, dateBetweenUtil.betweenMinute());
dateBetweenUtil.isReset(true);
assertEquals(58, dateBetweenUtil.betweenMinute());
assertEquals(58 * 60 - 1, dateBetweenUtil.betweenSecond());
dateBetweenUtil.beginDate("2021-07-02 23:01:02").endDate("2021-07-09 23:59:01").isReset(false);
assertEquals(1, dateBetweenUtil.betweenWeek());
}
}
这下使用起来顺手了,是否重置,是否取绝对值,日期要Date还是字符串都可以自由组合。需要的直接可以拷贝到项目中使用。