package jnpf.util;

import cn.hutool.core.collection.CollUtil;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoField;
import java.time.temporal.ChronoUnit;
import java.time.temporal.Temporal;
import java.util.*;

/**
 * 日期详情
 *
 * @author yanwenfu
 * @create 2021-02-26
 */
@Getter
@Setter
@ToString
@Slf4j
public class DateDetail {

    /** 最大提醒时间 */
    public static final Integer MAX_REMIND = 30;
    /**
     * 年
     */
    private int year;

    /**
     * 季
     */
    private int season;

    /**
     * 月
     */
    private int month;

    /**
     * 自然周
     */
    private int week;

    /**
     * 天
     */
    private int day;

    /**
     * 小时(24)
     */
    private int hour;

    private Calendar cal = Calendar.getInstance();

    private SimpleDateFormat sf = new SimpleDateFormat(DATE_FORMAT_YYYY_MM_DD);

    public static final int MIN_MONTH = 1;

    public static final int MAX_MONTH = 12;

    public static final int MIN_WEEK = 1;

    /**
     * 第1季度结束
     */
    public static final int SEASON_1_END = 3;
    /**
     * 第2季度结束
     */
    public static final int SEASON_2_END = 6;
    /**
     * 第3季度结束
     */
    public static final int SEASON_3_END = 9;
    /**
     * 第4季度结束
     */
    public static final int SEASON_4_END = 12;

    public static final String YEAR_STR = "year";
    public static final String SEASON_STR = "season";
    public static final String MONTH_STR = "month";
    public static final String WEEK_STR = "week";
    public static final String DAY_STR = "day";

    /**
     * 系统默认时区
     */
    public static final ZoneId ZONE_ID = ZoneId.systemDefault();
    /**
     * yyyy-MM-dd
     */
    public static final DateTimeFormatter DF = DateTimeFormatter.ofPattern("yyyy-MM-dd");
    /**
     * M.d
     */
    public static final DateTimeFormatter MD = DateTimeFormatter.ofPattern("M.d");
    /**
     * yyyy-MM-dd HH:mm:00
     */
    public static final DateTimeFormatter DF2 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:00");
    /**
     * yyyy/MM
     */
    public static final DateTimeFormatter DF3 = DateTimeFormatter.ofPattern("yyyy/MM");
    /**
     * yyyy-MM-dd HH:mm:ss
     */
    public static final DateTimeFormatter DF4 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
    /**
     * yyyyMMddHH
     */
    public static final DateTimeFormatter DF5 = DateTimeFormatter.ofPattern("yyyyMMddHH");
    /**
     * yyyyMMdd
     */
    public static final DateTimeFormatter DF6 = DateTimeFormatter.ofPattern("yyyyMMdd");
    /**
     * MM-dd
     */
    public static final DateTimeFormatter DF7 = DateTimeFormatter.ofPattern("MM-dd");
    /**
     * yyyy-M-d
     */
    public static final DateTimeFormatter DF8 = DateTimeFormatter.ofPattern("yyyy-M-d");
    /**
     * yyyy-MM-dd HH:mm
     */
    public static final DateTimeFormatter DF9 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
    /**
     * HH:mm
     */
    public static final DateTimeFormatter DF10 = DateTimeFormatter.ofPattern("HH:mm");
    /**
     * yyyy/MM/dd
     */
    public static final DateTimeFormatter DF11 = DateTimeFormatter.ofPattern("yyyy/MM/dd");
    /**
     * yyyy年MM月dd日
     */
    public static final DateTimeFormatter DF12 = DateTimeFormatter.ofPattern("yyyy年MM月dd日");
    /**
     * yyyyMMdd.HHmmss
     */
    public static final DateTimeFormatter DF13 = DateTimeFormatter.ofPattern("yyyyMMdd.HHmmss");
    /**
     * yyyyMMdd.000000
     */
    public static final DateTimeFormatter DF14 = DateTimeFormatter.ofPattern("yyyyMMdd.000000");
    /**
     * yyyy-MM
     */
    public static final DateTimeFormatter DF15 = DateTimeFormatter.ofPattern("yyyy-MM");
    /**
     * yyyy-MM-dd 00:00:00
     */
    public static final DateTimeFormatter DF16 = DateTimeFormatter.ofPattern("yyyy-MM-dd 00:00:00");
    /**
     * yyyy-MM-dd 23:59:59
     */
    public static final DateTimeFormatter DF17 = DateTimeFormatter.ofPattern("yyyy-MM-dd 23:59:59");
    /**
     * HH:mm:ss
     */
    public static final DateTimeFormatter DF18 = DateTimeFormatter.ofPattern("HH:mm:ss");
    /**
     * yyyy-MM-dd HH:mm:59
     */
    public static final DateTimeFormatter DF19 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:59");
    /**
     * yyyy年MM月dd日 HH:mm
     */
    public static final DateTimeFormatter DF20 = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH:mm");

    /**
     * 日期格式，年月日，用横杠分开，例如：2006-12-25，2008-08-08
     */
    public static final String DATE_FORMAT_YYYY_MM_DD = "yyyy-MM-dd";

    public static final SimpleDateFormat Y_M = new SimpleDateFormat("yyyy-MM");

    public DateDetail() {
        setValue(this.cal);
    }

    public DateDetail(Calendar cal) {
        this.cal = cal;
        setValue(cal);
    }

    public DateDetail(Date date) {
        changeDay(date);
    }

    public DateDetail(String dateStr) {
        Date date = DateDetail.getStr2DateTime(dateStr);
        changeDay(date);
    }

    public static String convert(int number) {
        //数字对应的汉字
        String[] num = {"一", "二", "三", "四", "五", "六", "七", "八", "九"};
        //单位
        String[] unit = {"", "十", "百", "千", "万", "十", "百", "千", "亿", "十", "百", "千", "万亿"};
        //将输入数字转换为字符串
        String result = String.valueOf(number);
        //将该字符串分割为数组存放
        char[] ch = result.toCharArray();
        //结果 字符串
        String str = "";
        int length = ch.length;
        for (int i = 0; i < length; i++) {
            int c = (int) ch[i] - 48;
            if (c != 0) {
                str += num[c - 1] + unit[length - i - 1];
            }
        }
        return str;
    }

    public static Date goToMaxSeconds(Date now) {

        String dateStr = getDate2Str(now, DF19);
        return getStr2DateTime(dateStr);
    }

    public static Long getBetweenWeeks(Temporal begin, Temporal end) {
        if (begin.getLong(ChronoField.EPOCH_DAY) > end.getLong(ChronoField.EPOCH_DAY)) return 0L;

        if (end.getLong(ChronoField.EPOCH_DAY) - begin.getLong(ChronoField.EPOCH_DAY) < 0) {
            Temporal temp = begin;
            begin = end;
            end = temp;
        }
        int beginWeekDay = begin.get(ChronoField.DAY_OF_WEEK);
        long daysBetween = Math.abs(ChronoUnit.DAYS.between(begin, end));
        long weeksBetween = daysBetween / 7;
        int offset = (daysBetween % 7 + beginWeekDay) > 7 ? 1 : 0;
        //不算本周
        return offset + weeksBetween;
    }

    public static Date getDateWithOutTime(Date date) {

        if (null == date) {
            return null;
        }
        String d1 = getDate2Str(date, DF);
        return getStr2Date(d1);
    }

    /**
     * 小时
     *
     * @param minutes 分钟数
     * @return java.math.BigDecimal
     */
    public static BigDecimal changeMinuteToHour(Integer minutes) {

        BigDecimal b1 = new BigDecimal(minutes);
        return b1.divide(new BigDecimal("60"), 1, RoundingMode.DOWN);
    }

    /**
     * 转换分钟为天
     *
     * @param minutes 分钟数
     * @return java.math.BigDecimal
     */
    public static BigDecimal changeMinuteToDay(Integer minutes) {

        BigDecimal b1 = new BigDecimal(minutes);
        int num = 60 * 24;
        return b1.divide(new BigDecimal(Integer.toString(num)), 1, RoundingMode.DOWN);
    }

    /**
     * 获取日期段内每一天的日期(String)
     *
     * @param startDay 开始日期
     * @param endDay   结束日期
     * @return com.shs.cts.util.domain.vo.performance.DateStrVo
     */
    public static DateStrVo getDateStr(Date startDay, Date endDay) {

        DateStrVo dateStrVo = new DateStrVo();
        try {
            SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd");
            Date start = sf.parse(sf.format(startDay));
            Date end = sf.parse(sf.format(endDay));
            Calendar cal1 = Calendar.getInstance();
            cal1.setTime(start);
            Calendar cal2 = Calendar.getInstance();
            cal2.setTime(end);
            while (true) {
                String format = sf.format(cal1.getTime());
                dateStrVo.getUseList().add(format);
                if (cal1.compareTo(cal2) == 0) {
                    break;
                } else {
                    cal1.add(Calendar.DATE, 1);
                }
            }
            String lastMonth = "";
            for (int i = 0; i < dateStrVo.getUseList().size(); i++) {
                String str = dateStrVo.getUseList().get(i);
                String[] split = str.split("-");
                if (i == 0) {
                    lastMonth = split[1];
                    String sub = str.substring(5);
                    dateStrVo.getShowList().add(sub);
                } else {
                    String sub;
                    if (lastMonth.equals(split[1])) {
                        sub = str.substring(8);
                    } else {
                        sub = str.substring(5);
                        lastMonth = split[1];
                    }
                    dateStrVo.getShowList().add(sub);
                }
            }
        } catch (Exception e) {
            log.error("getDateStr - 日期转换异常");
        }
        return dateStrVo;
    }

    /**
     * 返回当前日期是星期几
     *
     * @param date 日期
     * @return int
     */
    public static int getDayOfWeek(Date date) {

        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        int index = cal.get(Calendar.DAY_OF_WEEK);
        switch (index) {
            case 2:
                return 0;
            case 3:
                return 1;
            case 4:
                return 2;
            case 5:
                return 3;
            case 6:
                return 4;
            case 7:
                return 5;
            case 1:
                return 6;
            default:
                return -1;
        }
    }

    /**
     * 判断是否同一天
     *
     * @param day1 日期1
     * @param day2 日期2
     * @return boolean
     */
    public static boolean checkSameDay(Date day1, Date day2) {

        if (null == day1 || null == day2) {
            return false;
        }
        return getDate2Str(day1, DF).equals(getDate2Str(day2, DF));
    }

    public static Date getMonthBeginDate(Date date) {

        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.set(Calendar.DATE, 1);
        String dateStr = getDate2Str(cal.getTime(), DF16);
        return getStr2DateTime(dateStr);
    }

    public static Date getMonthBeginDate(String month) {
        String[] split = month.split("-");
        Calendar cal = Calendar.getInstance();
        cal.set(Calendar.YEAR, Integer.valueOf(split[0]));
        cal.set(Calendar.MONTH, Integer.valueOf(split[1]) - 1);
        cal.set(Calendar.DATE, 1);
        String dateStr = getDate2Str(cal.getTime(), DF16);
        return getStr2DateTime(dateStr);
    }

    public static Date getMonthEndDate(String month) {
        String[] split = month.split("-");
        Calendar cal = Calendar.getInstance();
        cal.set(Calendar.YEAR, Integer.valueOf(split[0]));
        cal.set(Calendar.MONTH, Integer.valueOf(split[1]));
        cal.set(Calendar.DAY_OF_MONTH, 0);
        String dateStr = getDate2Str(cal.getTime(), DF17);
        return getStr2DateTime(dateStr);
    }

    public static Integer getMonthEndDayNum(Date date) {
        String format = new SimpleDateFormat("yyyy-MM").format(date);
        String[] split = format.split("-");
        Calendar cal = Calendar.getInstance();
        cal.set(Calendar.YEAR, Integer.valueOf(split[0]));
        cal.set(Calendar.MONTH, Integer.valueOf(split[1]));
        cal.set(Calendar.DAY_OF_MONTH, 0);
        String dateStr = getDate2Str(cal.getTime(), DF17);
        return getMonthEndDayNum(dateStr);
    }

    public static Integer getMonthEndDayNum(String str) {

        if (null == str) {
            return null;
        }
        // 获取年月日
        String s = str.split(" ")[0];
        // 获取对应日期
        String day = s.split("-")[2];
        Integer dayNum = Integer.valueOf(day);
        System.out.println(day);

        return dayNum;
    }

    public static Date getMonthEndDate(Date date) {

        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.add(Calendar.MONTH, 1);
        cal.set(Calendar.DATE, 0);
        String dateStr = getDate2Str(cal.getTime(), DF17);
        return getStr2DateTime(dateStr);
    }

    public static Date beginOfDay(Date date) {
        String date2Str = getDate2Str(date, DF16);
        return getStr2DateTime(date2Str);
    }

    public static Date endOfDay(Date date) {
        String date2Str = getDate2Str(date, DF17);
        return getStr2DateTime(date2Str);
    }

    public static String getChineseNum(Integer num) {

        switch (num) {
            case 1:
                return "一";
            case 2:
                return "二";
            case 3:
                return "三";
            case 4:
                return "四";
            case 5:
                return "五";
            case 6:
                return "六";
            case 7:
                return "七";
            default:
                return "";
        }
    }

    /**
     * 判断两个日期的月份是否相同
     * @param date1 日期1
     * @param date2 日期2
     * @return boolean
     */
    public static boolean checkSameMonth(Date date1, Date date2) {
        String str1 = DateDetail.getDate2Str(date1, DF);
        String str2 = DateDetail.getDate2Str(date2, DF);
        return str1.split("-")[1].equals(str2.split("-")[1]);
    }

    public Date getNextDate(Integer nextWeek) {

        int week = getCurrentWeek(this.cal.getTime());
        while (week != nextWeek) {
            getTomorrow();
            week = getCurrentWeek(this.cal.getTime());
        }
        getYesterday();
        return this.cal.getTime();
    }

    public static int getCurrentWeekNumber(Date time) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(time);
        int week = cal.get(Calendar.DAY_OF_WEEK);
        switch (week) {
            case Calendar.MONDAY:
                return 1;
            case Calendar.TUESDAY:
                return 2;
            case Calendar.WEDNESDAY:
                return 3;
            case Calendar.THURSDAY:
                return 4;
            case Calendar.FRIDAY:
                return 5;
            case Calendar.SATURDAY:
                return 6;
            case Calendar.SUNDAY:
                return 7;
            default:
                return 0;
        }
    }

    private int getCurrentWeek(Date time) {

        Calendar cal = Calendar.getInstance();
        cal.setTime(time);
        int week = cal.get(Calendar.DAY_OF_WEEK);
        switch (week) {
            case Calendar.MONDAY:
                return 1;
            case Calendar.TUESDAY:
                return 2;
            case Calendar.WEDNESDAY:
                return 3;
            case Calendar.THURSDAY:
                return 4;
            case Calendar.FRIDAY:
                return 5;
            case Calendar.SATURDAY:
                return 6;
            case Calendar.SUNDAY:
                return 7;
            default:
                return 0;
        }
    }


    private void setValue(Calendar cal) {
        cal.setFirstDayOfWeek(Calendar.MONDAY);
        this.year = cal.get(Calendar.YEAR);
        this.month = cal.get(Calendar.MONTH) + 1;
        this.season = (int) Math.ceil((double) month / 3);
        this.week = cal.get(Calendar.WEEK_OF_YEAR);
        this.day = cal.get(Calendar.DATE);
        this.hour = cal.get(Calendar.HOUR_OF_DAY);
    }

    public void changeDay(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        this.cal = cal;
        setValue(cal);
    }

    /**
     * 根据日期和时间返回新的一天
     *
     * @param day  日期(取yyyy-MM-dd)
     * @param time 时间(取HH:mm)
     * @return java.util.Date
     */
    public Date changeDayWithDayAndTime(Date day, Date time) {

        String pre = getDate2Str(day, DF);
        String suf = getDate2Str(time, DF10) + ":00";
        return getStr2DateTime(pre + " " + suf);
    }

    /**
     * 根据时段的差值添加到新的时间上产生新的时间
     *
     * @param start  开始时间
     * @param end    结束时间
     * @param target 目标时间
     * @return
     */
    public static Date getNewDateByPeriod(Date start, Date end, Date target) {
        if (Objects.isNull(end)) {
            return null;
        }
        int i = calculateMinuteDiff(start, end);
        return DateUtil.dateAddMinutes(target, i);
    }

    /**
     * 变更日期
     *
     * @param date 日期
     * @param num  变更天数
     */
    public void changeDayByNum(Date date, Integer num) {

        changeDay(date);
        this.cal.add(Calendar.DATE, num);
        setValue(this.cal);
    }

    /**
     * 获取昨天
     */
    public void getYesterday() {

        this.cal.add(Calendar.DATE, -1);
        setValue(this.cal);
    }

    /**
     * 获取当前日期时间
     *
     * @return java.util.Date
     */
    public Date getCurrentDate() {

        return this.cal.getTime();
    }

    /**
     * 获取明天
     */
    public void getTomorrow() {

        this.cal.add(Calendar.DATE, 1);
        setValue(this.cal);
    }

    public static Date getNextDay(Date date) {

        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.add(Calendar.DATE, 1);
        return cal.getTime();
    }

    /**
     * 日期转换为yyyy-MM-dd
     *
     * @param date 日期
     * @return java.lang.String
     */
    public static String getDate2Str(Date date, DateTimeFormatter df) {
        if (null == date) {
            return "";
        }
        LocalDateTime localDateTime = date.toInstant().atZone(ZONE_ID).toLocalDateTime();
        return localDateTime.format(df);
    }

    /**
     * 日期转换为yyyy-MM-dd HH:mm:00
     *
     * @param date 日期
     * @return java.lang.String
     */
    public static String getDateTime2Str(Date date) {

        if (null == date) {
            return "";
        }
        LocalDateTime localDateTime = date.toInstant().atZone(ZONE_ID).toLocalDateTime();
        return localDateTime.format(DF2);
    }

    /**
     * 字符串转日期(yyyy-MM-dd HH:mm:ss)
     *
     * @param str 字符串日期
     * @return java.util.Date
     */
    public static Date getStr2DateTime(String str) {

        if (StringUtils.isEmpty(str)) {
            return null;
        }
        str = str.replace(" ", "T");
        LocalDateTime localDateTime = LocalDateTime.parse(str);
        return Date.from(localDateTime.atZone(ZONE_ID).toInstant());
    }

    public static Date getStr2Date(String str) {

        if (StringUtils.isEmpty(str)) {
            return null;
        }
        LocalDate localDate = LocalDate.parse(str, DF8);
        return Date.from(localDate.atStartOfDay(ZONE_ID).toInstant());
    }

    public static Date getMonthStr2Date(String str) {

        if (StringUtils.isEmpty(str)) {
            return null;
        }
        str = str + "-01 00:00:00";
        LocalDate localDate = LocalDate.parse(str, DF4);
        return Date.from(localDate.atStartOfDay(ZONE_ID).toInstant());
    }

    public static Date getStr2Date10(String str) {

        if (StringUtils.isEmpty(str)) {
            return null;
        }
        LocalDate localDate = LocalDate.parse(str, DF);
        return Date.from(localDate.atStartOfDay(ZONE_ID).toInstant());
    }

    /**
     * 获取季度列表
     *
     * @return java.util.List<java.lang.Integer>
     */
    public static List<Integer> getSeasonList() {
        List<Integer> list = new ArrayList<>();
        list.add(1);
        list.add(2);
        list.add(3);
        list.add(4);
        return list;
    }

    /**
     * 获取当前季度下的月份
     *
     * @param season 季度
     * @return java.util.List<java.lang.Integer>
     */
    public static List<Integer> getSeasonMonth(Integer season) {

        List<Integer> list = new ArrayList<>();
        switch (season) {
            case 1:
                list.add(1);
                list.add(2);
                list.add(3);
                break;
            case 2:
                list.add(4);
                list.add(5);
                list.add(6);
                break;
            case 3:
                list.add(7);
                list.add(8);
                list.add(9);
                break;
            case 4:
                list.add(10);
                list.add(11);
                list.add(12);
                break;
            default:
                break;
        }
        return list;
    }

    /**
     * 传入年和月，获取到本月的第一天：
     *
     * @param year  年
     * @param month 月
     * @return Date
     */
    public String getFirstDayOfMonth(int year, int month) {
        Calendar cal = Calendar.getInstance();
        //设置年份
        cal.set(Calendar.YEAR, year);
        //设置月份
        cal.set(Calendar.MONTH, month - 1);
        //获取某月最小天数
        int firstDay = cal.getMinimum(Calendar.DATE);
        //设置日历中月份的最小天数
        cal.set(Calendar.DAY_OF_MONTH, firstDay);
        //格式化日期
        SimpleDateFormat sdf = new SimpleDateFormat(DATE_FORMAT_YYYY_MM_DD);
        return sdf.format(cal.getTime());
    }

    /**
     * 传入年和月，获取到本月的最后一天
     *
     * @param year  年
     * @param month 月
     * @return java.lang.String
     */
    public String getLastDayOfMonth(int year, int month) {
        //获取某月最大天数
        int lastDay = getLastDateOfMonth(year, month);
        //设置日历中月份的最大天数
        this.cal.set(Calendar.DAY_OF_MONTH, lastDay);
        //格式化日期
        SimpleDateFormat sdf = new SimpleDateFormat(DATE_FORMAT_YYYY_MM_DD);
        return sdf.format(cal.getTime());
    }

    /**
     * 通过传入的年月，获取结束时间
     * 当传入日期是本月时返回今天的年月日，当不等于本月时返回月末最后一天的日期
     * @param yearMonthStr 年月
     */
    public  String getCutoffDate(String yearMonthStr) {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM");
        DateTimeFormatter day = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        YearMonth yearMonth = YearMonth.parse(yearMonthStr, formatter);

        LocalDate today = LocalDate.now();
        YearMonth currentYearMonth = YearMonth.from(today);

        if (yearMonth.equals(currentYearMonth)) {
            return day.format(today);
        } else {
            return day.format(yearMonth.atEndOfMonth());
        }
    }

    public static String getPreviousYear(String year) {
        LocalDate localDate = LocalDate.parse(year + "-01-01 00:00:00", DF4);
        Date from = Date.from(localDate.atStartOfDay(ZONE_ID).toInstant());
        return new SimpleDateFormat("yyyy").format(DateUtil.dateAddYears(from, -1));
    }

    /**
     * 获取本月最大天数
     *
     * @param year  年
     * @param month 月
     * @return int
     */
    public int getLastDateOfMonth(int year, int month) {

        //设置年份
        this.cal.set(Calendar.YEAR, year);
        //设置月份
        this.cal.set(Calendar.MONTH, month - 1);
        // 设置日期
        this.cal.set(Calendar.DATE, 1);
        return this.cal.getActualMaximum(Calendar.DATE);
    }

    /**
     * 一周所有天
     *
     * @param
     * @return
     */
    public List<String> getFixedWeek() {
        List<String> fixedWeek = new ArrayList<>();
        fixedWeek.add("周一");
        fixedWeek.add("周二");
        fixedWeek.add("周三");
        fixedWeek.add("周四");
        fixedWeek.add("周五");
        fixedWeek.add("周六");
        fixedWeek.add("周日");
        return fixedWeek;
    }

    /**
     * 一月所有天
     *
     * @param day
     * @return
     */
    public List<String> getFixedMonth(Integer day) {
        ArrayList<String> fixedMonth = new ArrayList<>();
        for (int i = 1; i <= day; i++) {
            fixedMonth.add(i + "");
        }
        return fixedMonth;
    }

    /**
     * 一年的所有月
     *
     * @param
     * @return
     */
    public List<String> getFixedYear() {
        List<String> fixedYear = new ArrayList<>();
        fixedYear.add("一月");
        fixedYear.add("二月");
        fixedYear.add("三月");
        fixedYear.add("四月");
        fixedYear.add("五月");
        fixedYear.add("六月");
        fixedYear.add("七月");
        fixedYear.add("八月");
        fixedYear.add("九月");
        fixedYear.add("十月");
        fixedYear.add("十一月");
        fixedYear.add("十二月");
        return fixedYear;
    }

    /**
     * 当前所在周之前的共八个周
     *
     * @param
     * @return
     */
    public List<String> getWeekList() {
        List<String> fixedYear = new ArrayList<>();
        DateDetail dateDetail = new DateDetail();
        //得到当前周
        int week = dateDetail.getWeek();
        if (week - 7 < 0) {
            //得到上一年的最后一周
            int count = getLastWeek(dateDetail);
            int num = 7 - week;
            for (int i = count - num; i <= count; i++) {
                fixedYear.add("第" + i + "周");
            }
            for (int i = 1; i <= week; i++) {
                fixedYear.add("第" + i + "周");
            }
        } else {
            for (int i = week - 7; i <= week; i++) {
                fixedYear.add("第" + i + "周");
            }
        }
        return fixedYear;
    }

    private int getLastWeek(DateDetail dateDetail) {
        //得到上一年的最后一周
        Calendar c = new GregorianCalendar();
        c.set(dateDetail.getYear() - 1, Calendar.DECEMBER, 31, 23, 59, 59);
        return getWeekthOfYear(c.getTime());
    }

    /**
     * 获取当前日期是一年中第几周
     *
     * @param date
     * @return
     */
    public static Integer getWeekthOfYear(Date date) {
        Calendar c = new GregorianCalendar();
        c.setFirstDayOfWeek(Calendar.MONDAY);
        c.setMinimalDaysInFirstWeek(7);
        c.setTime(date);

        return c.get(Calendar.WEEK_OF_YEAR);
    }

    /**
     * 一年十二个月
     *
     * @param
     * @return
     */
    public List<String> getFixedYearNum() {
        List<String> fixedYear = new ArrayList<>();
        fixedYear.add("01");
        fixedYear.add("02");
        fixedYear.add("03");
        fixedYear.add("04");
        fixedYear.add("05");
        fixedYear.add("06");
        fixedYear.add("07");
        fixedYear.add("08");
        fixedYear.add("09");
        fixedYear.add("10");
        fixedYear.add("11");
        fixedYear.add("12");
        return fixedYear;
    }

    public List<String> getDays(String startDay, String endDay) {
        List<String> days = new ArrayList<>();
        Date startDate = null;
        Date endDate = null;
        try {
            startDate = sf.parse(startDay);
            endDate = sf.parse(endDay);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        Calendar calendar = Calendar.getInstance();
        if (startDate == null || endDate == null) {
            return new ArrayList<>();
        }
        calendar.setTime(startDate);
        while (calendar.getTime().getTime() <= endDate.getTime()) {
            days.add(sf.format(calendar.getTime()));
            calendar.add(Calendar.DAY_OF_MONTH, 1);
        }
        return days;
    }

    public static int getWeekByDate(String yearMonthDay) {

        SimpleDateFormat format = new SimpleDateFormat(DATE_FORMAT_YYYY_MM_DD);
        Calendar c = Calendar.getInstance();
        try {
            c.setTime(format.parse(yearMonthDay));
        } catch (ParseException e) {
            e.printStackTrace();
        }
        int dayForWeek;
        if (c.get(Calendar.DAY_OF_WEEK) == 1) {
            dayForWeek = 7;
        } else {
            dayForWeek = c.get(Calendar.DAY_OF_WEEK) - 1;
        }
        return dayForWeek;
    }

    /**
     * 通过年月日返回属于周几
     *
     * @param yearMonthDay
     * @return
     */
    public int getWeekNum(String yearMonthDay) {

        return getWeekByDate(yearMonthDay);
    }

    /**
     * 通过传入的年月日 返回属于第几周
     *
     * @param yearMonthDay 日期
     * @return int
     */
    public int getWeeks(String yearMonthDay) {
        SimpleDateFormat format = new SimpleDateFormat(DATE_FORMAT_YYYY_MM_DD);
        Date date = null;
        try {
            date = format.parse(yearMonthDay);
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.setFirstDayOfWeek(Calendar.MONDAY);
        int currentWeek = calendar.get(Calendar.WEEK_OF_YEAR);
        int month = calendar.get(Calendar.MONTH) + 1;
        if (month == MAX_MONTH && currentWeek == MIN_WEEK) {
            calendar.add(Calendar.WEEK_OF_YEAR, -1);
            return calendar.get(Calendar.WEEK_OF_YEAR) + 1;
        }
        return calendar.get(Calendar.WEEK_OF_YEAR);
    }

    /**
     * 某个日期加上几个月后的日期
     *
     * @param startDay 日期
     * @param num      加上的月份
     * @return
     */
    public String getDayDate(String startDay, Integer num) {
        // 获得一个日历的实例
        Calendar c = Calendar.getInstance();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        Date date = null;
        try {
            // 初始日期
            date = sdf.parse(startDay);
        } catch (Exception e) {
        }
        // 设置日历时间
        c.setTime(date);
        c.add(Calendar.MONTH, num);
        return sdf.format(c.getTime());
    }

    /**
     * 某个日期加上多少天后的年月日
     *
     * @param startDay 开始时间
     * @param num      天数
     * @return
     */
    public String getDate(String startDay, Integer num) {
        // 获得一个日历的实例
        Calendar c = Calendar.getInstance();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        Date date = null;
        try {
            // 初始日期
            date = sdf.parse(startDay);
        } catch (Exception e) {
        }
        // 设置日历时间
        c.setTime(date);
        c.add(Calendar.DAY_OF_MONTH, num);
        return sdf.format(c.getTime());
    }

    /**
     * 获取当年剩余的月份
     *
     * @param month 当前月
     * @return java.util.List<java.lang.Integer>
     */
    public static List<Integer> getSurplusMonth(Integer month) {

        List<Integer> list = new ArrayList<>();
        if (null == month) {
            month = 1;
        }
        if (month < 0) {
            month = 1;
        }
        if (month > MAX_MONTH) {
            month = 12;
        }
        for (int i = month; i <= MAX_MONTH; i++) {
            list.add(i);
        }
        return list;
    }

    public int getLastWeekOfYear(String year) {

        String day = year + "-12-31";
        Date date = DateDetail.getStr2Date(day);
        this.cal.setTime(date);
        this.cal.setFirstDayOfWeek(Calendar.MONDAY);
        int currentWeek = this.cal.get(Calendar.WEEK_OF_YEAR);
        int month = this.cal.get(Calendar.MONTH) + 1;
        if (month == DateDetail.MAX_MONTH && currentWeek == DateDetail.MIN_WEEK) {
            this.cal.add(Calendar.WEEK_OF_YEAR, -1);
            currentWeek = this.cal.get(Calendar.WEEK_OF_YEAR) + 1;
        }
        return currentWeek;
    }

    public static List<Date> getAllDays(Date startTime, Date endTime) {
        List<Date> listDay = new ArrayList();
        new Date();

        for(Date dtDay = startTime; dtDay.compareTo(endTime) <= 0; dtDay = dateAddDays(dtDay, 1)) {
            listDay.add(dtDay);
        }

        return listDay;
    }

    public static Date dateAddDays(Date startDate, int days) {
        if (startDate == null) {
            startDate = new Date();
        }

        Calendar c = Calendar.getInstance();
        c.setTime(startDate);
        c.set(5, c.get(5) + days);
        return c.getTime();
    }

    /**
     * 获取两个时间段之间的交集日期集合
     * @param start1Date 开始时间1
     * @param end1Date 结束时间1
     * @param start2Date 开始时间2
     * @param end2Date 结束时间2
     */
    public static List<String> getDateIntersection(Date start1Date, Date end1Date, Date start2Date, Date end2Date) {
        LocalDate start1 = start1Date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
        LocalDate end1 = end1Date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
        LocalDate start2 = start2Date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
        LocalDate end2 = end2Date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
        List<String> intersection = new ArrayList<>();
        LocalDate intersectionStart;
        LocalDate intersectionEnd;
        // 找到交集的起始和结束日期
        int startCompare = start1.compareTo(start2);
        if (startCompare > 0){
            intersectionStart = start1;
        }else if (startCompare == 0){
            intersectionStart = start1;
        }else {
            intersectionStart = start2;
        }

        int endCompare = end1.compareTo(end2);
        if (endCompare > 0){
            intersectionEnd = end2;
        }else if (endCompare == 0){
            intersectionEnd = end1;
        }else {
            intersectionEnd = end1;
        }
        // 添加交集内的所有日期到列表中
        while (!intersectionStart.isAfter(intersectionEnd)) {
            intersection.add(intersectionStart.toString());
            intersectionStart = intersectionStart.plusDays(1);
        }
        return intersection;
    }
    /**
     * 获取两个时间段之间的年月
     *
     * @param beginDateStr 开始时间(yyyy/MM/dd)
     * @param endDateStr   结束时间(yyyy/MM/dd)
     * @return java.util.List<java.lang.String>
     */
    public static List<String> getMonthBetweenTwoDate(String beginDateStr, String endDateStr) throws Exception {

        List<String> list = new ArrayList<>();
        Date beginDate = getStr2Date(beginDateStr.replaceAll("/", "-"));
        Date endDate = getStr2Date(endDateStr.replaceAll("/", "-"));
        // 日期格式化失败
        if (null == beginDate || null == endDate) {
            throw new Exception("日期转换异常");
        }
        // 位置调换
        if (endDate.before(beginDate)) {
            Date tempDate = beginDate;
            beginDate = endDate;
            endDate = tempDate;
        }
        Calendar beginCal = Calendar.getInstance();
        beginCal.setTime(beginDate);
        Calendar endCal = Calendar.getInstance();
        endCal.setTime(endDate);
        int endYear = endCal.get(Calendar.YEAR);
        int endMonth = endCal.get(Calendar.MONTH) + 1;
        // 开始获取yyyy年-M月
        while (true) {
            int beginYear = beginCal.get(Calendar.YEAR);
            int beginMonth = beginCal.get(Calendar.MONTH) + 1;
            list.add(beginYear + "年" + "-" + beginMonth + "月");
            if (beginYear == endYear && beginMonth == endMonth) {
                break;
            } else {
                beginCal.add(Calendar.MONTH, 1);
            }
        }
        return list;
    }

    /**
     * 日期 + 分钟数
     *
     * @param date      日期
     * @param addMinute 添加分钟数
     * @return java.util.Date
     */
    public Date addMinute(Date date, Integer addMinute) {

        this.cal.setTime(date);
        this.cal.add(Calendar.MINUTE, addMinute);
        return this.cal.getTime();
    }

    public Date addNum(Date date, Integer num, int unit) {

        if (null != date) {
            this.cal.setTime(date);
        }
        this.cal.add(unit, num);
        return this.cal.getTime();
    }

    /**
     * 设置日期秒数
     *
     * @param date    日期
     * @param seconds 设置秒数
     * @return java.util.Date
     */
    public Date setSecond(Date date, Integer seconds) {

        this.cal.setTime(date);
        this.cal.set(Calendar.SECOND, seconds);
        return this.cal.getTime();
    }

    /**
     * 计算日期之间的分钟差(d2 -  d1)
     *
     * @param d1 日期1
     * @param d2 日期2
     * @return int
     */
    public static int calculateMinuteDiff(Date d1, Date d2) {
        long minutes = ChronoUnit.MINUTES.between(Instant.ofEpochMilli(d1.getTime()), Instant.ofEpochMilli(d2.getTime()));
        return (int) minutes;
    }

    public static int calculateSecondDiff(Date d1, Date d2) {
        long seconds = ChronoUnit.SECONDS.between(Instant.ofEpochMilli(d1.getTime()), Instant.ofEpochMilli(d2.getTime()));
        return (int) seconds;
    }

    public static int calculateDayDiff(LocalDate d1, LocalDate d2) {
        if (d1 == null || d2 == null) {
            return 0;
        }
        return (int) ChronoUnit.DAYS.between(d1, d2);
    }

    /**
     * 判断时间是否在区间内
     *
     * @param currentTime 当前时间
     * @param beginTime   开始时间
     * @param endTime     结束时间
     * @return boolean
     */
    public static boolean checkTimeBetween(Date currentTime, Date beginTime, Date endTime) {

        if (currentTime.equals(beginTime) || currentTime.equals(endTime)) {
            return true;
        }
        return currentTime.after(beginTime) && currentTime.before(endTime);
    }
    /**
     * 判断时间是否在区间内
     *
     * @param currentTime 当前时间
     * @param beginTime   开始时间
     * @param endTime     结束时间
     * @return boolean
     */
    public static boolean checkTimeBetweenL(Date currentTime, Date beginTime, Date endTime) {

        if (currentTime.equals(beginTime)) {
            return true;
        }
        return currentTime.after(beginTime) && currentTime.before(endTime);
    }
    /**
     * 判断时间是否在区间内
     *
     * @param currentTime 当前时间
     * @param beginTime   开始时间
     * @param endTime     结束时间
     * @return boolean
     */
    public static boolean checkTimeBetweenR(Date currentTime, Date beginTime, Date endTime) {

        if (currentTime.equals(endTime)) {
            return true;
        }
        return currentTime.after(beginTime) && currentTime.before(endTime);
    }
    public static boolean checkBetween(Date currentTime, Date beginTime, Date endTime) {
        return currentTime.after(beginTime) && currentTime.before(endTime);
    }

    public Date changeDate(Date now, int day) {

        changeDay(now);
        int maxDay = getLastDateOfMonth(this.year, this.month);
        if (day > maxDay) {
            day = maxDay;
        }
        this.cal.set(Calendar.DATE, day);
        return getCurrentDate();
    }

    /**
     * 变更月份与号数
     *
     * @param now 日期
     * @param num 月份增减量
     * @param day 号数设置
     * @return java.util.Date
     */
    public Date changeMonthAndDate(Date now, int num, Integer day) {

        changeDay(now);
        this.cal.add(Calendar.MONTH, num);
        return changeDate(getCurrentDate(), day);
    }

    /**
     * @param date  当日时间
     * @param point 时间点
     * @return
     */

    public static Date getDateByPoint(Date date, String point, Integer type) {
        if (StringUtil.isBlank(point)) {
            return null;
        }
        String date2Str = DateDetail.getDate2Str(date, DateDetail.DF);
        DateDetail dateDetail = new DateDetail(date2Str + " " + point + ":00");
        if (Objects.equals(type,2)) {
            dateDetail.getTomorrow();
        }
        return dateDetail.getCurrentDate();
    }

    public static Date getDateByMonthAndDay(Date date, Integer month, Integer day) {
        Date date1 = new Date();
        date1.setYear(date.getYear());
        date1.setMonth(month - 1);
        date1.setDate(day);
        return cn.hutool.core.date.DateUtil.beginOfDay(date1);
    }

    /**
     * @param dayOfWeek
     * @return: java.util.Date
     * @decription 输入数值星期值返回开始时间
     * @date 2024/5/16 17:26
     */
    public static Date getStartTimeOfDay(int dayOfWeek) {
        if (dayOfWeek < 1 || dayOfWeek > 7) {
            throw new IllegalArgumentException("Invalid day of week: " + dayOfWeek);
        }
        LocalDate today = LocalDate.now();
        LocalDate targetDate = today.with(DayOfWeek.of(dayOfWeek));
        LocalDateTime startOfDay = targetDate.atStartOfDay();
        return Date.from(startOfDay.atZone(ZoneId.systemDefault()).toInstant());
    }

    /**
     * @param date
     * @param timeString
     * @return: java.util.Date
     * @decription 合并年月日和时分秒
     * @date 2024/5/16 17:31
     */
    public static Date combineDateAndTime(Date date, String timeString) {
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
        SimpleDateFormat timeFormat = new SimpleDateFormat("HH:mm");
        SimpleDateFormat resultFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

        try {
            // 将输入的 Date 转换为日期字符串
            String dateString = dateFormat.format(date);

            // 将给定的时间字符串解析为时间对象
            Date time = timeFormat.parse(timeString);

            // 将日期和时间分别格式化为字符串
            String formattedTime = timeFormat.format(time);

            // 将日期字符串和时间字符串合并为一个完整的日期时间字符串
            String combinedDateTimeString = dateString + " " + formattedTime + ":00";

            return resultFormat.parse(combinedDateTimeString);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * @param dayOfMonth
     * @return: java.util.Date
     * @decription 输入号数返回对应开始时间
     * @date 2024/5/16 17:42
    */
    public static Date getStartTimeOfMonth(int dayOfMonth) {
        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.DAY_OF_MONTH, dayOfMonth);
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        return calendar.getTime();
    }

    /**
     * 获取开始结束时间之间的月份
     * @param startStr 开始日期  2024-01
     * @param endStr    结束日期 2024-05
     */
    public static List<String> getMonthsBetweenStr(String startStr, String endStr)  {
        List<String> list = new ArrayList<>();
        if (startStr == null || endStr == null) {
            throw new IllegalArgumentException("参数不能为空");
        }
        if (startStr.equals(endStr)) {
            list.add(startStr);
            return list;
        }
        Date startDate = null;
        Date endDate = null;
        try {
            startDate = Y_M.parse(startStr);
            endDate = Y_M.parse(endStr);
        } catch (ParseException e) {
            throw new RuntimeException(e);
        }
        if (startDate.after(endDate)){
            Date copy = startDate;
            startDate = endDate;
            endDate = copy;
        }
        LocalDate start = startDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
        LocalDate end = endDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
        // 输出两个时间之间的所有月份
        while (start.isBefore(end) || start.isEqual(end)) {
            list.add(start.format(DateTimeFormatter.ofPattern("yyyy-MM")));
            start = start.plusMonths(1);
        }
        return list;
    }

    public String getLastDayOfMonthStr(String yearMonth) {
        String[] split = yearMonth.split("-");
        int year = Integer.parseInt(split[0]);
        int month = Integer.parseInt(split[1]);
        //获取某月最大天数
        int lastDay = getLastDateOfMonth(year, month);
        //设置日历中月份的最大天数
        this.cal.set(Calendar.DAY_OF_MONTH, lastDay);
        //格式化日期
        SimpleDateFormat sdf = new SimpleDateFormat(DATE_FORMAT_YYYY_MM_DD);
        return sdf.format(cal.getTime());
    }

    public  BigDecimal calculateDaysDifference(Date date1, Date date2) {
        return new BigDecimal(Math.abs(date2.getTime() - date1.getTime())).divide(new BigDecimal(24 * 60 * 60 * 1000), 2, RoundingMode.HALF_UP);
    }
    /**
     * 查询时段内的所有日期
     *
     * @param start 开始时间
     * @param end   结束时间
     * @return
     */
    public static List<Date> getDatesByPeriod(Date start, Date end) {
        List<Date> dates = CollUtil.newArrayList();
        start = cn.hutool.core.date.DateUtil.beginOfDay(start);
        while (start.before(end)) {
            dates.add(start);
            start = DateUtil.dateAddDays(start, 1);
        }
        return dates;
    }


    /**
     * 获取某天结束的日期  xxxx-xx-xx 23:59:59
     * @param date
     * @return
     */
    public static Date getDayBeginByDay(Date date) {
        String format = new SimpleDateFormat("yyyy-MM-dd").format(date);
        String[] split = format.split("-");
        Calendar cal = Calendar.getInstance();
        cal.set(Calendar.YEAR, Integer.valueOf(split[0]));
        cal.set(Calendar.MONTH, Integer.valueOf(split[1]) - 1);
        cal.set(Calendar.DAY_OF_MONTH, Integer.valueOf(split[2]));
        //0点
        cal.set(Calendar.HOUR_OF_DAY, 0);
        //0分
        cal.set(Calendar.MINUTE, 0);
        //0秒
        cal.set(Calendar.SECOND, 0);
        //0毫秒
        cal.set(Calendar.MILLISECOND, 0);
        return cal.getTime();
    }

    /**
     * 获取某天结束的日期  xxxx-xx-xx 23:59:59
     * @param date
     * @return
     */
    public static Date getDayEndByDay(Date date) {
        String format = new SimpleDateFormat("yyyy-MM-dd").format(date);
        String[] split = format.split("-");
        Calendar cal = Calendar.getInstance();
        cal.set(Calendar.YEAR, Integer.valueOf(split[0]));
        cal.set(Calendar.MONTH, Integer.valueOf(split[1]) - 1);
        cal.set(Calendar.DAY_OF_MONTH, Integer.valueOf(split[2]));
        //23点
        cal.set(Calendar.HOUR_OF_DAY, 23);
        //59分
        cal.set(Calendar.MINUTE, 59);
        //59秒
        cal.set(Calendar.SECOND, 59);
        return cal.getTime();
    }

    /**
     * 计算日期之间的日期差
     * @param d1 日期1
     * @param d2 日期2
     * @return int
     */
    public static BigDecimal calculateDayDiff(Date d1, Date d2) {
        // 计算日期之间的日期差
        BigDecimal days = new BigDecimal( ChronoUnit.DAYS.between(Instant.ofEpochMilli(d1.getTime()), Instant.ofEpochMilli(d2.getTime())));
        return days;
    }


    /**
     * 计算日期之间的半天差
     * @param d1 日期1
     * @param d2 日期2
     * @param startTimeType 开始时间类型 类型：1 上半天 2 下半天
     * @param endTimeType 结束时间类型 类型：1 上半天 2 下半天
     * @return int
     */
    public static BigDecimal calculateHalfDayDiff(Date d1,Integer startTimeType, Date d2,Integer endTimeType) {
        // 计算日期之间的日期差 一个半天等于0.5天
        BigDecimal days = new BigDecimal(ChronoUnit.DAYS.between(Instant.ofEpochMilli(d1.getTime()), Instant.ofEpochMilli(d2.getTime())));
        if (Objects.equals(startTimeType, endTimeType)) {
            // 相同的半天 需要额外加0.5天
            days = days.add(new BigDecimal("0.5"));
        }  else if (startTimeType == 1 && endTimeType == 2) {
            // 开始是上半天 结束是下半天 需要额外加1天
            days = days.add(BigDecimal.ONE);
        }
        // 开始是下半天 结束是上半天 保持不变
        return days;
    }


    /**
     * 获取两个时间之间的时间差
     * @param d1 时间1
     * @param d2 时间2
     * @return BigDecimal 时间差保留两位小数
     */
    public static BigDecimal getTimeDifference(Date d1, Date d2) {
        // 计算两个时间差
        long diff = d2.getTime() - d1.getTime();
        // 计算两个时间差且结果转化为小时保留两位小数
        return new BigDecimal(diff).divide(new BigDecimal(1000 * 60 * 60), 2, BigDecimal.ROUND_HALF_UP);
    }

}
