封装hutool的DateUtil的between()以及betweenDay()等带日期方法

首先这篇文章不是介绍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还是字符串都可以自由组合。需要的直接可以拷贝到项目中使用。

你可能感兴趣的:(java,java)