package com.iailab.framework.common.util.date;
|
|
import cn.hutool.core.collection.CollUtil;
|
import cn.hutool.core.date.DatePattern;
|
import cn.hutool.core.date.LocalDateTimeUtil;
|
import cn.hutool.core.lang.Assert;
|
import cn.hutool.core.util.StrUtil;
|
import com.iailab.framework.common.enums.DateIntervalEnum;
|
|
import java.time.*;
|
import java.time.format.DateTimeParseException;
|
import java.time.temporal.ChronoUnit;
|
import java.time.temporal.TemporalAdjusters;
|
import java.util.ArrayList;
|
import java.util.List;
|
|
/**
|
* 时间工具类,用于 {@link java.time.LocalDateTime}
|
*
|
* @author iailab
|
*/
|
public class LocalDateTimeUtils {
|
|
/**
|
* 空的 LocalDateTime 对象,主要用于 DB 唯一索引的默认值
|
*/
|
public static LocalDateTime EMPTY = buildTime(1970, 1, 1);
|
|
/**
|
* 解析时间
|
*
|
* 相比 {@link LocalDateTimeUtil#parse(CharSequence)} 方法来说,会尽量去解析,直到成功
|
*
|
* @param time 时间
|
* @return 时间字符串
|
*/
|
public static LocalDateTime parse(String time) {
|
try {
|
return LocalDateTimeUtil.parse(time, DatePattern.NORM_DATE_PATTERN);
|
} catch (DateTimeParseException e) {
|
return LocalDateTimeUtil.parse(time);
|
}
|
}
|
|
public static LocalDateTime addTime(Duration duration) {
|
return LocalDateTime.now().plus(duration);
|
}
|
|
public static LocalDateTime minusTime(Duration duration) {
|
return LocalDateTime.now().minus(duration);
|
}
|
|
public static boolean beforeNow(LocalDateTime date) {
|
return date.isBefore(LocalDateTime.now());
|
}
|
|
public static boolean afterNow(LocalDateTime date) {
|
return date.isAfter(LocalDateTime.now());
|
}
|
|
/**
|
* 创建指定时间
|
*
|
* @param year 年
|
* @param mouth 月
|
* @param day 日
|
* @return 指定时间
|
*/
|
public static LocalDateTime buildTime(int year, int mouth, int day) {
|
return LocalDateTime.of(year, mouth, day, 0, 0, 0);
|
}
|
|
public static LocalDateTime[] buildBetweenTime(int year1, int mouth1, int day1,
|
int year2, int mouth2, int day2) {
|
return new LocalDateTime[]{buildTime(year1, mouth1, day1), buildTime(year2, mouth2, day2)};
|
}
|
|
/**
|
* 判指定断时间,是否在该时间范围内
|
*
|
* @param startTime 开始时间
|
* @param endTime 结束时间
|
* @param time 指定时间
|
* @return 是否
|
*/
|
public static boolean isBetween(LocalDateTime startTime, LocalDateTime endTime, String time) {
|
if (startTime == null || endTime == null || time == null) {
|
return false;
|
}
|
return LocalDateTimeUtil.isIn(parse(time), startTime, endTime);
|
}
|
|
/**
|
* 判断当前时间是否在该时间范围内
|
*
|
* @param startTime 开始时间
|
* @param endTime 结束时间
|
* @return 是否
|
*/
|
public static boolean isBetween(LocalDateTime startTime, LocalDateTime endTime) {
|
if (startTime == null || endTime == null) {
|
return false;
|
}
|
return LocalDateTimeUtil.isIn(LocalDateTime.now(), startTime, endTime);
|
}
|
|
/**
|
* 判断当前时间是否在该时间范围内
|
*
|
* @param startTime 开始时间
|
* @param endTime 结束时间
|
* @return 是否
|
*/
|
public static boolean isBetween(String startTime, String endTime) {
|
if (startTime == null || endTime == null) {
|
return false;
|
}
|
LocalDate nowDate = LocalDate.now();
|
return LocalDateTimeUtil.isIn(LocalDateTime.now(),
|
LocalDateTime.of(nowDate, LocalTime.parse(startTime)),
|
LocalDateTime.of(nowDate, LocalTime.parse(endTime)));
|
}
|
|
/**
|
* 判断时间段是否重叠
|
*
|
* @param startTime1 开始 time1
|
* @param endTime1 结束 time1
|
* @param startTime2 开始 time2
|
* @param endTime2 结束 time2
|
* @return 重叠:true 不重叠:false
|
*/
|
public static boolean isOverlap(LocalTime startTime1, LocalTime endTime1, LocalTime startTime2, LocalTime endTime2) {
|
LocalDate nowDate = LocalDate.now();
|
return LocalDateTimeUtil.isOverlap(LocalDateTime.of(nowDate, startTime1), LocalDateTime.of(nowDate, endTime1),
|
LocalDateTime.of(nowDate, startTime2), LocalDateTime.of(nowDate, endTime2));
|
}
|
|
/**
|
* 获取指定日期所在的月份的开始时间
|
* 例如:2023-09-30 00:00:00,000
|
*
|
* @param date 日期
|
* @return 月份的开始时间
|
*/
|
public static LocalDateTime beginOfMonth(LocalDateTime date) {
|
return date.with(TemporalAdjusters.firstDayOfMonth()).with(LocalTime.MIN);
|
}
|
|
/**
|
* 获取指定日期所在的月份的最后时间
|
* 例如:2023-09-30 23:59:59,999
|
*
|
* @param date 日期
|
* @return 月份的结束时间
|
*/
|
public static LocalDateTime endOfMonth(LocalDateTime date) {
|
return date.with(TemporalAdjusters.lastDayOfMonth()).with(LocalTime.MAX);
|
}
|
|
/**
|
* 获得指定日期所在季度
|
*
|
* @param date 日期
|
* @return 所在季度
|
*/
|
public static int getQuarterOfYear(LocalDateTime date) {
|
return (date.getMonthValue() - 1) / 3 + 1;
|
}
|
|
/**
|
* 获取指定日期到现在过了几天,如果指定日期在当前日期之后,获取结果为负
|
*
|
* @param dateTime 日期
|
* @return 相差天数
|
*/
|
public static Long between(LocalDateTime dateTime) {
|
return LocalDateTimeUtil.between(dateTime, LocalDateTime.now(), ChronoUnit.DAYS);
|
}
|
|
/**
|
* 获取今天的开始时间
|
*
|
* @return 今天
|
*/
|
public static LocalDateTime getToday() {
|
return LocalDateTimeUtil.beginOfDay(LocalDateTime.now());
|
}
|
|
/**
|
* 获取昨天的开始时间
|
*
|
* @return 昨天
|
*/
|
public static LocalDateTime getYesterday() {
|
return LocalDateTimeUtil.beginOfDay(LocalDateTime.now().minusDays(1));
|
}
|
|
/**
|
* 获取本月的开始时间
|
*
|
* @return 本月
|
*/
|
public static LocalDateTime getMonth() {
|
return beginOfMonth(LocalDateTime.now());
|
}
|
|
/**
|
* 获取本年的开始时间
|
*
|
* @return 本年
|
*/
|
public static LocalDateTime getYear() {
|
return LocalDateTime.now().with(TemporalAdjusters.firstDayOfYear()).with(LocalTime.MIN);
|
}
|
|
public static List<LocalDateTime[]> getDateRangeList(LocalDateTime startTime,
|
LocalDateTime endTime,
|
Integer interval) {
|
// 1.1 找到枚举
|
DateIntervalEnum intervalEnum = DateIntervalEnum.valueOf(interval);
|
Assert.notNull(intervalEnum, "interval({}} 找不到对应的枚举", interval);
|
// 1.2 将时间对齐
|
startTime = LocalDateTimeUtil.beginOfDay(startTime);
|
endTime = LocalDateTimeUtil.endOfDay(endTime);
|
|
// 2. 循环,生成时间范围
|
List<LocalDateTime[]> timeRanges = new ArrayList<>();
|
switch (intervalEnum) {
|
case DAY:
|
while (startTime.isBefore(endTime)) {
|
timeRanges.add(new LocalDateTime[]{startTime, startTime.plusDays(1).minusNanos(1)});
|
startTime = startTime.plusDays(1);
|
}
|
break;
|
case WEEK:
|
while (startTime.isBefore(endTime)) {
|
LocalDateTime endOfWeek = startTime.with(DayOfWeek.SUNDAY).plusDays(1).minusNanos(1);
|
timeRanges.add(new LocalDateTime[]{startTime, endOfWeek});
|
startTime = endOfWeek.plusNanos(1);
|
}
|
break;
|
case MONTH:
|
while (startTime.isBefore(endTime)) {
|
LocalDateTime endOfMonth = startTime.with(TemporalAdjusters.lastDayOfMonth()).plusDays(1).minusNanos(1);
|
timeRanges.add(new LocalDateTime[]{startTime, endOfMonth});
|
startTime = endOfMonth.plusNanos(1);
|
}
|
break;
|
case QUARTER:
|
while (startTime.isBefore(endTime)) {
|
int quarterOfYear = getQuarterOfYear(startTime);
|
LocalDateTime quarterEnd = quarterOfYear == 4
|
? startTime.with(TemporalAdjusters.lastDayOfYear()).plusDays(1).minusNanos(1)
|
: startTime.withMonth(quarterOfYear * 3 + 1).withDayOfMonth(1).minusNanos(1);
|
timeRanges.add(new LocalDateTime[]{startTime, quarterEnd});
|
startTime = quarterEnd.plusNanos(1);
|
}
|
break;
|
case YEAR:
|
while (startTime.isBefore(endTime)) {
|
LocalDateTime endOfYear = startTime.with(TemporalAdjusters.lastDayOfYear()).plusDays(1).minusNanos(1);
|
timeRanges.add(new LocalDateTime[]{startTime, endOfYear});
|
startTime = endOfYear.plusNanos(1);
|
}
|
break;
|
default:
|
throw new IllegalArgumentException("Invalid interval: " + interval);
|
}
|
// 3. 兜底,最后一个时间,需要保持在 endTime 之前
|
LocalDateTime[] lastTimeRange = CollUtil.getLast(timeRanges);
|
if (lastTimeRange != null) {
|
lastTimeRange[1] = endTime;
|
}
|
return timeRanges;
|
}
|
|
/**
|
* 格式化时间范围
|
*
|
* @param startTime 开始时间
|
* @param endTime 结束时间
|
* @param interval 时间间隔
|
* @return 时间范围
|
*/
|
public static String formatDateRange(LocalDateTime startTime, LocalDateTime endTime, Integer interval) {
|
// 1. 找到枚举
|
DateIntervalEnum intervalEnum = DateIntervalEnum.valueOf(interval);
|
Assert.notNull(intervalEnum, "interval({}} 找不到对应的枚举", interval);
|
|
// 2. 循环,生成时间范围
|
switch (intervalEnum) {
|
case DAY:
|
return LocalDateTimeUtil.format(startTime, DatePattern.NORM_DATE_PATTERN);
|
case WEEK:
|
return LocalDateTimeUtil.format(startTime, DatePattern.NORM_DATE_PATTERN)
|
+ StrUtil.format("(第 {} 周)", LocalDateTimeUtil.weekOfYear(startTime));
|
case MONTH:
|
return LocalDateTimeUtil.format(startTime, DatePattern.NORM_MONTH_PATTERN);
|
case QUARTER:
|
return StrUtil.format("{}-Q{}", startTime.getYear(), getQuarterOfYear(startTime));
|
case YEAR:
|
return LocalDateTimeUtil.format(startTime, DatePattern.NORM_YEAR_PATTERN);
|
default:
|
throw new IllegalArgumentException("Invalid interval: " + interval);
|
}
|
}
|
|
}
|