package com.dates.utils;

import cn.hutool.core.collection.CollUtil;
import lombok.extern.slf4j.Slf4j;

import java.text.SimpleDateFormat;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalAdjusters;
import java.time.temporal.WeekFields;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @author chengzb-c
 * @date 2025年02月11日17:27:56
 * @doc 日期工具类
 */
@Slf4j
public class DateUtils {

    /**
     * 计算给定日期范围内的周数,并根据每周包含的天数来确定是否将该周纳入考核。
     * 返回纳入考核的周数。
     *
     * @param startDate     统计周期的起始日期
     * @param endDate       统计周期的结束日期
     * @param minDaysInWeek 纳入考核的最小天数
     * @return 返回纳入考核的周数
     */
    public static int calculateWeeksInPeriod(LocalDate startDate, LocalDate endDate, int minDaysInWeek) {
        int weeksInPeriod = 0;
        LocalDate currentDate = startDate;
        while (!currentDate.isAfter(endDate)) {
            LocalDate nextWeek = currentDate.with(TemporalAdjusters.next(DayOfWeek.MONDAY));
            int daysInWeek = Period.between(currentDate, nextWeek).getDays();
            if (daysInWeek >= minDaysInWeek) {
                weeksInPeriod++;
            }
            currentDate = nextWeek;
        }
        return weeksInPeriod;
    }

    /**
     * 计算给定日期范围内的周数,并根据每周包含的天数来确定是否将该周纳入考核。
     * 返回纳入考核的具体天数列表。
     *
     * @param startDate     统计周期的起始日期
     * @param endDate       统计周期的结束日期
     * @param minDaysInWeek 纳入考核的最小天数
     * @return 纳入考核的具体天数列表
     */
    public static List<List<LocalDate>> calculateWeeksInPeriodByDay(LocalDate startDate, LocalDate endDate, int minDaysInWeek) {
        LocalDate currentDate = startDate;
        List<List<LocalDate>> includedDays = new ArrayList<>();
        while (!currentDate.isAfter(endDate)) {
            LocalDate nextWeek = currentDate.with(TemporalAdjusters.next(DayOfWeek.MONDAY));
            //如果是最后一天是5天
            if (nextWeek.isAfter(endDate)) {
                nextWeek = endDate.plusDays(1);
            }
            int daysInWeek = Period.between(currentDate, nextWeek).getDays();
            if (daysInWeek >= minDaysInWeek) {
                List<LocalDate> daysInPeriod = Stream.iterate(currentDate, date -> date.plusDays(1))
                        .limit(daysInWeek)
                        .collect(Collectors.toList());
                includedDays.add(daysInPeriod);
            }
            currentDate = nextWeek;
        }
        return includedDays;
    }

    /**
     * 将连续的日期列表转换为多个时间区间
     * @param dates 日期列表(需已排序)
     * @return 包含开始和结束时间的时间区间列表
     */
    public static List<DayRange> convertToDateRanges(List<LocalDate> dates) {
        List<DayRange> ranges = new ArrayList<>();
        if (CollUtil.isEmpty(dates)) {
            return ranges;
        }
        // 对日期进行排序
        dates.sort(LocalDate::compareTo);
        LocalDate start = dates.get(0);
        LocalDate end = start;
        for (int i = 1; i < dates.size(); i++) {
            LocalDate current = dates.get(i);
            // 如果当前日期与上一个日期连续
            if (current.equals(end.plusDays(1))) {
                end = current;
            } else {
                // 保存当前区间
                DayRange dayRange = new DayRange();
                dayRange.setStartDate(start);
                dayRange.setEndDate(end);
                ranges.add(dayRange);
                // 开始新的区间
                start = current;
                end = current;
            }
        }
        // 添加最后一个区间
        DayRange dayRange = new DayRange();
        dayRange.setStartDate(start);
        dayRange.setEndDate(end);
        ranges.add(dayRange);
        return ranges;
    }

    /**
     * @param date          日期
     * @param minDaysInWeek 周内的最小天数
     * @return {@link List<List<LocalDate>>}
     */
    public static List<List<LocalDate>> calculateWeeksInPeriodByDay(List<LocalDate> date, int minDaysInWeek) {
        if (CollUtil.isEmpty(date)) {
            return Collections.emptyList();
        }
        List<List<LocalDate>> days = new ArrayList<>();
        List<DayRange> dayRanges = convertToDateRanges(date);
        for (DayRange dayRange : dayRanges) {
            days.addAll(calculateWeeksInPeriodByDay(dayRange.getStartDate(), dayRange.getEndDate(), minDaysInWeek));
        }
        return days;
    }

    /**
     * 时间区间排除时间段
     * @param startDate
     * @param endDate
     * @param excludedDayRanges
     * @return
     */
    public static List<LocalDate> excludeHolidays(LocalDate startDate, LocalDate endDate,  List<DayRange> excludedDayRanges) {
        List<LocalDate> result = new ArrayList<>();
        LocalDate current = startDate;
        // 遍历整个日期区间
        while (!current.isAfter(endDate)) {
            boolean isExcluded = false;
            // 检查当前日期是否在排除区间内
            for (DayRange range : excludedDayRanges) {
                if (!current.isBefore(range.getStartDate()) && !current.isAfter(range.getEndDate())) {
                    isExcluded = true;
                    break;
                }
            }
            // 如果不在排除区间内,则加入结果列表
            if (!isExcluded) {
                result.add(current);
            }
            current = current.plusDays(1);
        }
        return result;
    }

    /**
     * 从已经纳入考核的天数列表中排除指定的一些天。
     *
     * @param includedDays     已经纳入考核的天数列表
     * @param excludedDayStart 需要排除的天数开始
     * @param excludedDayEnd   需要排除的天数结束
     * @return 排除指定天数后的考核天数列表
     */
    public static List<List<LocalDate>> excludeDays(List<List<LocalDate>> includedDays, LocalDate excludedDayStart, LocalDate excludedDayEnd) {
        if (excludedDayStart == null || excludedDayEnd == null) {
            return includedDays;
        }
        excludedDayEnd = excludedDayEnd.plusDays(1);
        List<LocalDate> excludedDays = Stream.iterate(excludedDayStart, date -> date.plusDays(1))
                .limit(excludedDayStart.until(excludedDayEnd, ChronoUnit.DAYS) - 1)
                .collect(Collectors.toList());
        log.info("[人员履职]:过滤:{}", excludedDays);
        List<List<LocalDate>> resultDateList = new ArrayList<>();
        for (List<LocalDate> localDates : includedDays) {
            if (!excludedDays.contains(localDates.get(0))) {
                resultDateList.add(localDates);
            }
        }
        log.info("[人员履职]:过滤扣除后:{}", resultDateList);
        return resultDateList;
    }

    /**
     * 计算给定日期范围内的月度考核情况。
     * 若当前考核时间包含天数大于该月总天数的1/2,则该月计入考核;
     * 若包含天数小于等于该月总天数的1/2,则该月不计入考核。
     *
     * @param startDate 统计周期的起始日期
     * @param endDate   统计周期的结束日期
     * @return 纳入考核的月份列表
     */
    public static List<List<LocalDate>> calculateMonthsInPeriod(LocalDate startDate, LocalDate endDate) {
        List<List<LocalDate>> includedMonths = new ArrayList<>();
        LocalDate currentDate = startDate;
        while (!currentDate.isAfter(endDate)) {
            int daysInMonth = currentDate.lengthOfMonth();
            LocalDate nextMonth = currentDate.plusMonths(1);
            LocalDate startOfDay = nextMonth.atStartOfDay().toLocalDate();
            if (startOfDay.isAfter(endDate)) {
                nextMonth = endDate.plusDays(1);
            }
            int daysInPeriod = (int) ChronoUnit.DAYS.between(currentDate, nextMonth);
            int halfDaysInMonth = (daysInMonth + 1) / 2;
            if (daysInPeriod > halfDaysInMonth) {
                List<LocalDate> dateByMonth = Stream.iterate(currentDate, date -> date.plusDays(1))
                        .limit(daysInPeriod)
                        .collect(Collectors.toList());
                includedMonths.add(dateByMonth);
            }
            currentDate = currentDate.plusMonths(1);
        }
        return includedMonths;
    }

    /**
     * 计算给定日期范围内的月度。
     * 若当前考核时间包含天数大于该月总天数的1/2,则该月计入考核;
     * 若包含天数小于等于该月总天数的1/2,则该月不计入考核。
     *
     * @param startDate 统计周期的起始日期
     * @param endDate   统计周期的结束日期
     * @return 纳入考核的月份列表
     */
    public static List<YearMonth> getYearMonthsWithMoreThanHalfDaysInRange(LocalDate startDate, LocalDate endDate) {
        List<YearMonth> result = new ArrayList<>();
        // 确保startDate在endDate之前
        if (startDate.isAfter(endDate)) {
            return result;
        }
        // 使用YearMonth类来遍历月份
        YearMonth startYearMonth = YearMonth.from(startDate);
        YearMonth endYearMonth = YearMonth.from(endDate);
        endYearMonth = endYearMonth.plusMonths(1); // 加一个月以确保包含endDate所在的月份
        // 遍历起始月份到结束月份之前的所有月份
        for (YearMonth yearMonth = startYearMonth; !yearMonth.isAfter(endYearMonth); yearMonth = yearMonth.plusMonths(1)) {
            // 获取当前月份的第一天和最后一天
            LocalDate firstDayOfMonth = yearMonth.atDay(1);
            LocalDate lastDayOfMonth = yearMonth.atEndOfMonth();
            // 计算给定日期范围内当前月份的天数
            long daysInRange = ChronoUnit.DAYS.between(
                    startDate.isBefore(firstDayOfMonth) ? firstDayOfMonth : startDate,
                    endDate.isAfter(lastDayOfMonth) ? lastDayOfMonth : endDate) + 1;
            // 获取当前月份的总天数
            int daysInMonth = yearMonth.lengthOfMonth();
            // 检查在范围内的天数是否大于月份天数的一半
            if (daysInRange > daysInMonth / 2l) {
                // 如果是,则添加该年和月到结果列表中
                // 使用格式 "YYYY-MM"
                result.add(yearMonth);
            }
        }
        return result;
    }

    // 根据季度和年份获取该季度的所有月份
    public static List<YearMonth> getYearMonths(Integer year, Integer quarter) {
        List<YearMonth> result = new ArrayList<>();
        switch (quarter) {
            case 1:
                result.add(YearMonth.of(year, 1));
                result.add(YearMonth.of(year, 2));
                result.add(YearMonth.of(year, 3));
                break;
            case 2:
                result.add(YearMonth.of(year, 4));
                result.add(YearMonth.of(year, 5));
                result.add(YearMonth.of(year, 6));
                break;
            case 3:
                result.add(YearMonth.of(year, 7));
                result.add(YearMonth.of(year, 8));
                result.add(YearMonth.of(year, 9));
                break;
            case 4:
                result.add(YearMonth.of(year, 10));
                result.add(YearMonth.of(year, 11));
                result.add(YearMonth.of(year, 12));
                break;
            default:
                break;
        }
        return result;
    }

    /**
     * 计算给定日期范围内的季度考核情况。
     * 若当前考核时间包含天数大于该月总天数的1/2,则该月计入考核;
     * 若包含天数小于等于该月总天数的1/2,则该月不计入考核。
     *
     * @param startDate 统计周期的起始日期
     * @param endDate   统计周期的结束日期
     * @return 纳入考核的月份列表
     */
    public static List<List<LocalDate>> calculateQuarterInPeriod(LocalDate startDate, LocalDate endDate) {
        List<List<LocalDate>> includedMonths = new ArrayList<>();
        LocalDate currentDate = startDate;
        while (!currentDate.isAfter(endDate)) {
            int daysInQuarter = getDaysInQuarter(currentDate); // 30 * 3
            LocalDate nextQuarter = plusQuarter(currentDate);
            LocalDate startOfDay = nextQuarter.atStartOfDay().toLocalDate();
            if (startOfDay.isAfter(endDate)) {
                nextQuarter = endDate.plusDays(1);
            }
            int daysInPeriod = (int) ChronoUnit.DAYS.between(currentDate, nextQuarter); // 10-10 - 12-31
            int halfDaysInMonth = (daysInQuarter + 1) / 2;
            if (daysInPeriod > halfDaysInMonth) {
                List<LocalDate> dateByMonth = Stream.iterate(currentDate, date -> date.plusDays(1))
                        .limit(daysInPeriod)
                        .collect(Collectors.toList());
                includedMonths.add(dateByMonth);
            }
            currentDate = nextQuarter;
        }
        return includedMonths;
    }

    /**
     * 获取当前季度的总天数
     * @param localDate 当前日期
     * @return 当前季度的总天数
     */
    public static int getDaysInQuarter(LocalDate localDate) {
        int quarter = getQuarter(localDate);
        int year = localDate.getYear();

        switch (quarter) {
            case 1:
                return YearMonth.of(year, 1).lengthOfMonth()
                        + YearMonth.of(year, 2).lengthOfMonth()
                        + YearMonth.of(year, 3).lengthOfMonth();
            case 2:
                return YearMonth.of(year, 4).lengthOfMonth()
                        + YearMonth.of(year, 5).lengthOfMonth()
                        + YearMonth.of(year, 6).lengthOfMonth();
            case 3:
                return YearMonth.of(year, 7).lengthOfMonth()
                        + YearMonth.of(year, 8).lengthOfMonth()
                        + YearMonth.of(year, 9).lengthOfMonth();
            case 4:
                return YearMonth.of(year, 10).lengthOfMonth()
                        + YearMonth.of(year, 11).lengthOfMonth()
                        + YearMonth.of(year, 12).lengthOfMonth();
            default:
                throw new IllegalArgumentException("Invalid quarter: " + quarter);
        }
    }

    private static LocalDate plusQuarter(LocalDate currentDate) {
        int monthValue = currentDate.getMonthValue();
        int year = currentDate.getYear();
        switch (monthValue) {
            case 1:
            case 2:
            case 3:
                return LocalDate.of(year, 4, 1);
            case 4:
            case 5:
            case 6:
                return LocalDate.of(year, 7, 1);
            case 7:
            case 8:
            case 9:
                return LocalDate.of(year, 10, 1);
            case 10:
            case 11:
            case 12:
                return LocalDate.of(year+1, 1, 1);
            default:
                throw new IllegalStateException("Unexpected month value: " + monthValue);
        }
    }

    /**
     * 判断给定的时间是否在给定的日期范围内。 整天维度
     * @param days
     * @param time
     * @return
     */
    public static Boolean isContains(List<List<LocalDate>> days, Long time) {
        List<Long> dayList = days.stream().flatMap(List::stream).
                map(DateUtils::getTimestamp)
                .collect(Collectors.toList());
        return dayList.contains(DateUtils.getTimestamp(time));
    }


    /**
     * 获取档期日期的季度
     *
     * @param localDate 本地日期
     * @return int
     */
    public static int getQuarter(LocalDate localDate) {
        int month = localDate.getMonthValue();
        return (month - 1) / 3 + 1;
    }

    /**
     * 获取指定日期是当月的第几周
     * @param localDate 指定日期
     * @return 当月的第几周
     */
    public static int getWeekOfMonth(LocalDate localDate) {
        // 使用 ISO 标准的周定义,周一为一周的开始
        WeekFields weekFields = WeekFields.ISO;
        // 获取该日期是当月的第几周
        return localDate.get(weekFields.weekOfMonth());
    }

    /**
     *  定义一个方法用于将 Date 转换为 LocalDate
     *  
     * @param date
     * @return
     */
    public static LocalDate convertDateToLocalDate(Date date) {
        // 将 Date 转换为 Instant
        Instant instant = date.toInstant();
        // 获取系统默认时区
        ZoneId zoneId = ZoneId.systemDefault();
        // 将 Instant 转换为 LocalDate
        return instant.atZone(zoneId).toLocalDate();
    }

    /**
     * 获取两个时间周期内的所有日期
     * @param startDate 开始日期
     * @param endDate 结束日期
     * @return 包含所有日期的列表
     */
    public static List<LocalDate> getAllDaysBetween(LocalDate startDate, LocalDate endDate) {
        List<LocalDate> dates = new ArrayList<>();
        LocalDate currentDate = startDate;
        while (!currentDate.isAfter(endDate)) {
            dates.add(currentDate);
            currentDate = currentDate.plusDays(1);
        }
        return dates;
    }
    // ==== 按照周计算=======    
//    public static void main(String[] args) {
//        int minDaysInWeek = 5;
//        LocalDate startDate = LocalDate.of(2025, 2, 3);
//        LocalDate endDate = LocalDate.of(2025, 2, 28);
//        // 假设需要排除的天数
//        LocalDate excludedDayStart = LocalDate.of(2025, 2, 10);
//        LocalDate excludedDayEnd = LocalDate.of(2025, 2, 16);
//
//        int weeksInPeriod = calculateWeeksInPeriod(startDate, endDate, minDaysInWeek);
//        System.out.println("纳入考核的周数: " + weeksInPeriod);
//
//        List<List<LocalDate>> weeksInPeriodByDay = calculateWeeksInPeriodByDay(startDate, endDate, minDaysInWeek);
//        List<List<LocalDate>> finalIncludedDays = excludeDays(weeksInPeriodByDay, excludedDayStart, excludedDayEnd);
//
//        System.out.println("纳入考核的天: " + weeksInPeriodByDay);
//        System.out.println("排除指定天数后的考核天数: " + finalIncludedDays);
//    }

    /**
     * 将 LocalDate 转换为 Date
     * @param localDate 要转换的 LocalDate 对象
     * @return 转换后的 Date 对象
     */
    public static Date convertToDate(LocalDate localDate) {
        java.time.ZonedDateTime zonedDateTime = localDate.atStartOfDay(ZoneId.systemDefault());
        return Date.from(zonedDateTime.toInstant());
    }

    /**
     * 格式化日期
     * @param localDate
     * @return
     */
    public static String localDateToDateString(LocalDate localDate) {
        return localDate.format(DateTimeFormatter.ofPattern("yyyy.MM.dd"));
    }

    /**
     * 格式化日期
     * @param milliTime
     * @return
     */
    public static String milliTimeToDateString(Long milliTime) {
        return LocalDateTime.ofInstant(Instant.ofEpochMilli(milliTime), ZoneId.systemDefault()).format(DateTimeFormatter.ofPattern("yyyy.MM.dd"));
    }

    /**
     * 格式化日期
     * @param milliTime
     * @return
     */
    public static LocalDate milliTimeToLocalDate(Long milliTime) {
        return LocalDateTime.ofInstant(Instant.ofEpochMilli(milliTime), ZoneId.systemDefault()).toLocalDate();
    }

    /**
     * 格式化日期
     */
    private static final SimpleDateFormat SIMPLE_DATE_FORMAT = new SimpleDateFormat("yyyy.MM.dd");
    public static String dateToDateString(Date date) {
        return SIMPLE_DATE_FORMAT.format(date);
    }

    /*
     * 将时间段进行合并
     * 入参: [(25-01-01 - 25-01-09), (25-01-08 - 25-01-15), (25-01-20 - 25-01-30)]
     * 结果: [(25-01-01 - 25-01-15), (25-01-20 - 25-01-30)]
     * 将数据段也根据时间进行合并.
     */
    public static List<ProjectDateRangeProps> mergeIntervalsByDate(List<ProjectDateRangeProps> intervals) {
        if (intervals == null || intervals.isEmpty()) {
            return Collections.emptyList();
        }

        // 按 projectId 分组
        Map<Long, List<ProjectDateRangeProps>> intervalsByProject = intervals.stream()
                .collect(Collectors.groupingBy(ProjectDateRangeProps::getProjectId));

        // 对每个 projectId 的时间间隔进行合并
        List<ProjectDateRangeProps> mergedIntervals = new ArrayList<>();
        for (Map.Entry<Long, List<ProjectDateRangeProps>> entry : intervalsByProject.entrySet()) {
            List<ProjectDateRangeProps> projectIntervals = entry.getValue();
            mergedIntervals.addAll(mergeDate(projectIntervals));
        }
        return mergedIntervals;
    }
    
    public static List<ProjectDateRangeProps> mergeDate(List<ProjectDateRangeProps> singleProjectScoreCycles) {
        if (CollUtil.isEmpty(singleProjectScoreCycles)) {
            return Collections.emptyList();
        }

        // 对区间进行排序
        singleProjectScoreCycles.sort(Comparator.comparing(ProjectDateRangeProps::getStartDate));

        List<ProjectDateRangeProps> mergedIntervals = new ArrayList<>();
        ProjectDateRangeProps current = singleProjectScoreCycles.get(0);

        for (int i = 1; i < singleProjectScoreCycles.size(); i++) {
            ProjectDateRangeProps next = singleProjectScoreCycles.get(i);
            Calendar nextStartCal = Calendar.getInstance();
            nextStartCal.setTime(next.getStartDate());
            Calendar currentEndCal = Calendar.getInstance();
            currentEndCal.setTime(current.getEndDate());
            currentEndCal.add(Calendar.DAY_OF_YEAR, 1);

            // 比较日期
            if (!nextStartCal.after(currentEndCal)) {
                Calendar currentEndCalForCompare = Calendar.getInstance();
                currentEndCalForCompare.setTime(current.getEndDate());
                Calendar nextEndCal = Calendar.getInstance();
                nextEndCal.setTime(next.getEndDate());
                Date newEndDate = currentEndCalForCompare.after(nextEndCal) ? current.getEndDate() : next.getEndDate();
                current.setEndDate(newEndDate);
            } else {
                mergedIntervals.add(current);
                current = next;
            }
        }
        mergedIntervals.add(current);
        return mergedIntervals;
    }


    /**
     * 合并日期间隔
     *
     * @param dateRangeProps 日期范围道具
     * @return {@link List<DateRangeProps>}
     */
    public static List<DateRangeProps> mergeIntervals(List<DateRangeProps> dateRangeProps) {
        if (CollUtil.isEmpty(dateRangeProps)) {
            return Collections.emptyList();
        }

        // 对区间进行排序
        dateRangeProps.sort(Comparator.comparing(DateRangeProps::getStartDate));

        List<DateRangeProps> mergedIntervals = new ArrayList<>();
        DateRangeProps current = dateRangeProps.get(0);

        for (int i = 1; i < dateRangeProps.size(); i++) {
            DateRangeProps next = dateRangeProps.get(i);
            Calendar nextStartCal = Calendar.getInstance();
            nextStartCal.setTime(next.getStartDate());
            Calendar currentEndCal = Calendar.getInstance();
            currentEndCal.setTime(current.getEndDate());
            currentEndCal.add(Calendar.DAY_OF_YEAR, 1);

            // 比较日期
            if (!nextStartCal.after(currentEndCal)) {
                Calendar currentEndCalForCompare = Calendar.getInstance();
                currentEndCalForCompare.setTime(current.getEndDate());
                Calendar nextEndCal = Calendar.getInstance();
                nextEndCal.setTime(next.getEndDate());
                Date newEndDate = currentEndCalForCompare.after(nextEndCal) ? current.getEndDate() : next.getEndDate();
                current.setEndDate(newEndDate);
            } else {
                mergedIntervals.add(current);
                current = next;
            }
        }
        mergedIntervals.add(current);
        return mergedIntervals;
    }

    /**
     * 获取当天(整天 00:00:00) 的时间戳
     * @param localDate
     * @return
     */
    public static long getTimestamp(LocalDate localDate) {
        return localDate.atStartOfDay(ZoneOffset.UTC).toInstant().toEpochMilli() / CommonConsts.ONE_DAY_IN_MILLIS * CommonConsts.ONE_DAY_IN_MILLIS;
    }
    
    /**
     * 获取当天(整天 00:00:00) 的时间戳
     * @param timestamp
     * @return
     */
    public static long getTimestamp(Long timestamp) {
        return timestamp / CommonConsts.ONE_DAY_IN_MILLIS * CommonConsts.ONE_DAY_IN_MILLIS;
    }

}



 public static void main(String[] args) {
        log.info("[会议管理]:WEEKLY:days");
        LocalDate startDate = LocalDate.of(2024, 10, 1);
        LocalDate endDate = LocalDate.of(2024, 12, 27);
        List<DayRange> excludedDayRanges = new ArrayList<>();
        DayRange dayRange2 = new DayRange();
        dayRange2.setStartDate(LocalDate.of(2024, 10, 1));
        dayRange2.setEndDate(LocalDate.of(2024, 10, 7));
        excludedDayRanges.add(dayRange2);
        DayRange dayRange = new DayRange();
        dayRange.setStartDate(LocalDate.of(2024,10,15));
        dayRange.setEndDate(LocalDate.of(2024, 10, 28));
        excludedDayRanges.add(dayRange);
        DayRange dayRange1 = new DayRange();
        dayRange1.setStartDate(LocalDate.of(2024, 11, 5));
        dayRange1.setEndDate(LocalDate.of(2024, 12, 23));
        excludedDayRanges.add(dayRange1);
        
        List<LocalDate> dateList = DateUtils.excludeHolidays(startDate, endDate, excludedDayRanges);
        log.info("[会议管理]:WEEKLY:排除后的时间:{}", dateList);
        List<List<LocalDate>> days = DateUtils.calculateWeeksInPeriodByDay(dateList, CommonConsts.MIN_DAYS_IN_WEEK);
        log.info("[会议管理]:WEEKLY:按周过滤的时间区间:{}", days);
    } 
    ````  

Q.E.D.


夜阑卧听风吹雨,铁马冰河入梦来。