Hutool之LocalDateTimeUtil:让时间间隔操作如虎添翼

0 阅读10分钟

前言

  在 Java 开发中,日期和时间的处理是一个常见问题。日期时间工具类是 Hutool 的核心包之一,提供针对 JDK 中 Date、Calendar 对象的封装,封装对象如下:

封装对象说明
DateUtil针对日期时间操作提供一系列静态方法
DateTime提供类似于Joda-Time中日期时间对象的封装,继承自Date类,并提供更加丰富的对象方法
FastDateFormat提供线程安全的针对Date对象的格式化和日期字符串解析支持
DateBetween计算两个时间间隔的类
TimeInterval一个简单的计时器类,常用于计算某段代码的执行时间,提供各种单位的花费时长计算
DatePattern提供常用的日期格式化模式,包括String类型和FastDateFormat两种类型
Quarter季度枚举
Month月份枚举
Week周枚举
DateUnit时间枚举,要表示某个时间单位对应的毫秒数,常用于计算时间差

一、概述

1.1 工具简介

  LocalDateTimeUtil 是 Hutool 针对 Java 8 原生 java.time API 的优雅封装,旨在简化 LocalDateTime、LocalDate 等新时间 API 提供的封装工具类。它本身不重新实现时间逻辑,而是对原生 API 进行简化,解决了原生操作繁琐、边界处理复杂的问题,让代码更简洁、易读。该工具类从 Hutool 5.4.x 版本开始提供,涵盖了日常开发中绝大多数时间处理场景。

import cn.hutool.core.date.LocalDateTimeUtil;

1.2 引入依赖

  在使用 Hutool 工具之前,我们需要将 Hutool 添加到项目的依赖中。如果使用 Maven 构建项目,可以在 pom.xml 文件中添加以下依赖:

<!-- https://mvnrepository.com/artifact/cn.hutool/hutool-all -->
<dependency>
    <groupId>cn.hutool</groupId>
    <artifactId>hutool-all</artifactId>
    <!-- 请检查最新版本,可以根据实际需要进行调整 -->
    <version>5.8.40</version>
</dependency>

  Hutool-all 是一个 Hutool 的集成打包产品,由于考虑到“懒人”用户及分不清各个模块作用的用户,“无脑”引入 hutool-all 模块是快速开始和深入应用的最佳方式。

二、常用方法及使用示例

2.1 获取日期时间

方法简要说明
LocalDateTime now()获取默认时区的当前时间
Week dayOfWeek(LocalDate localDate)获取指定日期对应的星期值
int weekOfYear(TemporalAccessor date)获得指定日期是所在年份的第几周
long toEpochMilli(TemporalAccessor temporalAccessor)转为毫秒时间戳
// 获取当前 LocalDateTime
LocalDateTime localDateTime = LocalDateTimeUtil.now();

int week = LocalDateTimeUtil.weekOfYear(localDateTime);
System.out.println("指定日期 " + localDateTime + " 是所在年份的第 " + week + " 周");

// 转为时间戳(毫秒)
long milli = LocalDateTimeUtil.toEpochMilli(localDateTime);
System.out.println("指定日期 " + localDateTime + " 对应的时间戳(毫秒)为:" + milli);

2.2 日期时间转换

方法简要说明
of使用默认时区,将 Date、Instant 等转为 LocalDateTime
LocalDate ofDate(TemporalAccessor temporalAccessor)
LocalDateTime ofUTC(Instant instant)
LocalDateTime ofUTC(long epochMilli)
时间戳转LocalDateTime,使用UTC时区
// 1. 毫秒时间戳转LocalDateTime(系统默认时区)
long ts = System.currentTimeMillis();
LocalDateTime dtTs = LocalDateTimeUtil.of(ts);

// 2. Date对象转LocalDateTime
Date dateObj = new Date();
LocalDateTime dtFromDate = LocalDateTimeUtil.of(dateObj);

// 3. Instant转LocalDateTime
LocalDateTime dtInstant = LocalDateTimeUtil.of(Instant.now());

// 4. UTC时间戳转LocalDateTime(UTC时区)
LocalDateTime dtUtc = LocalDateTimeUtil.ofUTC(ts);

2.3 日期时间解析

方法简要说明
LocalDateTime parse(CharSequence text)按 ISO 格式解析,仅支持 yyyy-MM-dd'T'HH:mm:ss 格式
LocalDateTime parse(CharSequence text, DateTimeFormatter formatter)格式支持日期时间、日期、时间
LocalDateTime parse(CharSequence text, String format)使用指定模式,如 yyyy-MM-dd HH:mm:ss
LocalDate parseDate(CharSequence text)按 ISO 日期格式解析,仅支持 ``yyyy-MM-dd 格式
LocalDate parseDate(CharSequence text, DateTimeFormatter formatter)指定格式化器,时间部分会被丢弃
LocalDate parseDate(CharSequence text, String format)指定日期模式

✅ parse 与 parseDate 对 null、空白字符串做了保护,返回 null。

// 解析ISO时间格式
LocalDateTime localDateTime = LocalDateTimeUtil.parse("2026-10-31T14:30:00");
System.out.println("解析为 LocalDateTime: " + localDateTime);

// 解析自定义格式时间格式
localDateTime = LocalDateTimeUtil.parse("2026-10-31", DatePattern.NORM_DATE_PATTERN);
System.out.println("解析日期时间字符串 LocalDateTime: " + localDateTime);

LocalDate localDate = LocalDateTimeUtil.parseDate("2026-10-31");
System.out.println("解析为 LocalDate: " + localDate);

localDate = LocalDateTimeUtil.parseDate("2026-10-31 14:30:00", DatePattern.NORM_DATETIME_FORMATTER);
System.out.println("解析带时间的字符串为 LocalDate: " + localDate);

// 解析日期时间为LocalDate,时间部分舍弃格式
localDate = LocalDateTimeUtil.parseDate("2026-10-31T14:30:00", DateTimeFormatter.ISO_LOCAL_DATE_TIME);
System.out.println("解析带时间时区的字符串为 LocalDate: " + localDate);

2.4 日期时间格式化

  用于将时间对象输出为指定格式的字符串,常用方法如下表所示:

方法简要说明
format格式化为指定字符串
String formatNormal(LocalDate date)格式化日期时间为 yyyy-MM-dd 格式
String formatNormal(LocalDateTime time)格式化日期时间为 yyyy-MM-dd HH:mm:ss 格式
LocalDateTime localDateTime = LocalDateTime.now();
System.out.println("当前时间: " + localDateTime);

String format = LocalDateTimeUtil.format(localDateTime, DatePattern.NORM_DATETIME_PATTERN);
System.out.println("格式化时间: " + format);

String str = LocalDateTimeUtil.format(localDateTime, "yyyy年MM月dd日");
System.out.println("自定义格式化时间: " + str);

2.4 时间偏移

方法简要说明
offset(LocalDateTime time,long number,TemporalUnit field)对指定时间进行偏移,偏移会修改传入的对象。
offset 为正数表示增加,负数表示减少
LocalDateTime localDateTime = LocalDateTimeUtil.now();
System.out.println("当前时间:" + localDateTime);

LocalDateTime offset = LocalDateTimeUtil.offset(localDateTime, 1, ChronoUnit.DAYS);
System.out.println("增加一天:" + offset);

offset = LocalDateTimeUtil.offset(localDateTime, -2, ChronoUnit.HOURS);
System.out.println("减少2小时:" + offset);

offset = LocalDateTimeUtil.offset(localDateTime, 30, ChronoUnit.MINUTES);
System.out.println("增加30分钟:" + offset);

2.5 时间差计算

  计算两个时间点之间的间隔,如下表所示:

方法简要说明
Duration between(LocalDateTime start, LocalDateTime end)返回 Duration 对象,可以取天、时、分、秒
long between(LocalDateTime start, LocalDateTime end, ChronoUnit unit)直接获取指定单位差值
betweenPeriod(LocalDate start,LocalDate end)用于计算日期间隔(年、月、日)

✅ 注意:包含 start 但不包含 end,如果end < start,获取结果为负数。

LocalDateTime start = LocalDateTimeUtil.parse("1990-07-26T12:00:00");
LocalDateTime end = LocalDateTimeUtil.now();

Duration between = LocalDateTimeUtil.between(start, end);
System.out.println("相差天数:" + between.toDays());

// 直接获取指定单位差值
long years = LocalDateTimeUtil.between(start, end, ChronoUnit.YEARS);
System.out.println("相差年数:" + years);
long months = LocalDateTimeUtil.between(start, end, ChronoUnit.MONTHS);
System.out.println("相差月数:" + months);
long days = LocalDateTimeUtil.between(start, end, ChronoUnit.DAYS);
System.out.println("相差天数:" + days);

2.5 时间判断与比较

方法简要说明
isIn判断指定日期是否在指定日期范围内
isOverlap检查两个时间段是否有时间重叠,常用于会议室预订等场景
isSameDay比较两个日期是否为同一天
isWeekend是否为周末(周六或周日)
@Test
public void isInTest() {
    LocalDateTime target = LocalDateTimeUtil.now();
    LocalDateTime start = LocalDateTimeUtil.beginOfDay(now);
    LocalDateTime end = LocalDateTimeUtil.endOfDay(now);
    
    // 判断 target 是否在 [start, end] 区间
    boolean inRange = LocalDateTimeUtil.isIn(target, start, end);
    System.out.println(target + " 是否在 " + start + " 至 " + end + " 之间:" + inRange);
}

@Test
public void isOverlapTest() {

}

@Test
public void isSameDayInTest() {

}

@Test
public void isWeekendInTest() {
    LocalDateTime localDateTime = LocalDateTimeUtil.now();

    boolean weekend = LocalDateTimeUtil.isWeekend(localDateTime);
    System.out.println(localDateTime + " 是否是周末:" + weekend);
}

2.6 日期时间边界

  快速获取一天的开始或结束时刻,常用于数据库查询范围构造。

方法简要说明
beginOfDay返回指定天的开始时间(00:00:00)
endOfDay返回指定天的结束时间(23:59:59.99999)。
truncateMillisecond:是否毫秒归零
LocalDateTime localDateTime = LocalDateTimeUtil.now();

LocalDateTime beginOfDay = LocalDateTimeUtil.beginOfDay(localDateTime);
System.out.println("指定时间的开始时间: " + beginOfDay);

LocalDateTime endOfDay = LocalDateTimeUtil.endOfDay(localDateTime);
System.out.println("指定时间的结束时间: " + endOfDay);

LocalDateTime endOfDayTruncate = LocalDateTimeUtil.endOfDay(localDateTime, true);
System.out.println("指定时间的结束时间(毫秒归零): " + endOfDayTruncate);

三、附录

3.1 LocalDateTimeUtil 🆚 DateUtil

工具类操作对象JDK 版本特点
LocalDateTimeUtilLocalDateTime
LocalDate
JDK8+不可变、时区可控、推荐新项目
DateUtiljava.util.Date
Calendar
JDK1.7+可变对象,老项目兼容

✅ 不要混用:DateUtil 处理 Date,LocalDateTimeUtil 处理 java.time 时间。

3.2 业务日期工具封装

  基于 Hutool LocalDateTimeUtil 业务日期工具封装,底层全部复用 LocalDateTimeUtil 不重复造轮子,常用于今天、昨天、本周、上周、本月、上月、本季度、上季度、本年、去年起止、年龄计算、是否同一天、是否同周、近 N 天起止、人性化相对时间(多久之前)等。

import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.LocalDateTimeUtil;
import java.time.*;
import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalAdjusters;

public class BizDateUtil {
// ====================== 【当前快捷获取】 ======================

    /**
     * 当前 LocalDateTime
     */
    public static LocalDateTime now() {
        return LocalDateTimeUtil.now();
    }

    /**
     * 今天日期(LocalDate)
     */
    public static LocalDate today() {
        LocalDateTime localDateTime = LocalDateTime.now();
        String format = LocalDateTimeUtil.format(localDateTime, DatePattern.NORM_DATE_PATTERN);
        return LocalDateTimeUtil.parseDate(format, DatePattern.NORM_DATE_PATTERN);
    }

    /**
     * 今天开始时间 00:00:00
     */
    public static LocalDateTime beginOfToday() {
        return LocalDateTimeUtil.beginOfDay(today());
    }

    /**
     * 今天结束时间 23:59:59.999999999
     */
    public static LocalDateTime endOfToday() {
        return LocalDateTimeUtil.endOfDay(today());
    }

    /**
     * 昨天开始
     */
    public static LocalDateTime beginOfYesterday() {
        LocalDate yesterday = today().minusDays(1);
        return LocalDateTimeUtil.beginOfDay(yesterday);
    }

    /**
     * 昨天结束
     */
    public static LocalDateTime endOfYesterday() {
        LocalDate yesterday = today().minusDays(1);
        return LocalDateTimeUtil.endOfDay(yesterday);
    }

    // ====================== 【近N天】 ======================

    /**
     * 近n天(包含今天)起始时间
     * 示例:n=7 → 【6天前 00:00:00 ~ 今天 23:59:59.999999999】
     *
     * @param n 天数,必须 >=1
     * @return 起始时间
     */
    public static LocalDateTime beginOfRecentNDays(int n) {
        if (n < 1) {
            throw new IllegalArgumentException("天数不能小于1");
        }
        LocalDate startDate = today().minusDays(n - 1);
        return LocalDateTimeUtil.beginOfDay(startDate);
    }

    /**
     * 近n天(不包含今天)起始时间
     * 示例:n=7 → 【7天前 00:00:00 ~ 昨天 23:59:59.999999999】
     *
     * @param n 天数,必须 >=1
     * @return 起始时间
     */
    public static LocalDateTime beginOfRecentNDaysExcludeToday(int n) {
        if (n < 1) {
            throw new IllegalArgumentException("天数不能小于1");
        }
        LocalDate startDate = today().minusDays(n);
        return LocalDateTimeUtil.beginOfDay(startDate);
    }

    // ====================== 【本周 / 上周(周一为第一天)】 ======================

    /**
     * 本周第一天(周一)00:00:00
     */
    public static LocalDateTime beginOfThisWeek() {
        LocalDate monday = today().with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY));
        return LocalDateTimeUtil.beginOfDay(monday);
    }

    /**
     * 本周最后一天(周日)23:59:59.999999999
     */
    public static LocalDateTime endOfThisWeek() {
        LocalDate sunday = today().with(TemporalAdjusters.nextOrSame(DayOfWeek.SUNDAY));
        return LocalDateTimeUtil.endOfDay(sunday);
    }

    /**
     * 上周第一天(上周一)
     */
    public static LocalDateTime beginOfLastWeek() {
        LocalDate lastMonday = today()
                .with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY))
                .minusWeeks(1);
        return LocalDateTimeUtil.beginOfDay(lastMonday);
    }

    /**
     * 上周最后一天(上周日)
     */
    public static LocalDateTime endOfLastWeek() {
        LocalDate lastSunday = today()
                .with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY))
                .minusDays(1);
        return LocalDateTimeUtil.endOfDay(lastSunday);
    }

    // ====================== 【本月 / 上月】 ======================

    /**
     * 本月第一天 00:00:00
     */
    public static LocalDateTime beginOfThisMonth() {
        LocalDate firstDay = today().with(TemporalAdjusters.firstDayOfMonth());
        return LocalDateTimeUtil.beginOfDay(firstDay);
    }

    /**
     * 本月最后一天 23:59:59.999999999
     */
    public static LocalDateTime endOfThisMonth() {
        LocalDate lastDay = today().with(TemporalAdjusters.lastDayOfMonth());
        return LocalDateTimeUtil.endOfDay(lastDay);
    }

    /**
     * 上月第一天
     */
    public static LocalDateTime beginOfLastMonth() {
        LocalDate firstDay = today().minusMonths(1).with(TemporalAdjusters.firstDayOfMonth());
        return LocalDateTimeUtil.beginOfDay(firstDay);
    }

    /**
     * 上月最后一天
     */
    public static LocalDateTime endOfLastMonth() {
        LocalDate lastDay = today().minusMonths(1).with(TemporalAdjusters.lastDayOfMonth());
        return LocalDateTimeUtil.endOfDay(lastDay);
    }

    // ====================== 【本季度 / 上季度】 ======================

    /**
     * 获取本季度起始时间
     */
    public static LocalDateTime beginOfThisQuarter() {
        LocalDate nowDate = today();
        int quarter = (nowDate.getMonthValue() - 1) / 3;
        Month startMonth = Month.of(quarter * 3 + 1);
        LocalDate firstDay = LocalDate.of(nowDate.getYear(), startMonth, 1);
        return LocalDateTimeUtil.beginOfDay(firstDay);
    }

    /**
     * 获取本季度结束时间
     */
    public static LocalDateTime endOfThisQuarter() {
        LocalDate nowDate = today();
        int quarter = (nowDate.getMonthValue() - 1) / 3;
        Month endMonth = Month.of(quarter * 3 + 3);
        LocalDate lastDay = LocalDate.of(nowDate.getYear(), endMonth, 1)
                .with(TemporalAdjusters.lastDayOfMonth());
        return LocalDateTimeUtil.endOfDay(lastDay);
    }

    /**
     * 上季度起始
     */
    public static LocalDateTime beginOfLastQuarter() {
        LocalDate nowDate = today();
        int q = (nowDate.getMonthValue() - 1) / 3;
        LocalDate firstDay;
        if (q == 0) {
            // 当前Q1,上季度是去年Q4
            firstDay = LocalDate.of(nowDate.getYear() - 1, Month.OCTOBER, 1);
        } else {
            Month startMonth = Month.of((q - 1) * 3 + 1);
            firstDay = LocalDate.of(nowDate.getYear(), startMonth, 1);
        }
        return LocalDateTimeUtil.beginOfDay(firstDay);
    }

    /**
     * 上季度结束
     */
    public static LocalDateTime endOfLastQuarter() {
        LocalDate nowDate = today();
        int q = (nowDate.getMonthValue() - 1) / 3;
        LocalDate lastDay;
        if (q == 0) {
            lastDay = LocalDate.of(nowDate.getYear() - 1, Month.DECEMBER, 1)
                    .with(TemporalAdjusters.lastDayOfMonth());
        } else {
            Month endMonth = Month.of((q - 1) * 3 + 3);
            lastDay = LocalDate.of(nowDate.getYear(), endMonth, 1)
                    .with(TemporalAdjusters.lastDayOfMonth());
        }
        return LocalDateTimeUtil.endOfDay(lastDay);
    }

    // ====================== 【本年 / 去年】 ======================

    /**
     * 本年第一天
     */
    public static LocalDateTime beginOfThisYear() {
        LocalDate firstDay = today().with(TemporalAdjusters.firstDayOfYear());
        return LocalDateTimeUtil.beginOfDay(firstDay);
    }

    /**
     * 本年最后一天
     */
    public static LocalDateTime endOfThisYear() {
        LocalDate lastDay = today().with(TemporalAdjusters.lastDayOfYear());
        return LocalDateTimeUtil.endOfDay(lastDay);
    }

    /**
     * 去年第一天
     */
    public static LocalDateTime beginOfLastYear() {
        LocalDate firstDay = today().minusYears(1).with(TemporalAdjusters.firstDayOfYear());
        return LocalDateTimeUtil.beginOfDay(firstDay);
    }

    /**
     * 去年最后一天
     */
    public static LocalDateTime endOfLastYear() {
        LocalDate lastDay = today().minusYears(1).with(TemporalAdjusters.lastDayOfYear());
        return LocalDateTimeUtil.endOfDay(lastDay);
    }

    // ====================== 【判断工具】 ======================

    /**
     * 是否同一天
     */
    public static boolean isSameDay(LocalDateTime dt1, LocalDateTime dt2) {
        if (dt1 == null || dt2 == null) {
            return false;
        }
        return LocalDate.from(dt1).isEqual(LocalDate.from(dt2));
    }

    /**
     * 是否同一周(周一为一周起始)
     */
    public static boolean isSameWeek(LocalDateTime dt1, LocalDateTime dt2) {
        if (dt1 == null || dt2 == null) {
            return false;
        }
        LocalDate d1 = LocalDate.from(dt1);
        LocalDate d2 = LocalDate.from(dt2);
        LocalDate w1 = d1.with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY));
        LocalDate w2 = d2.with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY));
        return w1.isEqual(w2);
    }

    /**
     * 是否同一月
     */
    public static boolean isSameMonth(LocalDateTime dt1, LocalDateTime dt2) {
        if (dt1 == null || dt2 == null) {
            return false;
        }
        return dt1.getYear() == dt2.getYear() && dt1.getMonthValue() == dt2.getMonthValue();
    }

    /**
     * 时间是否在 [start, end] 闭区间内(封装hutool isIn)
     */
    public static boolean isIn(LocalDateTime target, LocalDateTime start, LocalDateTime end) {
        if (target == null || start == null || end == null) {
            return false;
        }
        return LocalDateTimeUtil.isIn(target, start, end);
    }

    // ====================== 【年龄计算】 ======================

    /**
     * 根据生日计算周岁
     *
     * @param birthday 生日 LocalDate
     * @return 周岁
     */
    public static int getAge(LocalDate birthday) {
        if (birthday == null) {
            return 0;
        }
        return (int) ChronoUnit.YEARS.between(birthday, today());
    }

    public static int getAge(LocalDateTime birthday) {
        if (birthday == null) {
            return 0;
        }
        return getAge(LocalDate.from(birthday));
    }

    // ====================== 【格式化快捷方法】 ======================

    /**
     * yyyy-MM-dd HH:mm:ss
     */
    public static String formatNormal(LocalDateTime dt) {
        if (dt == null) {
            return null;
        }
        return LocalDateTimeUtil.format(dt, DatePattern.NORM_DATETIME_PATTERN);
    }

    /**
     * yyyy-MM-dd
     */
    public static String formatDate(LocalDate date) {
        if (date == null) {
            return null;
        }
        return LocalDateTimeUtil.format(date, DatePattern.NORM_DATE_PATTERN);
    }

    // ====================== 【解析快捷方法】 ======================

    public static LocalDateTime parseNormal(String dateStr) {
        if (dateStr == null) {
            return null;
        }
        return LocalDateTimeUtil.parse(dateStr, DatePattern.NORM_DATETIME_PATTERN);
    }

    // ====================== 人性化相对时间(多久之前)】 ======================

    /**
     * 人性化相对时间:刚刚 / x分钟前 / x小时前 / x天前,超过7天返回 yyyy-MM-dd HH:mm:ss
     *
     * @param time 待格式化时间
     * @return 友好时间文本
     */
    public static String formatRelativeTime(LocalDateTime time) {
        if (time == null) {
            return "";
        }
        LocalDateTime now = now();
        // 防止传入未来时间
        if (time.isAfter(now)) {
            return formatNormal(time);
        }
        Duration duration = Duration.between(time, now);
        long second = duration.getSeconds();
        if (second < 60) {
            return "刚刚";
        }
        long minute = duration.toMinutes();
        if (minute < 60) {
            return minute + "分钟前";
        }
        long hour = duration.toHours();
        if (hour < 24) {
            return hour + "小时前";
        }
        long day = duration.toDays();
        if (day <= 7) {
            return day + "天前";
        }
        // 超过7天,返回标准日期字符串
        return formatNormal(time);
    }
}

测试使用示例:

public class LocalDateTimeUtilTest {
    public static void main(String[] args) {
        System.out.println("今天开始:" + BizDateUtil.beginOfToday());
        System.out.println("本周起止:" + BizDateUtil.beginOfThisWeek() + " ~ " + BizDateUtil.endOfThisWeek());
        System.out.println("上月起止:" + BizDateUtil.beginOfLastMonth() + " ~ " + BizDateUtil.endOfLastMonth());
        System.out.println("上季度起止:" + BizDateUtil.beginOfLastQuarter() + " ~ " + BizDateUtil.endOfLastQuarter());
        System.out.println("本年起止:" + BizDateUtil.beginOfThisYear() + " ~ " + BizDateUtil.endOfThisYear());

        // 年龄
        LocalDate birth = LocalDate.of(2000, 5, 20);
        System.out.println("年龄:" + BizDateUtil.getAge(birth));

        // 判断
        LocalDateTime t1 = LocalDateTime.of(2026, 11, 1, 10, 0, 0);
        LocalDateTime t2 = LocalDateTime.of(2026, 11, 1, 22, 0, 0);
        System.out.println("是否同一天:" + BizDateUtil.isSameDay(t1, t2));

        // 近7天(含今天)
        LocalDateTime recent7Start = BizDateUtil.beginOfRecentNDays(7);
        System.out.println("近7天起始(含今天):" + recent7Start + " ~ " + BizDateUtil.endOfToday());

        // 近7天(不含今天)
        LocalDateTime recent7ExStart = BizDateUtil.beginOfRecentNDaysExcludeToday(7);
        System.out.println("近7天起始(不含今天):" + recent7ExStart + " ~ " + BizDateUtil.endOfYesterday());

        // 人性化时间
        LocalDateTime m1 = LocalDateTime.now().minusMinutes(5);
        LocalDateTime h1 = LocalDateTime.now().minusHours(3);
        LocalDateTime d1 = LocalDateTime.now().minusDays(3);
        LocalDateTime d2 = LocalDateTime.now().minusDays(10);
        System.out.println("5分钟前" + BizDateUtil.formatRelativeTime(m1));
        System.out.println("3小时前" + BizDateUtil.formatRelativeTime(h1));
        System.out.println("3天前" + BizDateUtil.formatRelativeTime(d1));
        System.out.println("10天前" + BizDateUtil.formatRelativeTime(d2));
    }
}